跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

PHP下载文件断点续传怎么实现_PHP大文件下载支持技巧【方法】

PHP如何用
header()
开启断点续传支持 断点续传不是靠PHP自己“记住进度”,而是靠HTTP协议配合客户端(比如浏览器、wget、curl)重新发起带
Range
头的请求。PHP要做的是正确响应这个头,并返回对应字节段——核心就是设置
Accept-Ranges: bytes
和处理
Range
请求头。 常见错误是只加了
Content-Range
但没设
Accept-Ranges
,导致客户端压根不发
Range
请求;或者忽略
If-Range
校验,让过期缓存继续续传出错数据。 必须在输出文件内容前调用
header('Accept-Ranges: bytes')
检查
$_SERVER['HTTP_RANGE']
是否存在,格式是否为
bytes=N-M
,否则按完整文件响应 用
fopen()
打开文件后,用
fseek()
跳转到起始位置,再用
fread()
读取指定长度,别用
file_get_contents()
全载入内存 响应状态码要分情况:
206 Partial Content
(有Range),
200 OK
(无Range),不能一律用200 为什么
fseek()
+
fread()
比
readfile()
更安全
readfile()
会把整个文件一次性刷进输出缓冲区,对大文件(比如2GB视频)极易触发内存溢出或超时;而
fseek()
+
fread()
可以按块读取、边读边输出,内存占用稳定在几KB。 另外
readfile()
无法精确控制起始偏移和长度,没法适配
Range
请求;哪怕你手动截断输出,HTTP头里的
Content-Length
也容易算错,导致客户端解析失败。 立即学习 “ PHP免费学习笔记(深入) ”; 用
fopen($file, 'rb')
以二进制模式打开,避免Windows下换行符干扰 计算
Content-Length
时,用
$end - $start + 1
,不是
$end - $start
读取循环中每次
fread()
不超过8192字节,防止阻塞太久被Nginx/Apache切断连接 记得
ob_end_clean()
清空已有输出缓冲,否则
header()
会失败 Apache/Nginx下
mod_xsendfile
或
X-Accel-Redirect
能替代PHP逻辑吗 能,而且更推荐。PHP只负责校验权限、生成重定向头,真实文件传输交给Web服务器,既省PHP资源,又天然支持断点续传、gzip压缩、缓存协商。 PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 但要注意:启用后PHP不能再输出任何内容(包括空格、BOM),否则重定向失效;且路径需映射到Web服务器可访问的内部位置,不能暴露真实磁盘路径。 Apache需启用
mod_xsendfile
,并配置
XSendFile On
和
XSendFilePath /path/to/files
Nginx用
X-Accel-Redirect
时,需在location里配置
internal
,并确保响应头中的路径匹配内部别名 PHP中只需
header('X-Sendfile: /real/path/to/file.zip')
(Apache)或
header('X-Accel-Redirect: /nginx-alias/file.zip')
(Nginx) 别忘了仍要设置
Accept-Ranges: bytes
——Web服务器会自动处理Range,但前提是这个头存在 客户端不发
Range
请求?检查这几个地方 即使PHP代码完全正确,客户端也可能因为缓存策略、HTTP版本或工具限制,始终发完整请求。这不是PHP的问题,但排查时容易误判。 典型表现:用
wget -c
下载失败,Chrome开发者工具Network面板里看不到
Range
请求头,
curl -H "Range: bytes=0-1023" -I
返回200而非206。 确认客户端HTTP版本≥1.1(HTTP/1.0不支持Range) 检查响应头是否有
Cache-Control: no-store
或
Pragma: no-cache
——某些旧客户端遇到强禁止缓存时,会放弃续传 用
curl -v -H "Range: bytes=0-1023" http://yoursite/file.zip
直连测试,排除CDN或反向代理拦截Range头 部分CDN(如Cloudflare免费版)默认剥离
Range
头,需在页面规则里显式开启“Partial Request”支持 断点续传真正难的不是PHP怎么写,而是理清谁在哪个环节控制哪段字节——客户端决定要哪块,Web服务器决定能不能给,PHP只是中间那个校验权限、拼好头、不搞错偏移量的角色。漏掉
Accept-Ranges
头、用错读取方式、或者被CDN静默过滤Range,都会让整套逻辑失效。

相关文章