php服务端识别断点续传请求关键在解析$_server['http_range']并校验格式,提取起始偏移后用fseek定位,返回206状态及正确content-range头;须避免readfile全量读取、忽略if-range头、输出超长或含bom,推荐交由nginx处理range而php仅做鉴权与重定向。

PHP 服务端如何识别断点续传请求
关键在判断客户端是否携带 Range 请求头,以及服务端是否返回正确的 206 Partial Content 状态码。PHP 默认不自动处理分片请求,必须手动解析 $_SERVER['HTTP_RANGE'] 并计算偏移量。
常见错误是直接用 fopen($file, 'r') 从头读取,导致续传变成重传;或忽略 If-Range 头,导致文件被修改后仍返回旧分片。
- 检查
$_SERVER['HTTP_RANGE']是否存在,格式通常为bytes=12345-或bytes=12345-67890 - 用
preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)提取起始字节;若末尾为空,则读取到文件末尾 - 务必校验起始位置不超过文件大小,否则返回
416 Requested Range Not Satisfiable - 设置响应头:
header('HTTP/1.1 206 Partial Content')、header("Content-Range: bytes {$start}-{$end}/{$fileSize}")、header("Accept-Ranges: bytes")
PHP 输出大文件时如何避免内存溢出和超时
直接 readfile() 或 file_get_contents() 会把整个分片加载进内存,断点续传场景下极易触发 Fatal error: Allowed memory size exhausted 或 max_execution_time 超时。
必须流式输出,并关闭输出缓冲——尤其在 CLI 或 Nginx + PHP-FPM 架构下,ob_end_clean() 和 flush() 往往无效,真正起作用的是禁用 output_buffering 和设置 implicit_flush。
- 在脚本开头加
ini_set('output_buffering', 'Off')和ini_set('implicit_flush', 1) - 用
fopen($file, 'rb')打开,fseek($fp, $start)定位,再循环fread($fp, 8192)输出 - 每次
echo后调用fastcgi_finish_request()(仅限 PHP-FPM)可提前释放连接,避免占用 worker - Nginx 需关闭
gzip(否则压缩会阻塞流式传输),并设置proxy_buffering off(如走反向代理)
前端发送断点续传请求时 PHP 后端要注意的兼容细节
不是所有前端都严格遵循 RFC 7233:有些用 X-Resume-Position 自定义头,有些在 POST body 里传 offset,还有些把断点信息藏在 URL query 中(如 ?offset=1048576)。PHP 端不能只依赖 HTTP_RANGE 做唯一判断。
更麻烦的是,部分安卓 WebView 或旧版 iOS Safari 对 206 响应体长度校验极严——如果 Content-Range 声明的长度与实际输出字节数不一致(比如多输出一个换行或 BOM),就会中断下载。
- 统一入口先检查
$_SERVER['HTTP_RANGE'],再 fallback 到$_GET['offset']或$_SERVER['HTTP_X_RESUME_POSITION'] - 输出前用
ob_end_clean()清除所有可能的输出(包括 BOM、Warning、Notice 输出) - 确保
Content-Length不设置(由 Web 服务器自动计算),且Content-Range中的$end是真实读取结束位置($end = min($start + $chunkSize - 1, $fileSize - 1)) - 对非 GET 请求(如断点上传用的 PUT/PATCH),需额外验证
Content-Range请求头是否合法,并检查目标文件写权限与已存在分片大小
为什么用 PHP 做断点续传服务容易出问题
PHP 本质是无状态 CGI 模型,不适合长连接、高并发流式传输。Nginx/Apache 本身就能高效处理 Range 请求(启用 accept_ranges on 即可),而绕过 Web 服务器让 PHP 全权接管,反而引入单进程瓶颈、超时风险和 header 管理复杂度。
真正需要 PHP 参与的,只是鉴权、路径映射、访问日志或动态生成临时文件等逻辑。纯静态文件续传,应该交还给 Web 服务器;PHP 只做“守门人”——校验 token 后重定向到内部 location,或用 X-Accel-Redirect(Nginx)/ X-Sendfile(Apache)委托传输。
- 优先考虑
X-Accel-Redirect:PHP 校验通过后,输出header("X-Accel-Redirect: /internal/files/xxx.zip"),由 Nginx 读文件并处理 Range - 避免在 PHP 中拼接大文件路径后直接
readfile(),路径需白名单过滤,防止../目录穿越 - 并发续传时,多个请求可能同时写同一文件(上传场景),需用
flock()或独立分片存储(如按 offset 分块存为file.part.001)再合并
最常被忽略的一点:断点续传不是功能开关,而是整条链路(前端请求策略、CDN 缓存配置、Web 服务器 Range 支持、PHP 运行模式、磁盘 I/O 能力)的协同结果。单独改 PHP 代码,往往治标不治本。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











