php 支持斷點續傳的文件下載類

php 支持斷點續傳,主要依靠HTTP協議中 header HTTP_RANGE實現。

HTTP斷點續傳原理
Http頭 Range、Content-Range()
HTTP頭中通常斷點下載時纔用到Range和Content-Range實體頭,
Range用戶請求頭中,指定第一個字節的位置和最後一個字節的位置,如(Range:200-300)
Content-Range用於響應頭

請求下載整個文件: 
GET /test.rar HTTP/1.1 
Connection: close 
Host: 116.1.219.219 
Range: bytes=0-801 //通常請求下載整個文件是bytes=0- 或不用這個頭

通常正常回應 
HTTP/1.1 200 OK 
Content-Length: 801      
Content-Type: application/octet-stream 
Content-Range: bytes 0-800/801 //801:文件總大小

FileDownload.class.php
php

[php] view plain copylinux

  1. <?php  ubuntu

  2. /** php下載類,支持斷點續傳 app

  3. *   Date:   2013-06-30 測試

  4. *   Author: fdipzone ui

  5. *   Ver:    1.0 this

  6. * spa

  7. *   Func: .net

  8. *   download: 下載文件 指針

  9. *   setSpeed: 設置下載速度 

  10. *   getRange: 獲取header中Range 

  11. */  

  12.   

  13. class FileDownload{ // class start  

  14.   

  15.     private $_speed = 512;   // 下載速度  

  16.   

  17.   

  18.     /** 下載 

  19.     * @param String  $file   要下載的文件路徑 

  20.     * @param String  $name   文件名稱,爲空則與下載的文件名稱同樣 

  21.     * @param boolean $reload 是否開啓斷點續傳 

  22.     */  

  23.     public function download($file$name=''$reload=false){  

  24.         if(file_exists($file)){  

  25.             if($name==''){  

  26.                 $name = basename($file);  

  27.             }  

  28.   

  29.             $fp = fopen($file'rb');  

  30.             $file_size = filesize($file);  

  31.             $ranges = $this->getRange($file_size);  

  32.   

  33.             header('cache-control:public');  

  34.             header('content-type:application/octet-stream');  

  35.             header('content-disposition:attachment; filename='.$name);  

  36.   

  37.             if($reload && $ranges!=null){ // 使用續傳  

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

  39.                 header('Accept-Ranges:bytes');  

  40.                   

  41.                 // 剩餘長度  

  42.                 header(sprintf('content-length:%u',$ranges['end']-$ranges['start']));  

  43.                   

  44.                 // range信息  

  45.                 header(sprintf('content-range:bytes %s-%s/%s'$ranges['start'], $ranges['end'], $file_size));  

  46.                   

  47.                 // fp指針跳到斷點位置  

  48.                 fseek($fp, sprintf('%u'$ranges['start']));  

  49.             }else{  

  50.                 header('HTTP/1.1 200 OK');  

  51.                 header('content-length:'.$file_size);  

  52.             }  

  53.   

  54.             while(!feof($fp)){  

  55.                 echo fread($fpround($this->_speed*1024,0));  

  56.                 ob_flush();  

  57.                 //sleep(1); // 用於測試,減慢下載速度  

  58.             }  

  59.   

  60.             ($fp!=null) && fclose($fp);  

  61.   

  62.         }else{  

  63.             return '';  

  64.         }  

  65.     }  

  66.   

  67.   

  68.     /** 設置下載速度 

  69.     * @param int $speed 

  70.     */  

  71.     public function setSpeed($speed){  

  72.         if(is_numeric($speed) && $speed>16 && $speed<4096){  

  73.             $this->_speed = $speed;  

  74.         }  

  75.     }  

  76.   

  77.   

  78.     /** 獲取header range信息 

  79.     * @param  int   $file_size 文件大小 

  80.     * @return Array 

  81.     */  

  82.     private function getRange($file_size){  

  83.         if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])){  

  84.             $range = $_SERVER['HTTP_RANGE'];  

  85.             $range = preg_replace('/[\s|,].*/'''$range);  

  86.             $range = explode('-'substr($range, 6));  

  87.             if(count($range)<2){  

  88.                 $range[1] = $file_size;  

  89.             }  

  90.             $range = array_combine(array('start','end'), $range);  

  91.             if(empty($range['start'])){  

  92.                 $range['start'] = 0;  

  93.             }  

  94.             if(empty($range['end'])){  

  95.                 $range['end'] = $file_size;  

  96.             }  

  97.             return $range;  

  98.         }  

  99.         return null;  

  100.     }  

  101.   

  102. // class end  

  103.   

  104. ?>  

