exec()调用ffmpeg失败主因是环境配置问题:php进程找不到ffmpeg、disable_functions禁用相关函数、未捕获stderr、return_code非0即失败,且需确保ffmpeg/ffprobe路径正确、权限充足、参数合规。

exec() 调用 ffmpeg 失败,90% 不是代码写错了,而是环境没配对。
确认 ffmpeg 是否真能被 PHP 调用
很多“转码不执行”的问题,根源在于 PHP 进程根本找不到 ffmpeg。别只在终端里跑 ffmpeg -version 就以为万事大吉。
- 用 PHP 自己查一遍:
exec('which ffmpeg', $out, $rc); var_dump($out, $rc);—— 如果$out是空数组、$rc非 0,说明 PHP 用户(比如www-data)压根看不见ffmpeg -
ffmpeg安装路径不在系统$PATH?那就硬编码路径:/usr/local/bin/ffmpeg或/opt/ffmpeg/bin/ffmpeg,并在命令里写全 - 检查 PHP 的
disable_functions:运行phpinfo(),搜索disable_functions,确保exec、shell_exec、proc_open没被禁用
exec() 执行后无声无息?你没捕获 stderr
exec() 默认只返回 stdout,而 ffmpeg 的关键错误(如文件权限拒绝、编码器不支持、分辨率非法)全打在 stderr 上。不重定向就等于闭眼开车。
- 必须加
2>&1:例如exec('/usr/bin/ffmpeg -i /tmp/in.mp4 -vf scale=1280:-2 -c:v libx264 out.mp4 2>&1', $output, $return_code) -
$return_code是唯一可信的成败标尺:0成功,非0就失败 —— 别信$output是否为空,有些错误连 stdout 都不吐 - 别用
system():它会把输出直接刷到 HTTP 响应流,可能暴露绝对路径、参数或敏感信息,生产环境禁用
压缩视频时,这三个参数组合最稳
不是所有 -crf 都适合 Web;不是所有 -preset 都能扛住并发;scale 写错会直接报错。
-
-vf scale=1280:-2:宽度固定为 1280,高度自动计算并强制为偶数(-2是 ffmpeg 约定),避免 “height not divisible by 2” 错误 -
-crf 23:质量锚点,值越小越清晰但体积越大;18–28 是安全区间,23 是默认值,多数场景可直接用 -
-preset medium:编码速度与压缩率的平衡点;ultrafast体积大、slow耗时长,medium是上线首选 - 额外建议:大文件(>500MB)务必异步处理,否则 PHP 脚本超时、Nginx 504、用户看到白屏
用 php-ffmpeg 扩展前,先看清它真正依赖什么
php-ffmpeg/php-ffmpeg 看似封装了所有操作,但它只是个壳——底层仍要调用系统 ffmpeg 和 ffprobe。装完 Composer 包不代表就能跑。
- 必须确保
ffmpeg和ffprobe都在 PATH 中,或初始化时显式指定路径:FFMpeg::create(['ffmpeg.binaries' => '/usr/local/bin/ffmpeg', 'ffprobe.binaries' => '/usr/local/bin/ffprobe']) - 扩展本身不解决权限问题:PHP 进程仍需对输入文件可读、输出目录可写
- 错误堆栈不如原生命令直观:出错时它常抛出
RuntimeException,但真正原因还得看底层ffmpeg的 stderr 输出,建议开启日志:->setLogger($logger)
ffmpeg 在哪个用户身份下、以什么权限、从哪条路径、带着哪些环境变量跑起来的。这些细节藏在系统层,不挖到底,再漂亮的 PHP 封装也转不动一帧视频。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











