PHP实现文件下载断点续传详解


Posted in PHP onOctober 15, 2014

如果我们的网站提供文件下载的服务,那么通常我们都希望下载可以断点续传(Resumable Download),也就是说用户可以暂停下载,并在未来的某个时间从暂停处继续下载,而不必重新下载整个文件。

通常情况下,Web服务器(如Apache)会默认开启对断点续传的支持。因此,如果直接通过Web服务器来提供文件的下载,可以不必做特别的配置,即可享受到断点续传的好处。由于这些文件直接通过Web服务器来提供下载,后端脚本无法对这个下载过程进行控制。这对于仅提供公开、静态文件的网站来说不是问题,但对于需要提供私有、动态文件的网站来说,直接通过Web服务器来提供下载就无法满足需求了。这时,就需要在编写后台脚本程序时,加入对断点续传的支持。

本文将以PHP为例,简要介绍实现文件下载断点续传的方法。

原理

断点续传的原理还是比较直观的。

HTTP协议规定了如何传输某个资源的一部分,而不是全部。比如,有一个文件的大小是1000字节,浏览器可以只请求该文件的前300个字节,或者只请求第500到第1000个字节。通过这种方式,就可以不必在一次请求中传输某个资源的全部内容,而是发起多次请求,每次仅请求其中的一部分内容。等所有这些请求都返回之后,再把得到的内容一块一块的拼接起来得到完整的资源。

实现断点续传就是要利用HTTP协议的上述特性。当用户暂停下载的时候,浏览器会记录已经下载到什么位置,当用户在未来某一时间恢复下载时,就可以从上次暂停的位置继续下载,而不必从头开始。

实现

由于部分传输不是强制的,服务器可以支持也可以不支持,所以,我们需要在程序中告诉浏览器,它请求的资源是否支持部分传输。这可以通过设置HTTP的 Accept-Ranges 响应头信息来实现。PHP代码如下:

header('Accept-Ranges: bytes');

Accept-Ranges: bytes 告诉浏览器,该资源支持以字节为单位的部分传输。这个响应头需要附加在支持部分传输的所有资源上。

当接受到一个请求时,我们需要从浏览器的请求中提取浏览器具体是在请求资源的哪一个部分。这个信息是通过 Range 请求头来传递的。在PHP中,它被存储在$_SERVER['HTTP_RANGE']中。我们需要检查这个变量是否定义了,如果定义了,则使用该值,否则,就将range设为整个资源。

$range = "0-". ($content_length-1);

if(isset($_SERVER['HTTP_RANGE'])){

    $range = $_SERVER['HTTP_RANGE'];

}

接下来,就需要分析 $range 的值,来决定返回资源的哪一部分内容。可能的取值示例:
100-200 // 第100到第200字节

500-    // 第500字节到文件末尾

-1000   // 最后的1000个字节

这里需要注意,得到一个Range之后,你需要对它的取值进行检验,包括:

1.开始位置非负
2.结束位置需要大于开始位置
3.开始位置需要小于文件长度减一 (因为这里的位置索引是从0开始的)
4.若结束位置大于文件长度减一,则需要把它的值设置为文件长度减一

如果Range的取值不合法,则需要终止程序并告知浏览器:

header('HTTP/1.1 416 Requested Range Not Satisfiable');

为了保持文章简洁,具体的校验代码这里就不提供了。下面假定你已经校验了Range的取值,并得到了 $start 和 $end 两个变量,分别表示开始位置和结束位置。

接下来要做的就是把文件的对应部分的内容发送给浏览器。不过要注意的是,这里涉及到需要发送多个HTTP响应头信息,具体如下:

header('HTTP/1.1 206 Partial Content');

header('Accept-Ranges: bytes');

header("Content-Range: bytes $start-$end/$filesize");

$length = $end - $start + 1;

header("Content-Length: $length");
/* 输出文件的指定部分 */

这里的$length需要注意一下,它的取值是本次传输的内容的长度,而不是整个文件的长度。另外需要注意的一点是,这里的HTTP状态码是206,不是200。

总结

文件下载的断点续传实际上是利用了HTTP协议中对传输部分文件的支持。而HTTP协议的这一特性不仅可以用于实现断点续传,客户端程序也可以利用它来实现多线程下载。

