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应用程序来获取Web服务器的状态信息
Oct 09 PHP
用 PHP5 轻松解析 XML
Dec 04 PHP
php 小乘法表实现代码
Jul 16 PHP
Search File Contents PHP 搜索目录文本内容的代码
Feb 21 PHP
在Linux系统下一键重新安装WordPress的脚本示例
Jun 30 PHP
PHP7匿名类用法分析
Sep 26 PHP
浅谈PHP中的错误处理和异常处理
Feb 04 PHP
PHP常用算法和数据结构示例(必看篇)
Mar 15 PHP
PHP 网站修改默认访问文件的nginx配置
May 27 PHP
Ajax+PHP实现的分类列表框功能示例
Feb 11 PHP
php字符串截取函数mb_substr用法实例分析
Jun 25 PHP
Laravel框架下的Contracts契约详解
Mar 17 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下10件你也许并不了解的事情
2008/09/11 PHP
腾讯QQ php程序员面试题目整理
2010/06/08 PHP
php 地区分类排序算法
2013/07/01 PHP
php替换字符串中间字符为省略号的方法
2015/05/04 PHP
PHP连接Nginx服务器并解析Nginx日志的方法
2015/08/16 PHP
PHP实现二叉树的深度优先与广度优先遍历方法
2015/09/28 PHP
js树形控件脚本代码
2008/07/24 Javascript
基于jquery的inputlimiter 实现字数限制功能
2010/05/30 Javascript
javascript使用activex控件的代码
2011/01/27 Javascript
纯Javascript实现Windows 8 Metro风格实现
2013/10/15 Javascript
JQuery处理json与ajax返回JSON实例代码
2014/01/03 Javascript
jQuery自定义事件的简单实现代码
2014/01/27 Javascript
node.js中的socket.io的广播消息
2014/12/15 Javascript
jQuery滚动加载图片实现原理
2015/12/14 Javascript
jQuery实现的弹幕效果完整实例
2017/09/06 jQuery
JavaScript面向对象精要(下部)
2017/09/12 Javascript
解决Vue在封装了Axios后手动刷新页面拦截器无效的问题
2018/11/08 Javascript
vue组件从开发到发布的实现步骤
2018/11/11 Javascript
深入浅析JavaScript中的in关键字和for-in循环
2020/04/20 Javascript
vue打包npm run build时候界面报错的解决
2020/08/13 Javascript
vue中h5端打开app(判断是安卓还是苹果)
2021/02/26 Vue.js
Python的Django框架中的select_related函数对QuerySet 查询的优化
2015/04/01 Python
78行Python代码实现现微信撤回消息功能
2018/07/26 Python
wxPython实现绘图小例子
2019/11/19 Python
Python QT组件库qtwidgets的使用
2020/11/02 Python
HTML5中的postMessage API基本使用教程
2016/05/20 HTML / CSS
利用HTML5 Canvas API绘制矩形的超级攻略
2016/03/21 HTML / CSS
茱莉蔻美国官网:Jurlique美国
2020/11/24 全球购物
应届本科生推荐信范文
2013/12/25 职场文书
电脑售后服务承诺书
2014/03/27 职场文书
2014年母亲节演讲稿范文
2014/05/07 职场文书
小学生个人先进事迹材料
2014/05/08 职场文书
2014年秋季开学演讲稿
2014/05/24 职场文书
个人对照检查剖析材料
2014/10/13 职场文书
优秀团员自我评价
2015/03/10 职场文书
汤姆叔叔的小屋读书笔记
2015/06/30 职场文书