php视频处理依赖ffmpeg等外部工具,核心风险在于命令注入、内存溢出等安全问题;调用前须用escapeshellarg()过滤输入、指定绝对路径、禁用危险选项;大文件读取时feof失效属正常现象,应改用unread_bytes判断或手动控制读取长度。

PHP本身不直接处理视频编解码,所有“视频处理”本质都是调用外部工具(主要是ffmpeg)或控制流式传输逻辑。真正容易出问题的,从来不是“怎么写”,而是“怎么防”——防命令注入、防内存爆、防路径暴露、防断点失效。
用shell_exec调用ffmpeg前必须做这三件事
直接拼接字符串执行ffmpeg命令是最高危操作,90%以上的线上音视频服务被攻破都源于此。
- 绝不允许用户输入直接进入命令行:比如
$_POST['output_name']、$_GET['video_id']这类变量,必须经过escapeshellarg()包裹后再使用 - 固定二进制路径,不依赖
PATH环境变量:/usr/local/bin/ffmpeg比ffmpeg更安全,避免被恶意软链接劫持 - 禁用危险选项:如
-f rawvideo -vcodec copy配合pipe:可能触发任意文件读取;-i参数后禁止跟http://或rtmp://等远程协议,除非你明确信任源
fopen读大视频文件时内存不涨,但feof总卡住
这不是bug,是Linux下普通文件描述符在mmap模式下的正常行为——PHP 8.3+默认对>64MB文件启用内存映射,feof()会失效,因为底层没有传统EOF标记。
- 改用
stream_get_meta_data($fp)['unread_bytes'] === 0判断是否读完 - 或显式控制读取长度:
$size = filesize($path); $read = 0; while ($read - 注意
fread()返回false不代表结束,可能是I/O错误,需配合feof()和ferror()双重判断
HTTP Range请求支持不完整,导致H5播放器拖动失败
很多PHP流式响应代码只处理了Range: bytes=xxx-,但现代浏览器(尤其是iOS Safari)会发Range: bytes=xxx-yyy甚至多个范围,不兼容就卡在加载图标。
- 必须解析
HTTP_RANGE并提取起止值,不能只取explode('-', ...)[0] - 响应头必须严格匹配:
Content-Range: bytes $start-$end/$size,$end要min($end, $size - 1),否则返回206但内容长度不对,浏览器拒绝渲染 - 不要用
readfile()——它不支持偏移,必须fseek()+fread()分段输出,并调用flush()
PHP代理视频流时被CDN缓存,导致权限校验失效
当你用PHP脚本做鉴权层(如if (!valid_token()) die(); readfile($real_path);),如果前面套了Nginx、Cloudflare或CDN,它们可能把整个响应缓存下来,后续请求绕过PHP直接返回缓存的视频。
- 强制禁用缓存:在响应头加
Cache-Control: no-store, no-cache, must-revalidate, max-age=0和Pragma: no-cache - 动态URL加随机参数没用,CDN通常忽略查询参数;必须让URL本身带变化(如
/video/abc123.mp4?t=1718531760)且配置CDN规则排除该路径 - 更稳妥做法是用
X-Accel-Redirect(Nginx)或X-Sendfile(Apache),让Web服务器接管文件输出,PHP只负责鉴权
最常被忽略的其实是FFmpeg进程残留:proc_open启动后没调用proc_close或proc_terminate,转码卡住时子进程持续占用CPU和内存,积压几十个就拖垮整台机器。别只盯着代码逻辑,记得查ps aux | grep ffmpeg。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











