视频上传后须立即触发异步审核,禁用扩展名或$_files['type']校验;落地即用finfo_file()验真实mime,ffmpeg探针校验结构合法性,redis队列分发任务至后台worker调用云审核api,并按场景变化动态截帧。

视频上传后立刻触发审核,别等用户点播放才检查
PHP 本身不带内容识别能力,所谓“审核”必须交由第三方服务或本地 FFmpeg + 模型做前置判断。直接用 $_FILES['video']['type'] 或扩展名过滤毫无意义——攻击者改个 .mp4 后缀就能绕过。真正有效的风控前置,是在文件落地瞬间启动异步审核流程,而不是把审核逻辑塞进上传响应里。
- 上传成功后,立即用
finfo_file()确认真实 MIME 类型,拒绝非video/mp4、video/webm等合法类型(注意:video/quicktime不等于 mov 文件安全) - 调用 FFmpeg 快速探针:执行
exec('ffmpeg -v error -i '.escapeshellarg($tmpPath).' -f null - 2>&1', $output, $ret),返回码非 0 就说明文件结构异常,可能是伪装视频的恶意 payload - 生成唯一任务 ID,把文件路径、用户 ID、时间戳写入 Redis 队列,交由后台 worker 调用内容安全 API(如阿里云视频审核、腾讯云天御),避免阻塞上传响应
截帧不是“每秒一张”,而是按关键帧+场景变化动态采样
很多团队直接用 ffmpeg -i input.mp4 -vf fps=1 thumbnail_%03d.jpg 生成截图,结果审核漏报率高——因为固定间隔会错过黑屏、花屏、静帧或快速闪动画面。内容安全平台的“截帧策略”配置项(如默认 1s)只是参考值,实际应结合视频内容动态调整。
- 优先使用
-vf "select='gt(scene,0.4)'"提取场景切换帧,阈值 0.4 是平衡灵敏度与数量的经验值,太低会导致大量重复帧,太高则漏掉细微变化 - 对短视频(-skip_frame nokey)+ 场景检测双路输出
- 截帧后务必校验图片有效性:用
getimagesize()排除空图、损坏图,否则上传到审核接口会返回InvalidImage错误
回调地址必须公网可达且带签名验证,别裸奔暴露审核结果
第三方视频审核服务(如内容安全平台)几乎全部采用异步回调模式。如果你的 PHP 服务部署在内网或 NAT 后,回调根本收不到;更危险的是,不校验回调签名就直接入库或发通知,攻击者伪造请求就能篡改审核状态。
- 确保回调 URL 是公网可访问的 HTTPS 地址,Nginx 需开放对应路径,且禁用缓存(
add_header Cache-Control "no-cache") - 收到回调时,先用平台提供的密钥和请求 body 计算 HMAC-SHA256 签名,比对
X-Signature头(或类似字段),不匹配直接 403 - 审核结果字段必须严格校验:
result.suggestion只接受pass、review、block,其他值一律视为无效,防止 JSON 注入或字段污染
违规片段定位不能只靠时间戳,得绑定 GOP 起始位置
审核返回的违规时间点(如 "start_time": 12.34)是 PTS 时间,但直接用这个去 FFmpeg 截取,大概率得到黑屏或错帧——因为视频编码是基于 GOP(Group of Pictures)结构的,硬切会破坏 I 帧依赖关系。
- 截取前先用
ffprobe -v quiet -show_entries format=duration -of default=nw=1 input.mp4获取总时长,确认时间点合法 - 用
ffprobe -v quiet -show_frames -select_streams v:0 -show_entries frame=pkt_pts_time,pict_type input.mp4找到最接近违规时间点的 I 帧位置,作为实际截取起点 - 截取命令必须加
-avoid_negative_ts make_zero -vsync vfr,否则部分设备播放会卡顿或音画不同步
审核不是上传完点个按钮就结束的事。从文件落地、帧采样、回调验签到 GOP 对齐截取,每个环节都有隐蔽但致命的坑。最容易被忽略的是:你以为审核平台返回的时间戳能直接喂给 FFmpeg,实际上它只是“人类可读时间”,而视频引擎要的是“编码层锚点”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











