video标签preload=”metadata”在移动端常失效,因浏览器策略限制;PHP需用ffprobe预解析时长和封面,再通过异步接口返回元数据供前端动态更新。

为什么 video 标签加 preload="metadata" 不生效?
浏览器是否真正预加载,取决于实际网络策略和媒体格式。即使设置了 preload="metadata",Chrome 或 Safari 在移动设备上仍可能忽略它——尤其是当页面未用户交互(如点击)触发播放时,会强制降级为 preload="none"。这不是 PHP 的问题,但 PHP 要配合前端做兜底:比如生成可快速响应的首帧或时长信息。
PHP 怎么提前获取视频时长和封面?
不能靠前端 JS 读取(duration 初始为 NaN),得在服务端解析。推荐用 ffprobe(FFmpeg 工具集)而非纯 PHP 解析,因为 MP4/WebM 等容器结构复杂,手动解析极易出错且不兼容新编码。
-
ffprobe必须已安装并加入系统 PATH,PHP 通过shell_exec()调用 - 命令示例:
ffprobe -v quiet -show_entries format=duration -of default=nw=1 input.mp4
- 提取首帧为封面:
ffmpeg -i input.mp4 -ss 00:00:01 -vframes 1 -q:v 2 cover.jpg
- 注意权限:Web 服务器用户(如
www-data)需有执行权限和写入输出目录权限
如何让 PHP 输出“预加载中”状态给前端?
不要等 ffprobe 执行完才返回 HTML——那会阻塞页面渲染。应分两步:
- PHP 页面立即输出
标签,含占位属性:preload="none"、poster="/temp-loading.gif"、自定义data-video-id="123" - 另起一个轻量接口(如
/api/video-meta.php?id=123),由 JS 异步请求,返回 JSON:{"duration": 214.5, "poster": "/covers/123.jpg", "ready": true} - JS 收到后更新
video的duration属性、替换poster,并可选调用load()触发真实预加载
PHP 后端要注意哪些坑?
常见失效点不在代码逻辑,而在环境与边界:
立即学习“PHP免费学习笔记(深入)”;
-
shell_exec()默认被禁用,需确认php.ini中disable_functions未包含它 -
ffprobe超时必须设限,否则大视频卡住整个 PHP 进程:exec("timeout 5s ffprobe ...", $output, $return_code) - 视频路径不能直接传用户输入,必须白名单校验或映射为内部 ID,防止
../../../etc/passwd类路径遍历 - 并发调用
ffprobe多次?加文件锁或缓存结果(Redis / APCu),避免重复解析同一视频
最易被忽略的是:移动端 WebView 对 preload 的支持几乎形同虚设,别依赖它;真正的“预加载提示”得靠 PHP 提前算好元数据 + 前端渐进式接管。
