使用 PHP 的 exec 压缩 Ghostscript PDF 文件(Laravel on Docker)
Ghostscript PDF file compression using PHP's exec (Laravel on Docker)
需要做的事情:
用户必须能够上传 PDF,然后将文件上传到 Amazon S3 存储桶,然后应压缩文件。
当前环境:
- Laravel 应用程序(安装在 Docker 上)(
php:7.4-fpm-alpine3.11
、GPL Ghostscript 9.50
、Laravel Framework 5.8.37
)
- 用于保存文档的 Amazon S3 存储桶
- 脚本位于 shell 文件中,该文件可执行并作为
shrink
添加到 /usr/local/bin
- Shell没有明确添加到Docker容器中,应该是吧?
当前流量:
- 用户上传文件
- 文件已上传到 S3
- Laravel 然后将文件下载到本地临时文件夹
- Ghostscript 然后 运行 压缩所述文件(这个 script)
- 压缩文件上传回 S3
问题:
文件已找到并正在压缩,但输出为空白(1 页,白色)pdf 文件。
Docker文件:
# Add compression shell script to global executables
COPY .docker/config/shrink.sh /usr/local/bin/shrink
RUN chmod u+x /usr/local/bin/shrink
RUN chown nobody.nobody /usr/local/bin/shrink
nobody
是用户 PHP 是 运行。
PHP 应该压缩文件的函数:
public function optimizeFile($file_path)
{
// Copy file from default disk to temp disk
Storage::disk('temp')->put($file_path, Storage::get($file_path));
$fullTempFilePath = Storage::disk('temp')->path($file_path);
if (Storage::mimeType($file_path) == 'application/pdf') {
$output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);
if ($output != null) {
Log::error($output);
}
} else {
ImageOptimizer::optimize($fullTempFilePath);
}
// Write the compressed file back to default disk
Storage::put($file_path, Storage::disk('temp')->get($file_path));
// Delete temp file
Storage::disk('temp')->delete($file_path);
}
如果文件不是 PDF,ImageOptimizer
会完成它的工作并成功压缩图像。
我尝试了什么:
- (本地)在没有 Docker 的情况下成功压缩文件,使用
php artisan serve
启动 Laravel 应用程序;
- (本地)使用
docker exec -it <container_id> shrink in.pdf out.pdf
; 成功压缩 Docker 文件
- (本地)使用
docker exec -it <container_id> /bin/bash
; 成功压缩 shell 中带有 Docker 的文件
- (本地)我的同事在本地做了同样的事情,回复也是空白的 pdf
好的,所以问题就在这里:
$output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);
如果输入和输出文件相同,Ghostscript PDF 压缩无法按预期工作。解决方案:
$output = shell_exec("shrink " . $fullTempFilePath . $fullTempFilePath . "-compressed ");
shell_exec("mv " . $fullTempFilePath . "-compressed " . $fullTempFilePath);
好的,第一点; Ghostscript(更准确地说是 Ghostscript pdfwrite 设备)不会缩小 PDF 文件。 VectorDevices.htm 中概述中的文档中描述了实际过程。我建议您阅读它。
其次,输入和输出文件不能使用相同的名称。当 pdfwrite 设备想要写入输出文件时,Ghostscript 仍会从输入文件中读取。
需要做的事情:
用户必须能够上传 PDF,然后将文件上传到 Amazon S3 存储桶,然后应压缩文件。
当前环境:
- Laravel 应用程序(安装在 Docker 上)(
php:7.4-fpm-alpine3.11
、GPL Ghostscript 9.50
、Laravel Framework 5.8.37
) - 用于保存文档的 Amazon S3 存储桶
- 脚本位于 shell 文件中,该文件可执行并作为
shrink
添加到 /usr/local/bin
- Shell没有明确添加到Docker容器中,应该是吧?
当前流量:
- 用户上传文件
- 文件已上传到 S3
- Laravel 然后将文件下载到本地临时文件夹
- Ghostscript 然后 运行 压缩所述文件(这个 script)
- 压缩文件上传回 S3
问题:
文件已找到并正在压缩,但输出为空白(1 页,白色)pdf 文件。
Docker文件:
# Add compression shell script to global executables
COPY .docker/config/shrink.sh /usr/local/bin/shrink
RUN chmod u+x /usr/local/bin/shrink
RUN chown nobody.nobody /usr/local/bin/shrink
nobody
是用户 PHP 是 运行。
PHP 应该压缩文件的函数:
public function optimizeFile($file_path)
{
// Copy file from default disk to temp disk
Storage::disk('temp')->put($file_path, Storage::get($file_path));
$fullTempFilePath = Storage::disk('temp')->path($file_path);
if (Storage::mimeType($file_path) == 'application/pdf') {
$output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);
if ($output != null) {
Log::error($output);
}
} else {
ImageOptimizer::optimize($fullTempFilePath);
}
// Write the compressed file back to default disk
Storage::put($file_path, Storage::disk('temp')->get($file_path));
// Delete temp file
Storage::disk('temp')->delete($file_path);
}
如果文件不是 PDF,ImageOptimizer
会完成它的工作并成功压缩图像。
我尝试了什么:
- (本地)在没有 Docker 的情况下成功压缩文件,使用
php artisan serve
启动 Laravel 应用程序; - (本地)使用
docker exec -it <container_id> shrink in.pdf out.pdf
; 成功压缩 Docker 文件
- (本地)使用
docker exec -it <container_id> /bin/bash
; 成功压缩 shell 中带有 Docker 的文件
- (本地)我的同事在本地做了同样的事情,回复也是空白的 pdf
好的,所以问题就在这里:
$output = shell_exec("shrink " . $fullTempFilePath . " " . $fullTempFilePath);
如果输入和输出文件相同,Ghostscript PDF 压缩无法按预期工作。解决方案:
$output = shell_exec("shrink " . $fullTempFilePath . $fullTempFilePath . "-compressed ");
shell_exec("mv " . $fullTempFilePath . "-compressed " . $fullTempFilePath);
好的,第一点; Ghostscript(更准确地说是 Ghostscript pdfwrite 设备)不会缩小 PDF 文件。 VectorDevices.htm 中概述中的文档中描述了实际过程。我建议您阅读它。
其次,输入和输出文件不能使用相同的名称。当 pdfwrite 设备想要写入输出文件时,Ghostscript 仍会从输入文件中读取。