PHP断点续传需手动处理Range头、文件指针与响应头:用fopen('rb')打开文件,fseek定位,校验偏移后fread分块输出,返回206或416状态码,并严格按规范设置Content-Range头。

PHP怎么用fread配合Range头做断点续传
能做,但得自己管好文件指针、响应头和状态码,PHP本身不自动处理断点续传逻辑。
核心是:客户端发Range: bytes=1024-,服务端读取对应偏移并返回206 Partial Content,同时设置Content-Range和Accept-Ranges头。用fread时必须先用fseek跳到指定位置,否则读的还是开头。
-
fseek($fp, $start)必须执行,且返回值要检查(失败返回-1) - 别直接
fread($fp, $length),得算出真实可读字节数:$real_len = min($file_size - $start, $end - $start + 1) - 如果
Range超出文件大小(比如bytes=9999999-),应返回416 Requested Range Not Satisfiable,不是200
为什么fread读出来的内容不对或乱码
常见于没正确处理二进制模式或指针偏移——PHP默认以文本模式打开文件,Windows下会把\r\n转成\n,破坏原始字节。
- 务必用
fopen($path, 'rb')(b代表binary) - 用
fseek后,不要紧接着调用ftell再fseek二次校验,某些系统/PHP版本下ftell在rb模式下可能不准 - 如果读取后浏览器显示乱码或下载损坏,先用
bindec(dechex(ord($buf[0])))之类方式抽样检查前几个字节是否与原文件一致
PHP断点续传中Content-Range头怎么写才合法
格式错一个字符(比如少空格、多斜杠)就会让客户端拒绝接收,Chrome/Firefox对这个头极其敏感。
- 正确格式:
Content-Range: bytes 1024-2047/8192(注意bytes后有空格,/前无空格) - 如果只传一部分(如最后1KB),
$start = 7168; $end = 8191; $size = 8192→bytes 7168-8191/8192 - 若请求
Range: bytes=8192-(超出范围),响应416时也得带Content-Range: bytes */8192(星号不能省)
大文件下fread卡死或内存爆掉怎么办
fread一次性读太大(比如fread($fp, 2GB))会触发OOM,而太小(如每次1KB)又导致IO频繁拖慢整体速度。
- 推荐分块读取:每次
fread($fp, 8192)(8KB),边读边echo或print,避免缓冲区堆积 - 禁用输出缓冲:
if (ob_get_level()) ob_end_clean();,否则echo内容可能被缓存住,破坏流式传输 - 用
set_time_limit(0)防超时,但注意CLI和FPM行为不同——FPM下还受request_terminate_timeout限制
断点续传真正难的不是读文件,而是精确控制HTTP状态、头字段和字节边界。哪怕Range头里多一个空格,或者Content-Length算错1字节,客户端就可能静默失败,连错误提示都不给。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











