php调用ffmpeg前必须逃逸用户输入路径并验证权限:先用move_uploaded_file()存入安全目录,再用realpath()和escapeshellarg()处理绝对路径,同时检查disable_functions、文件权限及输出目录隔离,以防止shell注入与越权访问。

exec()调用前必须逃逸用户输入的文件路径
直接拼接$_FILES["video"]["tmp_name"]或前端传来的$filename进命令字符串,等于给攻击者开了一扇shell后门。FFmpeg本身不校验路径合法性,但PHP执行时会把整个字符串交给系统shell解析。
正确做法是:先用move_uploaded_file()把上传文件存到预设安全目录(如/var/www/uploads/),再用realpath()获取绝对路径,最后套一层escapeshellarg():
exec('ffmpeg -i ' . escapeshellarg($safe_abs_path) . ' -c:v libx264 out.mp4 2>&1', $output, $return_code);
- 绝不能对
$_FILES["video"]["name"]做任何escapeshellcmd()后直接使用——它只过滤元字符,不防路径遍历 -
realpath()能自动展开../并验证路径是否落在白名单目录内,失败则返回false - 如果输出路径也来自用户(比如指定
output_name),同样要限制扩展名(仅允许.mp4、.webm等)并强制加白名单后缀
disable_functions检查比写代码还重要
很多线上环境默认禁用exec、shell_exec、proc_open,你写的命令再完美也执行不了。这不是bug,是PHP配置硬限制。
上线前必须确认两点:
- 在
phpinfo()页面搜索disable_functions,确保exec没出现在列表里 - 如果用
proc_open()做流式处理(比如实时推流),还要确认proc_open和proc_close未被禁用 - 某些云主机(如阿里云轻量应用服务器)默认禁用全部执行函数,只能改
php.ini或换用云转码服务
权限最小化:Web用户不该有FFmpeg执行权以外的任何权限
让www-data用户能执行ffmpeg,不等于让它能读任意目录或写/tmp。生产环境出问题,八成是权限过大导致的。
实际部署时应:
- 用
chmod 755 /usr/bin/ffmpeg,确保只有所有者可写,组和其他人仅可执行 - 输入目录(如上传临时目录)和输出目录(如
/var/www/videos/)的属主设为www-data:www-data,权限设为750或770,禁止其他用户访问 - 绝对不要把输出目录设在Web根目录下且开放HTTP直链——攻击者可能上传恶意
.php文件伪装成视频
错误码不等于日志,但日志必须包含错误码
$return_code是唯一可信的成败信号,$output里的文字只是辅助。很多人只看if (!$output)就认为成功,结果转码静默失败。
记录日志时必须同时保留三要素:
- 原始命令(脱敏路径,保留参数结构)
-
$return_code值(注意负数,如-9表示被kill) -
implode("\n", $output)完整内容(含ffmpeg stderr输出)
特别注意:2>&1重定向必须显式写在命令末尾,漏掉就捕获不到错误;system()会直接输出到响应体,生产环境禁用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