demo

[php] view plain copy

  1. <?php  

  2.   

  3. require('FileDownload.class.php');  

  4. $file = 'book.zip';  

  5. $name = time().'.zip';  

  6. $obj = new FileDownload();  

  7. $flag = $obj->download($file$name);  

  8. //$flag = $obj->download($file, $name, true); // 斷點續傳  

  9.   

  10. if(!$flag){  

  11.     echo 'file not exists';  

  12. }  

  13.   

  14. ?>  

斷點續傳測試方法:
使用linux wget命令去測試下載, wget -c -O file http://xxx

1.先關閉斷點續傳
$flag = $obj->download($file, $name);

[plain] view plain copy

  1. fdipzone@ubuntu:~/Downloads$ wget -O test.rar http://demo.fdipzone.com/demo.php  

  2. --2013-06-30 16:52:44--  http://demo.fdipzone.com/demo.php  

  3. 正在解析主機 demo.fdipzone.com... 127.0.0.1  

  4. 正在鏈接 demo.fdipzone.com|127.0.0.1|:80... 已鏈接。  

  5. 已發出 HTTP 請求,正在等待迴應... 200 OK  

  6. 長度: 10445120 (10.0M) [application/octet-stream]  

  7. 正在保存至: 「test.rar」  

  8.   

  9. 30% [============================>                                                                     ] 3,146,580    513K/s  估時 14s  

  10. ^C  

  11. fdipzone@ubuntu:~/Downloads$ wget -c -O test.rar http://demo.fdipzone.com/demo.php  

  12. --2013-06-30 16:52:57--  http://demo.fdipzone.com/demo.php  

  13. 正在解析主機 demo.fdipzone.com... 127.0.0.1  

  14. 正在鏈接 demo.fdipzone.com|127.0.0.1|:80... 已鏈接。  

  15. 已發出 HTTP 請求,正在等待迴應... 200 OK  

  16. 長度: 10445120 (10.0M) [application/octet-stream]  

  17. 正在保存至: 「test.rar」  

  18.   

  19. 30% [============================>                                                                     ] 3,146,580    515K/s  估時 14s  

  20. ^C  

  21.   

  22. 能夠看到,wget -c不能斷點續傳  


2.開啓斷點續傳
$flag = $obj->download($file, $name, true);

[plain] view plain copy

  1. fdipzone@ubuntu:~/Downloads$ wget -O test.rar http://demo.fdipzone.com/demo.php  

  2. --2013-06-30 16:53:19--  http://demo.fdipzone.com/demo.php  

  3. 正在解析主機 demo.fdipzone.com... 127.0.0.1  

  4. 正在鏈接 demo.fdipzone.com|127.0.0.1|:80... 已鏈接。  

  5. 已發出 HTTP 請求,正在等待迴應... 200 OK  

  6. 長度: 10445120 (10.0M) [application/octet-stream]  

  7. 正在保存至: 「test.rar」  

  8.   

  9. 20% [==================>                                                                               ] 2,097,720    516K/s  估時 16s  

  10. ^C  

  11. fdipzone@ubuntu:~/Downloads$ wget -c -O test.rar http://demo.fdipzone.com/demo.php  

  12. --2013-06-30 16:53:31--  http://demo.fdipzone.com/demo.php  

  13. 正在解析主機 demo.fdipzone.com... 127.0.0.1  

  14. 正在鏈接 demo.fdipzone.com|127.0.0.1|:80... 已鏈接。  

  15. 已發出 HTTP 請求,正在等待迴應... 206 Partial Content  

  16. 長度: 10445121 (10.0M),7822971 (7.5M) 字節剩餘 [application/octet-stream]  

  17. 正在保存至: 「test.rar」  

  18.   

  19. 100%[++++++++++++++++++++++++=========================================================================>] 10,445,121   543K/s   花時 14s     

  20.   

  21. 2013-06-30 16:53:45 (543 KB/s) - 已保存 「test.rar」 [10445121/10445121])  

  22.   

  23. 能夠看到會從斷點的位置(%20)開始下載。  

相關文章
相關標籤/搜索