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 无限级缓存的类的扩展
Mar 16 PHP
PHP 程序员的调试技术小结
Nov 15 PHP
mysql总结之explain
Feb 27 PHP
解析PHP正则提取或替换img标记属性
Jun 26 PHP
PHP对接微信公众平台消息接口开发流程教程
Mar 25 PHP
PHP命令行脚本接收传入参数的三种方式
Aug 20 PHP
列举PHP的Yii 2框架的开发优势
Jul 03 PHP
PHP随机数 C扩展随机数
May 04 PHP
php 三元运算符实例详细介绍
Dec 15 PHP
phpMyAdmin无法登陆的解决方法
Apr 27 PHP
PHP封装curl的调用接口及常用函数详解
May 31 PHP
在Ubuntu 18.04上安装PHP 7.3 7.2和7.0的方法
Apr 09 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部分常见问题总结
2006/10/09 PHP
PHP 的 __FILE__ 常量
2007/01/15 PHP
PHP用SAX解析XML的实现代码与问题分析
2011/08/22 PHP
解析php常用image图像函数集
2013/06/24 PHP
完美实现wordpress禁止文章修订和自动保存的方法
2014/11/03 PHP
php+flash+jQuery多图片上传源码分享
2020/07/27 PHP
利用PHP命令行模式采集股票趋势信息
2016/08/09 PHP
关于PHP定时发送服务的解决办法
2017/04/23 PHP
PHP实现基本留言板功能原理与步骤详解
2020/03/26 PHP
基于JQuery的类似新浪微博展示信息效果的代码
2012/07/23 Javascript
web的各种前端打印方法之jquery打印插件PrintArea实现网页打印
2013/01/09 Javascript
Javascript与jQuery方法的隐藏与显示
2015/01/19 Javascript
javascript定时器完整实例
2015/02/10 Javascript
javascript使用shift+click实现选择和反选checkbox的方法
2015/05/04 Javascript
javascript实现获取字符串hash值
2015/05/10 Javascript
javascript中使用未定义变量或值的情况分析
2016/07/19 Javascript
详解jQuery中的事件
2016/12/14 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
zTree树形菜单交互选项卡效果的实现方法
2017/12/25 Javascript
Angular4学习教程之DOM属性绑定详解
2018/01/04 Javascript
基于JavaScript实现抽奖系统
2018/01/16 Javascript
JS编写兼容IE6,7,8浏览器无缝自动轮播
2018/10/12 Javascript
详解vue中v-bind:style效果的自定义指令
2020/01/21 Javascript
[01:14]2014DOTA2展望TI 剑指西雅图newbee战队专访
2014/06/30 DOTA
pandas实现DataFrame显示最大行列,不省略显示实例
2019/12/26 Python
opencv 实现特定颜色线条提取与定位操作
2020/06/02 Python
python Matplotlib数据可视化(2):详解三大容器对象与常用设置
2020/09/30 Python
详解Python中openpyxl模块基本用法
2021/02/23 Python
IRO美国官网:法国服装品牌
2018/03/06 全球购物
课外访万家心得体会
2014/09/03 职场文书
冬季作息时间调整通知
2015/04/24 职场文书
辅导员学期工作总结
2015/08/14 职场文书
2016年基层党组织创先争优承诺书
2016/03/25 职场文书
python如何做代码性能分析
2021/04/26 Python
36个正则表达式(开发效率提高80%)
2021/11/17 Javascript
Pandas数据结构之Series的使用
2022/03/31 Python