PHP调用FFMPEG执行视频处理命令时如何捕获执行错误
PHP搭配FFmpeg处理视频时捕获执行错误的实现方案
“该场景下无法捕获FFmpeg执行错误”的说法并不成立。你当前代码拿不到错误的核心原因是shell_exec()函数的局限性:
- 该函数仅返回命令的标准输出(stdout)内容,而FFmpeg的报错、警告信息默认全部输出到标准错误流(stderr),不会被
shell_exec()捕获 - 该函数不会返回命令的执行退出状态码,你无法判断命令是成功跑完还是中途异常退出
- 你当前的代码存在两个额外问题:所有传入shell的参数未做转义,存在命令注入风险、特殊字符导致命令解析失败的问题;
-s分辨率参数放置位置错误,和filter_complex滤镜链逻辑冲突,可能导致输出分辨率不符合预期。
正确实现步骤
- 替换执行函数:用
exec()替代shell_exec(),该函数支持通过第三个参数接收命令的退出状态码(状态码为0代表执行成功,非0值均为执行异常) - 重定向错误流:在命令末尾加
2>&1,把FFmpeg输出到stderr的错误信息重定向到stdout,这样就能拿到全量执行日志 - 转义所有shell参数:对所有文件路径、动态传入的参数用
escapeshellarg()做转义,彻底避免命令注入和特殊字符解析问题 - 修正命令逻辑:把分辨率调整逻辑整合到滤镜链中,增加
-y参数自动覆盖已存在的输出文件避免进程卡住,增加-map参数明确指定输出流避免流选择异常
可直接使用的修正代码
// 对所有动态传入命令的参数做shell转义 $ffmpegBin = escapeshellarg($ffmpeg); $inputFile = escapeshellarg($video['tmp_name']); $watermarkFile = escapeshellarg('pics/watermark.png'); $outputFile = escapeshellarg("videos/{$video_name}"); // 拼接处理命令,2>&1 用于捕获错误输出 $command = <<<SHELL {$ffmpegBin} -y -i {$inputFile} -i {$watermarkFile} \ -filter_complex "[1:v][0:v]scale2ref=(127/60)*ih/10/sar:ih/10[wm][base];[base][wm]overlay=10:10,scale={$resolution}[outv]" \ -map "[outv]" -pix_fmt yuv420p -c:a copy {$outputFile} 2>&1 SHELL; // 执行命令,$fullOutput 存全量执行日志,$exitCode 存执行状态码 exec($command, $fullOutput, $exitCode); // 异常判断 if ($exitCode !== 0) { $errorDetail = implode(PHP_EOL, $fullOutput); // 此处可自定义错误处理逻辑:写入日志、返回前端错误提示等 throw new Exception("视频处理失败:" . $errorDetail); } // 执行到此处即代表视频处理完成
优化提示
如果处理的视频时长较长,全量日志存在内存里会占用较多资源,可以把错误输出重定向到临时文件:执行时把2>&1替换为2>' . escapeshellarg($tempLogPath),执行完成后如果状态码非0,再读取临时日志文件的内容拿到错误信息,执行成功则直接删除临时文件即可,能大幅降低内存占用。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

