推荐使用ffprobe解析视频元数据获取准确时长;因其支持主流格式、输出JSON便于PHP解析,且比getid3和已废弃的ffmpeg-php更稳定可靠。

PHP 本身不能直接“播放”视频,也无法在服务端实时读取正在播放的视频时长;所谓“获取视频播放时长”,实际是指**解析视频文件元数据,提取其总时长(duration)**。最可靠、通用的做法是调用外部命令行工具 ffprobe(FFmpeg 套件的一部分),而非依赖 PHP 内置函数或不稳定的扩展。
为什么不要用 getid3 或 ffmpeg-php
虽然 getid3 库能读取部分视频文件的时长,但它严重依赖文件头信息是否完整、编码格式是否被支持(如某些 H.265/HEVC 或 fragmented MP4 可能返回 0 或 false)。ffmpeg-php 扩展早已停止维护,不兼容 PHP 7.4+,且编译困难。生产环境应避免。
-
getid3对网络流、加密 HLS、或未完成上传的临时文件几乎无效 -
ffmpeg-php在 PHP 8 下无法安装,官方仓库已归档 - 纯 PHP 实现(如手动解析 MP4 atoms)复杂度高、易出错、不跨格式
用 ffprobe 获取准确时长(推荐方案)
ffprobe 是 FFmpeg 提供的轻量级媒体分析工具,能精准读取几乎所有主流格式(MP4、AVI、MKV、MOV、WebM)的 duration 字段,且支持 JSON 输出,便于 PHP 解析。
- 确保服务器已安装 FFmpeg:运行
ffprobe -version验证 - PHP 必须允许执行系统命令(
shell_exec、exec等未被禁用) - 路径需绝对(尤其在 CLI 与 Web 环境路径不一致时),建议写死或配置为常量
exec('ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 /path/to/video.mp4 2>/dev/null', $output, $return_code);
$duration = floatval(trim($output[0]));
if ($return_code !== 0 || $duration <= 0) {
// 处理失败:文件不存在、损坏、权限不足
}
处理常见失败场景
即使用了 ffprobe,仍可能返回空值或错误码。关键不是“有没有命令”,而是“为什么没拿到结果”。
立即学习“PHP免费学习笔记(深入)”;
- 文件路径含中文或空格?必须用
escapeshellarg()包裹:escapeshellarg($video_path) - Web 服务器用户(如
www-data)无权读取该文件?检查ls -l和 SELinux/AppArmor 策略 - 视频是 HTTP URL?
ffprobe支持直接解析远程地址,但需确保 PHP 进程能出外网,且目标服务允许 HEAD/GET - 返回
N/A?说明容器未写入 duration(常见于录制中未封包的 MP4),此时可尝试加-sexagesimal或 fallback 到streams中计算
替代方案:用 ffprobe JSON 输出更健壮
默认文本输出易受格式变动影响。JSON 模式结构稳定,适合自动化解析。
$cmd = 'ffprobe -v quiet -show_format -print_format json ' . escapeshellarg($video_path); $result = shell_exec($cmd); $data = json_decode($result, true); $duration = isset($data['format']['duration']) ? (float)$data['format']['duration'] : 0;
注意:duration 字段可能为字符串(如 "123.45"),务必用 (float) 转换;若缺失,可尝试从第一个视频流的 tags:DURATION 或估算帧率 × 帧数,但可靠性大幅下降。
真正麻烦的从来不是“怎么写一行命令”,而是视频文件来源不可控——用户上传的、CDN 回源的、分片合并的、甚至只是个 .txt 伪装的链接。别省略 escapeshellarg,别忽略 $return_code,也别相信任何未经验证的 duration 字段。元数据永远比你想象的更脆弱。











