php实现的支持断点续传的文件下载类


Posted in PHP onSeptember 23, 2014

本文实例讲述了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下载类,支持断点续传 
*  Date:  2013-06-30 
*  Author: test 
*  Ver:  1.0 
* 
*  Func: 
*  download: 下载文件 
*  setSpeed: 设置下载速度 
*  getRange: 获取header中Range 
*/ 
 
class FileDownload{ // class start 
 
  private $_speed = 512;  // 下载速度 
 
  /** 下载 
  * @param String $file  要下载的文件路径 
  * @param String $name  文件名称,为空则与下载的文件名称一样 
  * @param boolean $reload 是否开启断点续传 
  */ 
  public function download($file, $name='', $reload=false){ 
    if(file_exists($file)){ 
      if($name==''){ 
        $name = basename($file); 
      } 
 
      $fp = fopen($file, 'rb'); 
      $file_size = filesize($file); 
      $ranges = $this->getRange($file_size); 
 
      header('cache-control:public'); 
      header('content-type:application/octet-stream'); 
      header('content-disposition:attachment; filename='.$name); 
 
      if($reload && $ranges!=null){ // 使用续传 
        header('HTTP/1.1 206 Partial Content'); 
        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)); 
         
        // fp指针跳到断点位置 
        fseek($fp, sprintf('%u', $ranges['start'])); 
      }else{ 
        header('HTTP/1.1 200 OK'); 
        header('content-length:'.$file_size); 
      } 
 
      while(!feof($fp)){ 
        echo fread($fp, round($this->_speed*1024,0)); 
        ob_flush(); 
        //sleep(1); // 用于测试,减慢下载速度 
      } 
 
      ($fp!=null) && fclose($fp); 
 
    }else{ 
      return ''; 
    } 
  } 
 
  /** 设置下载速度 
  * @param int $speed 
  */ 
  public function setSpeed($speed){ 
    if(is_numeric($speed) && $speed>16 && $speed<4096){ 
      $this->_speed = $speed; 
    } 
  } 
 
  /** 获取header range信息 
  * @param int  $file_size 文件大小 
  * @return Array 
  */ 
  private function getRange($file_size){ 
    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; 
    } 
    return null; 
  } 
} // class end 
 
?>

demo示例代码如下:

<?php 
require('FileDownload.class.php'); 
$file = 'book.zip'; 
$name = time().'.zip'; 
$obj = new FileDownload(); 
$flag = $obj->download($file, $name); 
//$flag = $obj->download($file, $name, true); // 断点续传 
 
if(!$flag){ 
  echo 'file not exists'; 
} 
?>

断点续传测试方法:

使用linux wget命令去测试下载, wget -c -O file http://xxx

1.先关闭断点续传

$flag = $obj->download($file, $name);
test@ubuntu:~/Downloads$ wget -O test.rar http://demo.test.com/demo.php 
--2013-06-30 16:52:44-- http://demo.test.com/demo.php 
正在解析主机 demo.test.com... 127.0.0.1 
正在连接 demo.test.com|127.0.0.1|:80... 已连接。 
已发出 HTTP 请求,正在等待回应... 200 OK 
长度: 10445120 (10.0M) [application/octet-stream] 
正在保存至: “test.rar” 
 
30% [============================>                                   ] 3,146,580  513K/s 估时 14s 
^C 
test@ubuntu:~/Downloads$ wget -c -O test.rar http://demo.test.com/demo.php 
--2013-06-30 16:52:57-- http://demo.test.com/demo.php 
正在解析主机 demo.test.com... 127.0.0.1 
正在连接 demo.test.com|127.0.0.1|:80... 已连接。 
已发出 HTTP 请求,正在等待回应... 200 OK 
长度: 10445120 (10.0M) [application/octet-stream] 
正在保存至: “test.rar” 
30% [============================>                                   ] 3,146,580  515K/s 估时 14s 
^C

可以看到,wget -c不能断点续传 

2.开启断点续传

$flag = $obj->download($file, $name, true);
test@ubuntu:~/Downloads$ wget -O test.rar http://demo.test.com/demo.php 
--2013-06-30 16:53:19-- http://demo.test.com/demo.php 
正在解析主机 demo.test.com... 127.0.0.1 
正在连接 demo.test.com|127.0.0.1|:80... 已连接。 
已发出 HTTP 请求,正在等待回应... 200 OK 
长度: 10445120 (10.0M) [application/octet-stream] 
正在保存至: “test.rar” 
 
