You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取PHP中readfile传输远程视频文件时的已传输内容大小

实现方案

你当前使用readfile()直接输出远程文件的方式没有中间统计的切入点,同时也没有处理视频播放常见的范围请求(用户拖动进度条时浏览器发起的Range请求),不仅无法统计传输量,还可能出现播放拖动异常的问题。

核心实现思路

  • 不直接调用readfile(),改用逐块读取远程文件流、逐块输出到客户端的方式,每输出一块就累加已传输字节数
  • 增加Range请求的支持,兼容视频拖动播放的场景,保证统计数据和实际传输内容匹配
  • 检测客户端连接状态,即使客户端中途中断播放,也能正常记录最终已传输的字节数
  • 统计结果可以根据业务需要存入日志、数据库或Session中

可直接运行的实现代码

<?php
// 远程视频地址
$file = 'https://example.com/?rud27pxppu45zk.mp4';

// 获取远程文件头信息
$head = array_change_key_case(get_headers($file, TRUE));
$totalSize = $head['content-length'];
$mimeType = $head['content-type'] ?? 'video/mp4';

// 初始化传输计数
$transferred = 0;
// 可在此处自定义统计前置逻辑,比如初始化数据库记录、绑定用户标识等

// 处理视频拖动的Range请求
$start = 0;
$end = $totalSize - 1;
if (isset($_SERVER['HTTP_RANGE'])) {
    list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
    if (str_contains($range, ',')) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes */$totalSize");
        exit;
    }
    if (str_starts_with($range, '-')) {
        $start = $totalSize - intval(substr($range, 1));
    } else {
        $range = explode('-', $range);
        $start = intval($range[0]);
        $end = (isset($range[1]) && is_numeric($range[1])) ? intval($range[1]) : $end;
    }
    $end = ($end > $totalSize - 1) ? $totalSize - 1 : $end;
    if ($start > $end || $start >= $totalSize || $end < 0) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes */$totalSize");
        exit;
    }
    header('HTTP/1.1 206 Partial Content');
    header("Content-Range: bytes $start-$end/$totalSize");
    $length = $end - $start + 1;
} else {
    $length = $totalSize;
}

// 输出基础响应头
header('Content-Type: ' . $mimeType);
header('Accept-Ranges: bytes');
header('Content-Disposition: inline');
header('Content-Length: ' . $length);

// 打开远程文件流
$remoteStream = fopen($file, 'rb');
fseek($remoteStream, $start);

// 逐块读取输出并计数
$blockSize = 1024 * 8; // 单次读取8KB,可根据服务器性能调整,块越小统计精度越高
while (!feof($remoteStream) && $transferred < $length && !connection_aborted()) {
    $buffer = fread($remoteStream, $blockSize);
    echo $buffer;
    flush();
    ob_flush();
    $transferred += strlen($buffer);
}

// 关闭远程流
fclose($remoteStream);

// 统计结果处理逻辑,可自定义存入数据库、日志等
// 示例:写入本地日志
file_put_contents('./video_transfer_log.txt', date('Y-m-d H:i:s') . " 已传输字节数:{$transferred}/{$totalSize}\n", FILE_APPEND);

exit;

注意事项

  • 服务器需要开启allow_url_fopen配置才能正常读取远程HTTP文件流,如果该配置被关闭,可以改用curl的CURLOPT_WRITEFUNCTION回调实现逐块读取,在回调中完成输出和计数即可
  • 如果需要区分不同用户的传输数据,统计时可以绑定用户ID、Session ID等唯一标识
  • 远程视频地址如果存放在第三方存储服务,要保证服务器请求该资源时不会触发防盗链拦截

内容的提问来源于stack exchange,提问作者Alexandru Popa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:18:00