php 8 中安全执行 ffmpeg 的核心是禁用字符串拼接,改用 proc_open 配合参数数组;用户输入须先白名单校验再 escapeshellarg;禁用危险选项,最小化权限与攻击面。

PHP 8 中安全拼接 FFmpeg 命令,核心不是“拼接”,而是**完全避免字符串拼接**。直接用变量插进命令字符串(如 "ffmpeg -i {$input} -y {$output}")是高危操作,哪怕用了 escapeshellarg(),在复杂场景下仍可能被绕过或遗漏边界情况。
严格使用数组传参 + proc_open
PHP 8 推荐用 proc_open() 配合参数数组执行命令,系统自动处理参数分隔与转义,从根本上杜绝注入可能:
- 把每个 FFmpeg 参数作为独立数组元素,不拼成字符串
- 路径、文件名等用户输入必须经
escapeshellarg()单独包裹后再入数组 - 固定参数(如
'-c:v','libx264')可直接写死,无需转义
示例:
(注意:所有用户可控值都单独转义)$input = $_POST['video_path'] ?? ''; $output = '/tmp/converted.mp4'; // ✅ 安全:参数拆成数组,每个值独立处理 $cmd = [ '/usr/bin/ffmpeg', '-i', escapeshellarg($input), '-c:v', 'libx264', '-c:a', 'aac', '-y', escapeshellarg($output) ]; $descriptors = [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'] ]; $process = proc_open($cmd, $descriptors, $pipes);
输入验证比转义更重要
仅靠 escapeshellarg() 不够,它防不住逻辑型攻击(比如传入 /etc/passwd 或 ../config.php)。必须叠加白名单校验:
- 限制输入路径范围:只允许上传目录下的相对路径,禁止
..、/开头、通配符 - 检查文件扩展名与 MIME 类型(用
ffprobe或finfo_file()),拒绝非视频类型 - 对路径做规范化:
realpath()+ 检查是否落在允许根目录内
例如:
$allowed_root = '/var/www/uploads/';
$real_input = realpath($input);
if (!$real_input || strpos($real_input, $allowed_root) !== 0) {
throw new InvalidArgumentException('Invalid video path');
}
禁用危险选项,最小化攻击面
FFmpeg 自身支持很多高风险功能(如 -f concat 读取外部文本列表、-i pipe: 读取标准输入),这些在 Web 场景中极少需要,却极易被滥用:
- 明确禁止
-f concat、-protocol_whitelist、-safe 0等参数 - 若必须用拼接列表(如视频合并),改用 PHP 生成绝对安全的临时 list.txt,并设为只读、随机名、限定生命周期
- 不要让用户决定编码器、码率等参数;预设几档安全模板(如 “720p”、“480p”),后端映射到固定命令
权限隔离与运行环境加固
即使命令构造无误,运行时权限过大也会放大危害:
- PHP 进程以低权限用户运行(如
www-data),禁止访问系统关键目录 - FFmpeg 二进制文件权限设为
755,且仅该用户组可执行 - 输出目录挂载为 noexec,nosuid,并启用磁盘配额防止写满
- 生产环境禁用
shell_exec、system、passthru,只保留proc_open
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











