应使用 finfo_file() 验证视频 mime 类型并用 ffprobe 检查元数据:finfo_file() 读文件头返回准确 type,ffprobe 输出 json 提取 duration 和 streams 确保视频流存在且时长为正。

用 finfo_file() 判断是否真为视频格式
别信 $_FILES['video']['type'],它由浏览器提供,一改就失效。真正靠谱的是读文件头——PHP 的 finfo_file() 就干这事,依赖系统 magic 数据库,准确率远高于 mime_content_type()。
- 必须传
$_FILES['video']['tmp_name'],不是原始文件名,也不是 URL - 启用
FILEINFO_MIME_TYPE标志,返回如video/mp4、video/webm这类字符串 - 用
str_starts_with($mimeType, 'video/')匹配,比硬写死in_array($mimeType, ['video/mp4', ...])更健壮,能兼容video/vnd.dece.mp4这类变体 - 若返回
application/octet-stream或空字符串,基本可判定非视频或文件损坏
用 ffprobe 提取时长与格式合法性
ffprobe 是 FFmpeg 套件中专用于分析媒体元数据的工具,比 ffmpeg -i 更轻量、更稳定,且输出结构化 JSON,解析安全可靠。
- 命令必须加
-v quiet -print_format json -show_format -show_streams,否则输出含杂讯,正则易错 -
duration字段在$data['format']['duration']下,单位是秒,可能为 float(如123.45),注意类型判断 - 若
$data['format']['duration']不存在,或$data['streams']为空数组,说明文件无有效视频流——可能是假 MP4、损坏文件或纯音频 - 执行前务必用
escapeshellarg($filePath)过滤路径,防止命令注入;返回码非 0 时,$output里通常含错误描述,比如 “Invalid data found when processing input”
为什么不用 getimagesize() 或正则匹配 ffmpeg -i 输出
getimagesize() 对任何视频都返回 false,它压根不支持视频解析,误用会导致“检测通过但实际无法播放”的假阳性。
- 直接对
ffmpeg -i的 stderr 做正则匹配(比如抓Duration: (\d+:\d+:\d+))极不稳定:不同 FFmpeg 版本输出格式略有差异,中文环境还可能出现乱码,ffprobe的 JSON 输出才是唯一可信赖的解析入口 - 有人试图用
exec("file {$filePath}")替代finfo,但file命令依赖系统 locale 和 magic 文件版本,行为不一致,PHP 内置finfo更可控 - 仅靠扩展名(如
.mp4)或文件大小判断合法性,等于把门钥匙交给攻击者——一个伪造的 10MB PHP 脚本改后缀就能绕过
转 MP4 前必须确认的三个硬性条件
不是所有“能播”的视频都适合直接转 MP4。FFmpeg 转码失败常因源文件本身存在结构性缺陷,提前拦截能省掉大量调试时间。
-
$data['format']['nb_streams'] >= 1:至少含一个流(视频或音频),否则是空壳文件 -
isset($data['streams'][0]['codec_type']) && $data['streams'][0]['codec_type'] === 'video':首流必须是视频流,避免把纯音频当视频处理 -
!empty($data['format']['duration']) && $data['format']['duration'] > 0:时长必须为正数,0.000或null表示无法解析时间轴
漏掉其中任一检查,转码过程可能卡死、生成 0 字节 MP4,或触发 FFmpeg 内部断言失败。这些判断必须在调用 ffmpeg -i ... -c:v libx264 ... 之前完成。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











