天天看点

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

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

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

原理

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

实现

由于部分传输不是强制的,服务器可以支持也可以不支持,所以,我们需要在程序中告诉浏览器,它请求的资源是否支持部分传输。这可以通过设置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("content-range: bytes $start-$end/$filesize");

$length = $end - $start + 1;

header("content-length: $length");

/ 输出文件的指定部分 /

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

总结

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

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