You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PHP exec()与GhostScript合并PDF时错误码1的原因及解决方法

解决GhostScript合并PDF在生产服务器返回状态码1的问题

咱们先理清楚:GhostScript返回状态码1一般是一般性执行错误,不是某个特定问题,得从权限、路径、命令限制、文件本身这几个方向逐一排查,结合你的场景,我给你一步步分析:

1. 先搞定权限和sudo的问题

你本地用了sudo,但生产服务器里PHP是跑在Apache的系统用户(比如www-data)下的,直接用sudo可能踩两个坑:

  • 要么这个用户没有sudo权限,导致命令直接失败;
  • 就算配置了sudo,也可能因为环境变量不一致(比如PATH不同)出问题。

解决步骤:

  • 先去掉命令里的sudo,直接执行gs命令试试;
  • 手动切换到Apache用户身份测试命令:
    su www-data -c "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=/绝对路径/files/ovmext/sample.pdf /绝对路径/files/wkhtmltopdf/pdf-sample-*.pdf"
    
  • 检查输出目录files/ovmext/和源PDF目录的权限,确保www-data有读(源文件)和写(输出文件)的权限。

2. 排查路径问题

相对路径在不同环境下很容易踩坑:

  • 本地的files/目录相对于脚本的位置,可能和生产服务器不一样;
  • GhostScript的路径可能不在Apache用户的PATH里(不过你说单独执行gs -v正常,这个可能性低,但可以试试)。

解决步骤:

  • 把所有路径改成绝对路径,比如用realpath()函数获取文件的绝对路径:
    $outputPath = realpath('./files/ovmext/') . '/sample.pdf';
    $sourcePath = realpath('./files/wkhtmltopdf/') . '/pdf-sample-*.pdf';
    $command = "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=$outputPath $sourcePath";
    
  • 用which gs命令在服务器上查gs的绝对路径,比如/usr/bin/gs,然后把命令里的gs换成这个绝对路径。

3. 重点排查:命令行长度限制!

这大概率是你遇到的核心问题:Linux系统有个ARG_MAX参数,限制了命令行参数的总长度(默认一般是128KB左右),5000个PDF文件名加起来肯定超过这个限制了!本地Mac的ARG_MAX值更大(比如默认是2MB),所以没问题,但生产服务器触发了这个限制,导致命令执行失败返回状态码1。

完美解决办法:用GhostScript的@文件名语法,把所有要合并的PDF路径写到一个临时文件里,让gs从文件里读取列表:

// 1. 创建临时文件存储PDF列表
$tempFile = tempnam(sys_get_temp_dir(), 'pdf_merge_list');
$handle = fopen($tempFile, 'w');

// 2. 获取所有源PDF的绝对路径,逐行写入临时文件
$pdfFiles = glob(realpath('./files/wkhtmltopdf/') . '/pdf-sample-*.pdf');
foreach ($pdfFiles as $file) {
    fwrite($handle, $file . "\n");
}
fclose($handle);

// 3. 执行GhostScript命令,用@临时文件读取文件列表
$outputPath = realpath('./files/ovmext/') . '/sample.pdf';
$command = "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=$outputPath @$tempFile";
exec($command, $array, $return_var);

// 4. 执行完成后删除临时文件
unlink($tempFile);

// 检查结果
if ($return_var == 0) {
    echo 'works! - statuscode: ' . $return_var;
} else {
    echo 'does not work! - statuscode: ' . $return_var;
    // 可以获取详细错误信息
    $errorOutput = shell_exec($command . ' 2>&1');
    var_dump($errorOutput);
}

4. 查看详细错误日志

去掉命令里的-q参数,让GhostScript输出详细错误,同时把标准错误重定向到标准输出,这样能看到具体哪里出错了:

$command = 'gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=files/ovmext/sample.pdf files/wkhtmltopdf/pdf-sample-*.pdf';
$fullOutput = shell_exec($command . ' 2>&1');
echo $fullOutput;

这能帮你快速定位是某个PDF文件损坏,还是权限问题,或者资源不足。

5. 资源限制检查

合并5000个PDF需要不少内存和CPU,你可以检查:

  • PHP的memory_limit配置,在脚本开头临时调高试试:ini_set('memory_limit', '512M');
  • 服务器的ulimit限制,比如用ulimit -a查看,看进程的内存、打开文件数限制是不是不够。

内容的提问来源于stack exchange,提问作者Michał Płonski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:10:54