20% [==================>                                        ] 2,097,720  516K/s 估时 16s 
^C 
test@ubuntu:~/Downloads$ wget -c -O test.rar http://demo.test.com/demo.php 
--2013-06-30 16:53:31-- http://demo.test.com/demo.php 
正在解析主机 demo.test.com... 127.0.0.1 
正在连接 demo.test.com|127.0.0.1|:80... 已连接。 
已发出 HTTP 请求,正在等待回应... 206 Partial Content 
长度: 10445121 (10.0M),7822971 (7.5M) 字节剩余 [application/octet-stream] 
正在保存至: “test.rar” 
 
100%[++++++++++++++++++++++++=========================================================================>] 10,445,121  543K/s  花时 14s   
 
2013-06-30 16:53:45 (543 KB/s) - 已保存 “test.rar” [10445121/10445121])

可以看到会从断点的位置(%20)开始下载。 

本文实例完整源码可点击此处本站下载。

相信本文所述对大家的PHP程序设计有一定的借鉴价值。

PHP 相关文章推荐
PHP Memcached应用实现代码
Feb 08 PHP
php中定义网站根目录的常用方法
Aug 08 PHP
批量修改RAR文件注释的php代码
Nov 20 PHP
php模拟socket一次连接,多次发送数据的实现代码
Jul 26 PHP
使用php检测用户当前使用的浏览器是否为IE浏览器
Dec 03 PHP
php中hashtable实现示例分享
Feb 13 PHP
ThinkPHP访问不存在的模块跳转到404页面的方法
Jun 19 PHP
PHP队列用法实例
Nov 05 PHP
php文件上传简单实现方法
Jan 24 PHP
利用PHP命令行模式采集股票趋势信息
Aug 09 PHP
PHP实现表单提交时去除斜杠的方法
Dec 26 PHP
PHP RabbitMQ消息列队
May 11 PHP
php实现的click captcha点击验证码类实例
Sep 23 #PHP
PHP实现自动登入google play下载app report的方法
Sep 23 #PHP
PHP遍历文件夹与文件类及处理类用法实例
Sep 23 #PHP
PHP邮件发送类PHPMailer用法实例详解
Sep 22 #PHP
php实现的CSS更新类实例
Sep 22 #PHP
php的XML文件解释类应用实例
Sep 22 #PHP
php实现的返回数据格式化类实例
Sep 22 #PHP
You might like
PHP调用C#开发的dll类库方法
2014/07/28 PHP
浅析PHP类的反射来实现依赖注入过程
2018/02/06 PHP
详解php中curl返回false的解决办法
2019/03/18 PHP
PHP常用字符串输出方法分析(echo,print,printf及sprintf)
2021/03/09 PHP
用js计算页面执行时间的函数
2006/12/07 Javascript
原来Jquery.load的方法可以一直load下去
2011/03/28 Javascript
jQuery获取节点和子节点文本的方法
2014/07/22 Javascript
Node.js中HTTP模块与事件模块详解
2014/11/14 Javascript
JQuery分屏指示器图片轮换效果实例
2015/05/21 Javascript
详解JavaScript中的表单验证
2015/06/16 Javascript
js简单实现标签云效果实例
2015/08/06 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
prototype.js常用函数详解
2016/06/18 Javascript
深入理解bootstrap框架之入门准备
2016/10/09 Javascript
微信小程序 扎金花简单实例
2017/02/21 Javascript
Nodejs--post的公式详解
2017/04/29 NodeJs
基于node.js express mvc轻量级框架实践
2017/09/14 Javascript
VUE中的无限循环代码解析
2017/09/22 Javascript
python 解析XML python模块xml.dom解析xml实例代码
2014/02/07 Python
python利用正则表达式提取字符串
2016/12/08 Python
Python用imghdr模块识别图片格式实例解析
2018/01/11 Python
Python3.6连接Oracle数据库的方法详解
2018/05/18 Python
详解django+django-celery+celery的整合实战
2019/03/19 Python
Python实现的删除重复文件或图片功能示例【去重】
2019/04/23 Python
python计算无向图节点度的实例代码
2019/11/22 Python
HTML5制作酷炫音频播放器插件图文教程
2014/12/30 HTML / CSS
Rhone官方网站:男士运动服装、健身服装和高级运动服
2019/05/01 全球购物
波兰快递服务:Globkurier.pl
2019/11/08 全球购物
求职信格式范本
2013/11/15 职场文书
投标保密承诺书
2014/05/19 职场文书
大学生创业事迹材料
2014/12/30 职场文书
原生Js 实现的简单无缝滚动轮播图的示例代码
2021/05/10 Javascript
只需要100行Python代码就可以实现的贪吃蛇小游戏
2021/05/27 Python
Java SSH 秘钥连接mysql数据库的方法
2021/06/28 Java/Android
经典《舰娘》游改全新动画预告 预定11月开播
2022/04/01 日漫
css中:last-child不生效的解决方法
2022/08/05 HTML / CSS