zoukankan      html  css  js  c++  java
  • php实现断点下载

    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:文件总大小


    <?php
    /** php下载类,支持断点续传
    *   Date:   2014-05-15
    *   Author: 郝翔
    *   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){
            ob_start(); 
            $file=iconv('UTF-8','GB2312',$file);  //否则不能判断中文的文件名
            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)){
                    set_time_limit(0);  //设置脚本最大执行时间 0 表示没有限制  
                    echo fread($fp, round($this->_speed*1024,0)); //读取文件(可安全用于二进制文件),从文件指针 handle 读取最多 length 个字节  
                    flush();//该函数将当前为止程序的所有输出发送到用户的浏览器。  
                    ob_flush();//flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此,必须同时使用 ob_flush()  
                }
                
                ($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
    
    ?>
    
    
    
    

    测试使用:

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

    下载的文件默认保存在当前文件夹下


    如何使用:

    <body>
    <h1>
    	<a href="demo.php">断点续传测试</a>
    </h1>
    </body>


    <?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';
    }
    
    ?>


  • 相关阅读:
    Cocos2dx-demo演示项目:Part2
    利用Python抓取亚马逊评论列表数据
    Cocos2dx-demo演示项目:Part1
    正则表达式匹配原理
    js正则函数中test和match的区别
    【别人家的孩子系列之】浅析正则表达式—(原理篇)
    JS 获取浏览器窗口大小
    javascript的insertBefore、insertAfter和appendChild简单介绍
    javascript 限制字符串字数换行 带BUG
    一行一行分析JQ源码学习笔记-06
  • 原文地址:https://www.cnblogs.com/mr-amazing/p/3723027.html
Copyright © 2011-2022 走看看