根本原因是命令未执行成功,源于权限、路径、环境变量缺失;Web用户无shell环境导致PATH不含ffmpeg路径;应先which ffmpeg确认路径,显式使用绝对路径并捕获2>&1输出。

PHP调用ffmpeg命令失败,返回空或乱码
根本原因不是PHP写错了,而是命令根本没执行成功——常见于权限、路径、环境变量三重缺失。Web服务器用户(如www-data)通常没有shell环境,exec()调用时PATH可能不包含ffmpeg所在目录。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 别用
exec('ffmpeg -i ...')硬编码,先用which ffmpeg确认路径:exec('which ffmpeg 2>&1', $out);,若输出为空,说明系统找不到 - 显式指定完整路径,例如
/usr/bin/ffmpeg,而非依赖PATH - 检查
is_executable('/usr/bin/ffmpeg'),避免软链接指向不可执行文件 - 错误输出必须捕获:
2>&1不能省,否则$output里全是空的 - PHP禁用了
exec?查disable_functions配置,常见于共享主机,此时只能换云API或本地CLI模式
MP4下载后打不开,用文本编辑器打开看到
这不是视频损坏,是PHP把本该二进制直传的MP4内容“当代码执行了”。典型症状:文件开头出现<?php 、Warning:、空白行,或根本搜不到ftyp字符串。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
file -i broken.mp4检查真实类型,返回text/plain就坐实被污染 - 确认MP4文件物理存在且路径正确——
readfile('/var/www/videos/real.mp4')里的路径必须真实可读 - PHP脚本开头不能有任何输出:删掉BOM(用VS Code保存为UTF-8无BOM)、删掉
echo前的空行、确保include或require没意外输出 - 设置
header('Content-Type: video/mp4')必须在任何echo/print之前,且不能有前置空格 - 大文件别用
file_get_contents()再echo,改用readfile()或fopen()+fpassthru()流式输出
PHP输出MP4后无法拖动进度条
浏览器报“无法定位”或拖动时卡顿,本质是缺少HTTP范围请求(Range)支持,播放器没法跳到中间帧。MP4本身要求moov box在文件开头,但PHP默认输出不带Accept-Ranges头,也无法响应bytes=xxx-yyy请求。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 必须加
header('Accept-Ranges: bytes'),否则Chrome/Firefox直接禁用拖动 - 手动处理
HTTP_RANGE头,计算start/end,用fopen()+fseek()+fread()只读取片段,返回206 Partial Content - 别依赖
readfile()——它一次性输出全部,没法分段 - 如果
moov不在开头(比如FFmpeg生成时没加-movflags +faststart),拖动仍会卡,需额外用ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4修复
PHP 8+调用ffmpeg参数拼接出错,报command not found或文件名截断
PHP 8严格了类型和字符串处理,老式拼接"ffmpeg -i ".$input." -o ".$output在含空格或单引号的路径下必然崩,且易被注入攻击。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 每个参数必须用
escapeshellarg()包裹,哪怕只是'-i'也建议统一处理 - 改用数组传参+
proc_open()更安全,避免shell解析干扰:$cmd = ['/usr/bin/ffmpeg', '-i', escapeshellarg($input), '-y', escapeshellarg($output)]; - 用户输入的文件名必须过
basename()过滤,防../../etc/passwd路径遍历 - 别信
return_code === 0就万事大吉——ffprobe -v error -show_entries format=duration $output 2>&1才能验证MP4是否真能解析
Accept-Ranges,用户体验就打折。



















