PHP支持断点续传实例代码

让PHP下载代码支持断点续传,主要靠的 HTTP协议中header Content-Range来实现.

先来说说 HTTP的下载原理

对于HTTP协议,向服务器请求某个文件时,只要发送类似如下的请求即可,代码如下:

GET /Path/FileName HTTP/1.0

Host: www.server.com:80

Accept: **表示接收任何类型的数据。User-Agent表示用户代理,这个字段可有可无,但强烈建议加上,因为它是服务器统计、追踪以及识别客户端的依据。Connection字段中的close表示使用非持久连接。

关于HTTP协议更多的细节可以参考RFC2616(HTTP 1.1),因为我只是想通过HTTP协议实现文件下载,所以也只看了一部分,并没有看全。

如果服务器成功收到该请求,并且没有出现任何错误,则会返回类似下面的数据:

  1. HTTP/1.0 200 OK
  2. Content-Length: 13057672
  3. Content-Type: application/octet-stream
  4. Last-Modified: Wed, 10 Oct 2005 00:56:34 GMT
  5. Accept-Ranges: bytes
  6. ETag: "2f38a6cac7cec51:160c"
  7. Server: Microsoft-IIS/6.0
  8. X-Powered-By: ASP.NET
  9. Date: Wed, 16 Nov 2005 01:57:54 GMT
  10. Connection: close

先定义一个函数 getRange() 这个函数用来处理 header中 Range 具体数据的处理,代码如下:

  1. /** $file_size 文件大小 */
  2. function getRange($file_size){
  3. $range = isset($_SERVER['HTTP_RANGE'])?$_SERVER['HTTP_RANGE']:null;
  4. if(!emptyempty($range)){
  5. $range = preg_replace('/[s|,].*/', '', $range);
  6. $range = explode('-',substr($range,6));
  7. if (count($range) < 2 ) {
  8. $range[1] = $file_size;
  9. }
  10. $range = array_combine(array('start','end'),$range);
  11. if (emptyempty($range['start'])) {
  12. $range['start'] = 0;
  13. }
  14. if (!isset ($range['end']) || emptyempty($range['end'])) {
  15. $range['end'] = $file_size;
  16. }
  17. return $range;
  18. }
  19. return null;
  20. }

假设文件的地址为 $file_path,代码如下:

  1. $speed = 512;//此参数为下载最大速度
  2. $pos = strrpos($file_path, "/");
  3. $file_name = substr($file_path, $pos+1);
  4. $file_size = filesize($file_path);
  5. $ranges = getRange($file_size);
  6. $fh = fopen($file_path, "rb");
  7. header('Cache-control: public');
  8. header('Content-Type: application/octet-stream');
  9. header('Content-Disposition: attachment; filename='.$file_name);
  10. if ($ranges != null) {
  11. header('HTTP/1.1 206 Partial Content');
  12. header('Accept-Ranges: bytes');
  13. header(sprintf('Content-Length: %u',$ranges['end'] - $ranges['start']));
  14. header(sprintf('Content-Range: bytes %s-%s/%s', $ranges['start'], $ranges['end'], $file_size));
  15. fseek($fh, sprintf('%u',$ranges['start']));
  16. }else{
  17. header("HTTP/1.1 200 OK");
  18. header(sprintf('Content-Length: %s', $file_size));
  19. }
  20. while(!feof($fh))
  21. {
  22. echo fread($fh, round($speed*1024, 0));
  23. ob_flush();
  24. sleep(1);
  25. }
  26. ($fh != null) && fclose($fh);

基本如此,就可以解决一般性文件的断点续传或者下载.