php实现断点续传大文件示例代码
一、断点续传原理
所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了。一般断点下载时才用到Range和Content-Range实体头。
不使用断点续传
get/down.ziphttp/1.1 accept:image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/vnd.ms- excel,application/msword,application/vnd.ms-powerpoint,*/* accept-language:zh-cn accept-encoding:gzip,deflate user-agent:mozilla/4.0(compatible;msie5.01;windowsnt5.0) connection:keep-alive
服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:
HTTP/1.1200Ok content-length=106786028 accept-ranges=bytes date=mon,30apr200112:56:11gmt etag=w/"02ca57e173c11:95b" content-type=application/octet-stream server=microsoft-iis/5.0 last-modified=mon,30apr200112:56:11gmt
使用断点续传
GET/down.zipHTTP/1.0 User-Agent:NetFox RANGE:bytes=2000070- Accept:text/html,image/gif,image/jpeg,*;q=.2,*/*;q=.2
多了这么一行Range:bytes=2000070-
这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
Range的完整格式是:
Range:bytes=startOffset-targetOffset/sum[表示从startOffset读取,一直读取到targetOffset位置,读取总数为sum直接] Range:bytes=startOffset-targetOffset[字节总数也可以去掉]
服务器收到这个请求以后,返回的信息如下:
HTTP/1.1206PartialContent content-length=106786028 content-range=bytes2000070-106786027/106786028 date=mon,30apr200112:55:20gmt etag=w/"02ca57e173c11:95b" content-type=application/octet-stream server=microsoft-iis/5.0 last-modified=mon,30apr200112:55:20gmt
和前面服务器返回的信息比较一下,就会发现增加了一行:
Content-Range=bytes2000070-106786027/106786028
返回的代码也改为206了,而不再是200了。
HTTP/1.1206PartialContent
知道了以上原理,就可以进行断点续传的编程了。
二、PHP实现
/**php下载类,支持断点续传 *download:下载文件 *setSpeed:设置下载速度 *getRange:获取header中Range */ classFileDownload{ /**下载 *@paramString$file要下载的文件路径 *@paramString$name文件名称,为空则与下载的文件名称一样 *@paramboolean$reload是否开启断点续传 */ publicfunctiondownload($file,$name='',$reload=false){ $fp=@fopen($file,'rb'); if($fp){ if($name==''){ $name=basename($file); } $header_array=get_headers($file,true); //var_dump($header_array);die; //下载本地文件,获取文件大小 if(!$header_array){ $file_size=filesize($file); }else{ $file_size=$header_array['Content-Length']; } $ranges=$this->getRange($file_size); $ua=$_SERVER["HTTP_USER_AGENT"];//判断是什么类型浏览器 header('cache-control:public'); header('content-type:application/octet-stream'); $encoded_filename=urlencode($name); $encoded_filename=str_replace("+","%20",$encoded_filename); //解决下载文件名乱码 if(preg_match("/MSIE/",$ua)||preg_match("/Trident/",$ua)){ header('Content-Disposition:attachment;filename="'.$encoded_filename.'"'); }elseif(preg_match("/Firefox/",$ua)){ header('Content-Disposition:attachment;filename*="utf8\'\''.$name.'"'); }elseif(preg_match("/Chrome/",$ua)){ header('Content-Disposition:attachment;filename="'.$encoded_filename.'"'); }else{ header('Content-Disposition:attachment;filename="'.$name.'"'); } //header('Content-Disposition:attachment;filename="'.$name.'"'); if($reload&&$ranges!=null){//使用续传 header('HTTP/1.1206PartialContent'); header('Accept-Ranges:bytes'); //剩余长度 header(sprintf('content-length:%u',$ranges['end']-$ranges['start'])); //range信息 header(sprintf('content-range:bytes%s-%s/%s',$ranges['start'],$ranges['end'],$file_size)); //file_put_contents('test.log',sprintf('content-length:%u',$ranges['end']-$ranges['start']),FILE_APPEND); //fp指针跳到断点位置 fseek($fp,sprintf('%u',$ranges['start'])); }else{ file_put_contents('test.log','2222',FILE_APPEND); header('HTTP/1.1200OK'); header('content-length:'.$file_size); } while(!feof($fp)){ //echofread($fp,round($this->_speed*1024,0)); //echofread($fp,$file_size); echofread($fp,4096); ob_flush(); } ($fp!=null)&&fclose($fp); }else{ return''; } } /**设置下载速度 *@paramint$speed */ publicfunctionsetSpeed($speed){ if(is_numeric($speed)&&$speed>16&&$speed<4096){ $this->_speed=$speed; } } /**获取headerrange信息 *@paramint$file_size文件大小 *@returnArray */ privatefunctiongetRange($file_size){ //file_put_contents('range.log',json_encode($_SERVER),FILE_APPEND); if(isset($_SERVER['HTTP_RANGE'])&&!empty($_SERVER['HTTP_RANGE'])){ $range=$_SERVER['HTTP_RANGE']; $range=preg_replace('/[\s|,].*/','',$range); $range=explode('-',substr($range,6)); if(count($range)<2){ $range[1]=$file_size; } $range=array_combine(array('start','end'),$range); if(empty($range['start'])){ $range['start']=0; } if(empty($range['end'])){ $range['end']=$file_size; } return$range; } returnnull; } } $obj=newFileDownload(); $obj->download('http://down.golaravel.com/laravel/laravel-master.zip','',true);
以上就是php实现断点续传大文件示例代码的详细内容,更多关于php断点续传大文件的资料请关注毛票票其它相关文章!