PHP如何实现视频播放断点续播_PHP视频断点续播实现逻辑【要点】

PHP实现视频断点续播需手动处理HTTP Range请求:响应206状态码,设置Accept-Ranges、Content-Range、Content-Length和Content-Type等关键Header;避免Web服务器或CDN劫持Range响应。

PHP 本身不直接处理视频断点续播

断点续播不是靠 PHP 后端“播放”实现的,而是依赖 HTTP Range 请求 + 前端 标签的原生能力。PHP 的作用仅限于:正确响应字节范围请求(206 Partial Content),并确保文件可被分段读取。如果 PHP 脚本直接输出视频但没处理 Range 头,浏览器就无法拖动、无法续播。

必须用 readfile() 配合 header() 手动处理 Range

不能简单 echo file_get_contents($path) 或重定向到文件路径(比如 header("Location: /videos/xxx.mp4")),那样会丢失 Range 支持。需手动解析 HTTP_RANGE,计算起始/结束偏移,并设置对应 header:

if (isset($_SERVER['HTTP_RANGE'])) {
    $range = $_SERVER['HTTP_RANGE'];
    if (preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)) {
        $start = (int)$matches[1];
        $end = isset($matches[2]) ? (int)$matches[2] : filesize($file) - 1;
        $length = $end - $start + 1;
    header('HTTP/1.1 206 Partial Content');
    header('Content-Range: bytes ' . $start . '-' . $end . '/' . filesize($file));
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . $length);
    header('Content-Type: video/mp4');

    $fp = fopen($file, 'rb');
    fseek($fp, $start);
    fpassthru($fp);
    fclose($fp);
    exit;
}

} // 没有 Range 请求时,走完整响应 header('Content-Length: ' . filesize($file)); header('Content-Type: video/mp4'); readfile($file);

关键 Header 缺一不可,否则前端视为普通下载

以下 header 必须全部存在且值正确,否则 Chrome/Safari 会禁用进度条、拖动失效、续播失败:

  • Accept-Ranges: bytes — 告诉浏览器“我支持分段”
  • Content-Range(仅 206 响应)— 格式必须是 bytes 123-456/789,末尾总

    大小不能错
  • Content-Length — 对应本次响应的字节数(不是整个文件)
  • Content-Type — 必须匹配视频实际格式(如 video/mp4video/webm

漏掉 Accept-Ranges 是最常见错误,会导致前端完全忽略 Range 能力。

注意 Nginx/Apache 可能劫持 PHP 的 Range 响应

如果 PHP 脚本返回了正确的 206 和 header,但浏览器仍收到 200 全量响应,大概率是 Web 服务器在中间做了覆盖。例如:

  • Nginx 默认对 PHP-FPM 返回的 206 响应自动转为 200,需加 fastcgi_ignore_headers Range; 并确认未启用 fastcgi_buffering off;
  • Apache 的 mod_php 在某些配置下会清空部分 header,建议用 mod_proxy_fcgi 替代
  • CDN 或反向代理(如 Cloudflare)默认不透传 Range 请求,需显式开启 byte-range 支持

调试时务必用 curl -v -H "Range: bytes=0-999" http://yoursite.com/video.php 直接验证响应状态码和 header,别只看浏览器表现。