HTTP 断点续传及其基于 PHP 的实现方案 |
HTTP 断点续传及其基于 PHP 的实现方案 |
2009-09-22 15:54:50, Tue
Post
#1
|
|
猫猫猫 Group: Power Cat Posts: 626 Joined: 2006-12-8 Member No.: 2 |
引用 断点续传是我们现在经常接触的概念,那么HTTP协议是如何支持断点续传的呢。我们先从一个例子来看看。
下面是一个断点续传的例子:(使用NetVampire得到) I01-7-1219:19:23-------------------------Attempt1------------------------- P01-7-1219:19:24Connectingto127.0.0.3... P01-7-1219:19:24Connectedto127.0.0.3[127.0.0.3]S01-7-1219:19:24GET/VS0515AI.EXEHTTP/1.1 S01-7-1219:19:24Connection:close S01-7-1219:19:24Host:127.0.0.3 S01-7-1219:19:24Accept:*/* S01-7-1219:19:24Pragma:no-cache S01-7-1219:19:24Cache-Control:no-cache S01-7-1219:19:24Referer:http://127.0.0.3/ S01-7-1219:19:24User-Agent:Mozilla/4.04[en](Win95;I;Nav) S01-7-1219:19:24 R01-7-1219:19:24HTTP/1.1200OK R01-7-1219:19:24Server:ZeroHttpServer/1.0 R01-7-1219:19:24Date:Thu,12Jul200111:19:24GMT R01-7-1219:19:24Cache-Control:no-cache R01-7-1219:19:24Last-Modified:Tue,30Jan200113:11:30GMT R01-7-1219:19:24Content-Type:application/octet-stream R01-7-1219:19:24Content-Length:15143086 R01-7-1219:19:24Connection:close R01-7-1219:19:24 P01-7-1219:19:25Datatransferstarted I01-7-1219:19:32JobStoppedbyuser I01-7-1219:19:33Received5275648bytesin0:00:07(691435bytes/s) I01-7-1219:19:40-------------------------Attempt2------------------------- P01-7-1219:19:40Connectingto127.0.0.3... P01-7-1219:19:40Connectedto127.0.0.3[127.0.0.3] S01-7-1219:19:40GET/VS0515AI.EXEHTTP/1.1 S01-7-1219:19:40Connection:close S01-7-1219:19:40Host:127.0.0.3 S01-7-1219:19:40Accept:*/* S01-7-1219:19:40Pragma:no-cache S01-7-1219:19:40Cache-Control:no-cache S01-7-1219:19:40Referer:http://127.0.0.3/ S01-7-1219:19:40User-Agent:Mozilla/4.04[en](Win95;I;Nav) S01-7-1219:19:40Range:bytes=5275648- S01-7-1219:19:40 R01-7-1219:19:40HTTP/1.1206PartialContent R01-7-1219:19:40Server:ZeroHttpServer/1.0 R01-7-1219:19:40Date:Thu,12Jul200111:19:40GMT R01-7-1219:19:40Cache-Control:no-cache R01-7-1219:19:40Last-Modified:Tue,30Jan200113:11:30GMT R01-7-1219:19:40Content-Type:application/octet-stream R01-7-1219:19:40Content-Range:bytes5275648-15143085/15143086 R01-7-1219:19:40Content-Length:9867438 R01-7-1219:19:40Connection:close R01-7-1219:19:40 P01-7-1219:19:40Datatransferstarted I01-7-1219:19:41JobStoppedbyuser I01-7-1219:19:41Received1124756bytesin0:00:01(969617bytes/s) 第一次是普通的传输;第二次由于没有传完全,就发出了Range这个头部,从5275648字节开始传输(默认是按字节算),回应使用206状态值,表示现在开始部分传输,回复Content-Length头部,表示传输的部分,用字节记,然后就与普通传输没有区别了。 |
|
|
2009-09-22 15:55:50, Tue
Post
#2
|
|
猫猫猫 Group: Power Cat Posts: 626 Joined: 2006-12-8 Member No.: 2 |
断点续传指的是在上传时,将上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传,下面我们来看看php 断点续传功能的实现方法吧。
代码 <?php
/** * 作者 于恩水<yuenshui@126.com> * 支持断点续传下载 * 实例代码: * $down = new SD_DownLoad(); * $down->Down('E:/iso/MS.Office2003SP1.CHS.iso'); **/ class SD_DownLoad { /** * 下载的开始点 * * @access private * @var integer */ private $mDownStart; /** * 文件大小 * * @access private * @var integer */ private $mFileSize; /** * 文件句柄 * * @access private * @var integer */ private $mFileHandle; /** * 文件全路径 * * @access private * @var string */ private $mFilePath; /** * 文件下载时显示的文件名 * * @access private * @var string */ private $mFileName; /** * 构造函数 * * @access public * @return void **/ public function __construct() { } /** * 下载 * * @param string $pFilePath 文件全路径 * @param string pFileName 文件下载时显示的文件名,缺省为实际文件名 * @access public * @return void **/ public function Down($pFilePath, $pFileName = '') { $this->mFilePath = $pFilePath; if(!$this->IniFile()) $this->SendError(); $this->mFileName = empty($pFileName) ? $this->GetFileName() : $pFileName; $this->IniFile(); $this->SetStart(); $this->SetHeader(); $this->Send(); } /** * 初始化文件信息 * * @access private * @return boolean **/ private function IniFile() { if(!is_file($this->mFilePath)) return false; $this->mFileHandle = fopen($this->mFilePath, 'rb'); $this->mFileSize = filesize($this->mFilePath); return true; } /** * 设置下载开始点 * * @access private * @return void **/ private function SetStart() { if (!empty($_SERVER['HTTP_RANGE']) && preg_match("/^bytes=([d]?)-([d]?)$/i", $_SERVER['HTTP_RANGE'], $match)) { if(empty($match[1])) $this->mDownStart = $match[1]; fseek($this->mFileHandle, $this->mDownStart); } else { $this->mDownStart = 0; } } /** * 设置http头 * * @access private * @return void **/ private function SetHeader() { @header("Cache-control: public"); @header("Pragma: public"); Header("Content-Length: " . ($this->mFileSize - $this->mDownStart)); if ($this->mDownStart > 0) { @Header("HTTP/1.1 206 Partial Content"); Header("Content-Ranges: bytes" . $this->mDownStart . "-" . ($this->mFileSize - 1) . "/" . $this->mFileSize); } else { Header("Accept-Ranges: bytes"); } @header("Content-Type: application/octet-stream"); @header("Content-Disposition: attachment;filename=" . $this->mFileName); } /** * 获取全路径里的文件名部分 * * @access private * @return string **/ private function GetFileName() { return basename ($this->mFilePath); } /** * 发送数据 * * @access private * @return void **/ private function Send() { fpassthru($this->mFileHandle); } /** * 发送错误 * * @access public * @return void **/ public function SendError() { @header("HTTP/1.0 404 Not Found"); @header("Status: 404 Not Found"); exit(); } } |
|
|
Lo-Fi Version | Time is now: 2024-10-30 19:31 |