PHP无法原生压缩视频,必须通过调用ffmpeg等外部工具实现;其作用仅限于拼接命令、执行进程及处理结果,关键在于安全调用与合理参数配置。

PHP 本身不支持直接压缩视频,它没有内置的视频编解码能力。所有“PHP 压缩视频”的方案,本质都是调用外部命令行工具(主要是 ffmpeg),PHP 只负责拼接命令、执行进程、处理返回结果。
为什么不能用 PHP 原生函数处理视频
PHP 的 gd 扩展只支持图片(GIF/JPG/PNG),imagick 同样不支持视频帧序列的批量读写与编码。试图用 fopen + stream_copy_to_stream 直接“减小文件体积”只会破坏视频结构,导致无法播放。
- 视频压缩 = 重新编码(re-encode),必须由专业多媒体库完成
-
ffmpeg是事实标准,开源、跨平台、参数粒度细 - PHP 的作用仅限于:构造命令 →
exec()或shell_exec()调用 → 检查退出码和日志
用 ffmpeg 命令行压缩视频的关键参数
直接在终端测试通了,再封装进 PHP。以下是最常用且兼顾质量与体积的组合:
ffmpeg -i input.mp4 -vcodec libx264 -crf 28 -preset fast -acodec aac -b:a 128k -movflags +faststart output.mp4
-
-crf 28:恒定质量模式,数值越小质量越高(18~28 常用),比固定码率更智能 -
-preset fast:编码速度/压缩率权衡,fast适合服务端批量处理;slow更小但耗时翻倍 -
-b:a 128k:音频比特率,够用且不拖累体积;可改用-q:a 4(VBR 音频)获得更好听感 -
-movflags +faststart:把 moov atom 移到文件头,实现网页播放器“边下边播”
PHP 中安全调用 ffmpeg 的实操要点
别直接拼接用户上传的文件名,也别忽略错误输出。一个健壮的调用应包含:
立即学习“PHP免费学习笔记(深入)”;
- 对输入路径做
escapeshellarg(),防止命令注入 - 重定向
stderr到stdout,统一捕获日志:2>&1 - 检查
$return_code是否为0,非零即失败 - 设置超时(如
proc_open配合stream_set_timeout),避免大视频卡死进程
$input = escapeshellarg('/var/uploads/user123.mp4');
$output = escapeshellarg('/var/output/optimized.mp4');
$cmd = "ffmpeg -i $input -vcodec libx264 -crf 28 -preset fast -acodec aac -b:a 128k -movflags +faststart $output 2>&1";
$output_log = shell_exec($cmd);
$return_code = $return_code ?? 0;
if ($return_code !== 0) {
error_log("FFmpeg failed: $output_log");
}
常见失败场景与排查方向
执行后没生成文件、生成空文件、或浏览器提示“格式不受支持”,大概率是这些原因:
-
ffmpeg未安装或不在$PATH:在 PHP 中执行which ffmpeg验证 - 输入视频编码格式太偏门(如 AV1、HEVC),而系统 ffmpeg 编译时没启用对应解码器
- 权限问题:Web 进程用户(如
www-data)无权读取输入目录或写入输出目录 - 磁盘满或
open_basedir限制拦截了临时文件路径 - CRF 值设成
0(无损编码)——体积反而更大,且耗时极长
真正影响播放效率的不是“PHP 怎么写”,而是 ffmpeg 参数是否匹配目标设备(如 H.264 baseline profile 用于老安卓)、是否开启 faststart、以及 CDN 是否正确缓存了分片后的 MP4。这些细节比换哪个 PHP 封装库重要得多。











