PHP如何获取视频播放时长_PHP获取视频播放时长途径【实践】

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

PHP 本身不能直接“播放”视频,也无法在服务端实时读取正在播放的视频时长;所谓“获取视频播放时长”,实际是指**解析视频文件元数据,提取其总时长(duration)**。最可靠、通用的做法是调用外部命令行工具 ffprobe(FFmpeg 套件的一部分),而非依赖 PHP 内置函数或不稳定的扩展。

为什么不要用 getid3ffmpeg-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、A

VI、MKV、MOV、WebM)的 duration 字段,且支持 JSON 输出,便于 PHP 解析。

  • 确保服务器已安装 FFmpeg:运行 ffprobe -version 验证
  • PHP 必须允许执行系统命令(shell_execexec 等未被禁用)
  • 路径需绝对(尤其在 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,仍可能返回空值或错误码。关键不是“有没有命令”,而是“为什么没拿到结果”。

  • 文件路径含中文或空格?必须用 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 字段。元数据永远比你想象的更脆弱。