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断点续传大文件的资料请关注毛票票其它相关文章!