Hi,为确保您的账号安全,请大家修改登陆密码为包含大小写字母、标点、数字的复合密码,不要使用过于简单的登陆密码。
您当前的位置:首页 :: PHP

PHP实现大文件断点下载

时间:2014-04-10 15:57:05  来源:  作者:

参照网上的朋友发出来的代码。如果出现bcsub()出现,那就要重新配置一下 bcmath这个库类就可以正确运行了,代码如下

<?
/**
 * PHP支持断点下载大文件类
 * @author jorsh 20140410
 * @var [type]
 */
class SendBigFile{
    //缓存单元
    const BUFF_SIZE = 5120; //1024*5
    //文件地址 var string
    private $F_path;
    //文件大小 var string 可支持超级大的数字比如大于2G的文件
    private $F_size;
    //文件类型 var string
    private $F_type;
    //请求范围 var string
    private $range;
    //是否写入日志 var boolean
    private $isLog = false;

    //构造函数,初始化变量
    function __construct($filePath,$fileType=null,$range=null){
        $this->F_path = $filePath;
        $this->F_size = sprintf('%u',filesize($filePath));
        $this->F_type = ($fileType!=null)?$fileType:'application/octet-stream';
        $this->range  = $range;
    }

    /**
     * 取得文件区域
     * @return map {'start':long,'end':long} or null
     */
    private function getRange(){
        if($this->range){
            $range = preg_replace('/[s|,].*/', '', $this->range);
            $range = explode('-', substr($range, 6));
            if(count($range)<2) $range[1] = $this->F_size;
            $range = array_combine(array('start','end'),$range);
            if(empty($rang['start'])) $rang['start'] = 0;
            if(empty($rang['end']) || !isset($rang['end'])) $rang['end'] = $this->F_size;
            return $rang;
        }
        return null;
    }

    /**
     * 设置是否记录
     * @param boolean $isLog [description]
     */
    public function setIsLog($isLog=true){
        $this->isLog = $isLog;
    }

    /**
     * 记录信息
     * @param  [type] $msg [description]
     * @return [type]      [description]
     */
    private function log($msg){
        try {
            $handle = fopen('user_download_log.txt', 'a');
            fwrite($handle, sprintf('%s : %s'.PHP_EOL,date('Y-m-d H:i:s'),$msg));
            fclose($handle);
        } catch (Exception $e) {
            
        }
    }
    /**
     * 向客户端发送文件
     */
    public function send(){
        $fileHande = fopen($this->F_path, 'rb');
        if($fileHande){
            ob_end_clean(); //clean cache
            ob_start();
            ini_set('output_buffering', 'Off');
            ini_set('zlib.output_compression','Off');
            $magicQuotes = get_magic_quotes_gpc();
            set_magic_quotes_runtime(0);
            $lastModified = gmdate('D, d M Y H:i:s', filemtime($this->F_path)).'GMT';
            $etag = sprintf('W/"%s:%s"',md5($lastModified),$this->F_size);
            $ranges = $this->getRange();

            header(sprintf('Last-Modified: $s',$lastModified));
            header(sprintf('ETag: %s',$etag));
            header(sprintf('Content-Type: %s',$this->F_type));
            $disposition = 'attachment';
            if(strpos($this->F_type, 'image/') !== FALSE) $disposition = 'inline';
            header(sprintf('Content-Disposition: %s;filename="%s"',$disposition,basename($this->F_path)));
            if($ranges!=null){
                if($this->isLog){
                    $this->log(json_encode($ranges).' '.$_SERVER['HTTP_RANGE']);
                }
                header('HTTP/1.1 206 Partial Content');
                header('Accept-Ranges: bytes');
                header(sprintf('Content-Length: %u',$ranges['end'] - $ranges['start']));
                header(sprintf('Content-Range: bytes %s-%s/%s',$ranges['start'],$ranges['end'],$this->F_size));
                fseek($fileHande, sprintf('%u', $ranges['start']));
            }else{
                header('HTTP/1.1 200 OK');
                header(sprintf('Content-Length: %s', $this->F_size));
            }
            //read file
            $lastSize =0;
            while (!feof($fileHande) && !connection_aborted()) {
                $lastSize = sprintf('%u',bcsub($this->F_size, sprintf('%u',ftell($fileHande))));
                if(bccomp($lastSize, self::BUFF_SIZE)>0) $lastSize = self::BUFF_SIZE;
                echo fread($fileHande, $lastSize);
                flush();
                ob_flush();
            }
            set_magic_quotes_runtime($magicQuotes);
            ob_end_flush();
        }
        if($fileHande!=null){
            fclose($fileHande);
        }
    }
}
$filename = isset($_GET['f'])?$_GET['f']:'';
if(!$filename) exit();
$filename = str_replace('/', '', $filename);
$filepath = '/home/download/'.$filename;
$range = isset($_SERVER['HTTP_RANGE'])?$_SERVER['HTTP_RANGE']:null;
if(file_exists($filepath)){
    set_time_limit(0);
    $sendFile = new SendBigFile($filepath, null, $range);
    //$sendFile->setIsLog(true);
    $sendFile->send();
}
?>

 

举报
收藏0次 / 评论1
评论(1)
还可以输入 2000 个字符
还可以输入 2000 个字符
取消回复
举报×

还可以输入 264 字符

收藏(0)×