在实现断点续传的过程中,需要注意正确设置各种HTTP头信息。错误的头信息将导致用户下载到的文件损坏,无法使用。

PHP 相关文章推荐
php学习 函数 课件
Jun 15 PHP
fleaphp下不确定的多条件查询的巧妙解决方法
Sep 11 PHP
ecshop 批量上传(加入自定义属性)
Mar 20 PHP
朋友网关于QQ相关的PHP代码(研究QQ的绝佳资料)
Jan 26 PHP
PHP面向对象程序设计实例分析
Jan 26 PHP
Zend Framework教程之动作的基类Zend_Controller_Action详解
Mar 07 PHP
php文件系统处理方法小结
May 23 PHP
PHP常用的三种设计模式汇总
Aug 28 PHP
PHP中大括号'{}'用法实例总结
Feb 08 PHP
php注册审核重点解析(数据访问)
May 23 PHP
php使用json-schema模块实现json校验示例
Sep 28 PHP
Laravel数据库读写分离配置的方法
Oct 13 PHP
PHP多进程编程实例
Oct 15 #PHP
PHP实现采集中国天气网未来7天天气
Oct 15 #PHP
跟我学Laravel之视图 & Response
Oct 15 #PHP
跟我学Laravel之请求与输入
Oct 15 #PHP
跟我学Laravel之路由
Oct 15 #PHP
跟我学Laravel之请求(Request)的生命周期
Oct 15 #PHP
跟我学Laravel之配置Laravel
Oct 15 #PHP
You might like
让这部DC动画新作刷新你的认知
2020/03/03 欧美动漫
sae使用smarty模板的方法
2013/12/17 PHP
php实现登录tplink WR882N获取IP和重启的方法
2016/07/20 PHP
PHP实现QQ快速登录的方法
2016/09/28 PHP
php文件类型MIME对照表(比较全)
2016/10/07 PHP
利用php生成验证码
2017/02/23 PHP
BOOM vs RR BO3 第二场2.13
2021/03/10 DOTA
在IE模态窗口中自由查看HTML源码的方法
2007/03/08 Javascript
javascript json 新手入门文档
2009/12/03 Javascript
基于JQuery的6个Tab选项卡插件
2010/09/03 Javascript
jquery 定位input元素的几种方法小结
2013/07/28 Javascript
Extjs4实现两个GridPanel之间数据拖拽功能具体方法
2013/11/21 Javascript
jQuery向上遍历DOM树之parents(),parent(),closest()之间的区别
2013/12/02 Javascript
详解从angular-cli:1.0.0-beta.28.3升级到@angular/cli:1.0.0
2017/05/22 Javascript
vue使用ajax获取后台数据进行显示的示例
2018/08/09 Javascript
Node.js net模块功能及事件监听用法分析
2019/01/05 Javascript
npm 语义版本控制详解
2019/09/10 Javascript
小程序如何自主实现拦截器的示例代码
2019/11/04 Javascript
[02:29]完美世界高校联赛上海赛区回顾
2015/12/15 DOTA
Python利用正则表达式实现计算器算法思路解析
2018/04/25 Python
Python基本socket通信控制操作示例
2019/01/30 Python
用Python生成HTML表格的方法示例
2020/03/06 Python
Django实现whoosh搜索引擎使用jieba分词
2020/04/08 Python
HTML5 拖放(Drag 和 Drop)详解与实例代码
2017/09/14 HTML / CSS
Ramy Brook官网:美国现代女装品牌
2019/06/18 全球购物
写好自荐信的技巧
2013/11/08 职场文书
《兰亭集序》教学反思
2014/02/11 职场文书
如何撰写一封出色的求职信
2014/04/27 职场文书
团日活动总结
2014/04/28 职场文书
五好关工委申报材料
2014/05/31 职场文书
群众路线剖析材料
2014/09/30 职场文书
六一文艺汇演开幕词
2015/01/29 职场文书
董事长助理岗位职责
2015/02/11 职场文书
销售区域经理岗位职责
2015/04/10 职场文书
同学会感言
2015/07/30 职场文书
Ajax 的初步实现(使用vscode+node.js+express框架)
2021/06/18 Javascript