使用 readfile() 配合正确的 http 响应头(如 content-type、content-disposition 和 accept-ranges)即可实现 mp4 视频的强制下载与断点续传。核心在于检测客户端发送的 range 请求头,计算字节范围,并通过 fseek() 定位文件指针后分块输出,同时设置 content-range 响应头告知客户端当前传输的数据区间。

如何配置基础响应头以触发浏览器下载行为
要实现强制下载而非直接在浏览器中播放,必须设置 Content-Disposition: attachment 并指定文件名。同时,对于视频文件,需明确声明 Content-Type: video/mp4。若省略这些头部,浏览器可能尝试内联播放;若未正确设置 MIME 类型,部分客户端可能拒绝处理或报错。以下代码展示了最基础的下载逻辑,它会将整个文件一次性发送给客户端,适用于不支持断点续传或无需大文件优化的场景。

<?php $file = 'video.mp4';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream'); // 或使用 video/mp4
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>
上述代码通过 readfile() 直接读取文件内容并输出到标准输出流。虽然简单,但它无法处理中断后的重新连接,因为每次请求都会从头开始读取整个文件。对于大体积 MP4 文件,这会导致带宽浪费和用户体验下降。因此,需要引入对 HTTP_RANGE 环境变量的解析,以实现分段传输。
如何解析 Range 头并实现断点续传逻辑
断点续传的关键在于支持 HTTP 1.1 的 Range 请求。当客户端支持续传时,它会发送 Range: bytes=0-1023 这样的头部,表示从第 0 字节到第 1023 字节。服务器需解析该字符串,提取起始和结束位置,使用 fopen() 打开文件,用 fseek() 跳转到指定偏移量,然后循环读取剩余数据直到结束位置。同时,必须返回 206 Partial Content 状态码以及 Content-Range: bytes 0-1023/total_size 头部,否则客户端可能无法识别这是部分数据。

$_SERVER['HTTP_RANGE']
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











