PHP调用FFmpeg前必须确认三件事:ffmpeg已安装并加入PATH、PHP进程用户有执行及写入权限、disable_functions未禁用exec等函数。

PHP 调用 FFmpeg 前必须确认的三件事
PHP 本身不能直接转码视频,所谓“PHP 实现”本质是调用 ffmpeg 命令行工具。如果 ffmpeg 没装、没加到系统 PATH、或权限不足,exec() 或 shell_exec() 会静默失败或返回空字符串。
- 运行
which ffmpeg(Linux/macOS)或where ffmpeg(Windows)确认路径;若无输出,需先安装 FFmpeg 并配置环境变量 - PHP 进程用户(如 www-data、nginx、或 IIS 用户)必须有执行
ffmpeg的权限,且磁盘写入目录可写 - 禁用
disable_functions中的exec、shell_exec、system—— 否则函数直接被 PHP 拦截,连错误都看不到
如何用 FFmpeg 自动检测视频是否损坏
FFmpeg 本身不提供“损坏与否”的布尔判断,但可通过其日志输出和退出码间接判断。关键不是看文件能否播放,而是看容器结构是否完整、关键流(video/audio)是否存在。
- 用
ffmpeg -v error -i input.mp4 -f null -:仅输出错误信息,正常文件返回空,损坏文件会输出类似moov atom not found或Invalid data found when processing input - 检查返回值:
exec("ffmpeg -v error -i '$input' -f null - 2>&1", $output, $return_code),若$return_code !== 0,基本可判定异常 - 补充校验:用
ffprobe -v quiet -show_entries format=duration -of default=nw=1 input.mp4看能否读出时长;返回空或报错说明元数据严重损坏
修复常见损坏类型:moov 位置错乱、无音频流、关键帧缺失
不是所有损坏都能“修复”,但部分结构问题可通过重封装(re-mux)或重建索引解决,无需重新编码,速度快、质量无损。
-
moov atom 在末尾(常见于未完成上传的 MP4):用
ffmpeg -i broken.mp4 -c copy -movflags +faststart fixed.mp4把索引移到开头,浏览器就能边下边播 -
有视频无音频(或反之):若原始源含音轨但被误删,无法恢复;但若只是流标记丢失,可尝试
ffmpeg -i broken.mp4 -c copy -map 0:v? -map 0:a? -ignore_unknown fixed.mp4强制映射可用流 -
关键帧缺失导致快进/拖动失败:用
ffmpeg -i broken.mp4 -c copy -force_key_frames "expr:gte(t,n_forced*2)" fixed.mp4强制每 2 秒插一个 I 帧(注意:此操作会轻微增大体积,且仅对支持的编码有效)
PHP 封装时必须处理的陷阱
直接拼接字符串调用 ffmpeg 极易因文件名含空格、中文、特殊字符而崩溃,且错误日志不落地就等于盲跑。
立即学习“PHP免费学习笔记(深入)”;
- 文件路径必须用
escapeshellarg()包裹:escapeshellarg($input_path),否则/var/www/video file.mp4会被拆成两个参数 - 务必重定向 stderr 到 stdout:
2>&1,否则exec()拿不到错误信息;同时设置超时(如timeout 300防止卡死) - 不要依赖
exec()返回值判断成功:有些 FFmpeg 版本即使失败也返回 0,必须同时检查输出内容是否含error、failed、invalid等关键词 - 临时文件建议用
sys_get_temp_dir()+uniqid()生成,避免并发冲突;转码完成后手动unlink()原始损坏文件前,先file_exists()和is_writable()双重确认
真正难的不是命令怎么写,而是判断“这个文件到底算不算修好了”——有时候 FFmpeg 说成功了,但浏览器依然打不开,得再用 ffprobe 验证流信息、时长、关键帧间隔,缺一不可。



















