• 技术文章 >php教程 >php手册

    php 超大文件下载类 支持2g以上文件 支持断点续传

    2016-06-13 11:23:23原创899

    002 /**

    003 * 文件传输,支持断点续传。

    004 * 2g以上超大文件也有效

    005 * @author MoXie

    006 */

    007 class Transfer {

    008 /**

    009 * 缓冲单元

    010 */

    011 const BUFF_SIZE = 5120; // 1024 * 5

    012 /**

    013 * 文件地址

    014 * @var

    015 */

    016 private $filePath;

    017 /**

    018 * 文件大小

    019 * @var Php超大数字 字符串形式描述

    020 */

    021 private $fileSize;

    022 /**

    023 * 文件类型

    024 * @var

    025 */

    026 private $mimeType;

    027 /**

    028 * 请求区域(范围)

    029 * @var

    030 */

    031 private $range;

    032 /**

    033 * 是否写入日志

    034 * @var

    035 */

    036 private $isLog = false;

    037 /**

    038 *

    039 * @param $filePath 文件路径

    040 * @param $mimeType 文件类型

    041 * @param $range 请求区域(范围)

    042 */

    043 function __construct($filePath, $mimeType = null , $range = null) {

    044 $this->filePath = $filePath;

    045 $this->fileSize = sprintf('%u',filesize($filePath));

    046 $this->mimeType = ($mimeType != null)?$mimeType:"application/octet-stream"; // bin

    047 $this->range = trim($range);

    048 }

    049 /**

    050 * 获取文件区域

    051 * @return {'start':long,'end':long} or null

    052 */

    053 private function getRange() {

    054 /**

    055 * Range: bytes=-128

    056 * Range: bytes=-128

    057 * Range: bytes=28-175,382-399,510-541,644-744,977-980

    058 * Range: bytes=28-175n380

    059 * type 1

    060 * RANGE: bytes=1000-9999

    061 * RANGE: bytes=2000-9999

    062 * type 2

    063 * RANGE: bytes=1000-1999

    064 * RANGE: bytes=2000-2999

    065 * RANGE: bytes=3000-3999

    066 */

    067 if (!empty($this->range)) {

    068 $range = preg_replace('/[s|,].*/','',$this->range);

    069 $range = explode('-',substr($range,6));

    070 if (count($range) < 2 ) {

    071 $range[1] = $this->fileSize; // Range: bytes=-100

    072 }

    073 $range = array_combine(array('start','end'),$range);

    074 if (empty($range['start'])) {

    075 $range['start'] = 0;

    076 }

    077 if (!isset ($range['end']) || empty($range['end'])) {

    078 $range['end'] = $this->fileSize;

    079 }

    080 return $range;

    081 }

    082 return null;

    083 }

    084 /**

    085 * 向客户端发送文件

    086 */

    087 public function send() {

    088 $fileHande = fopen($this->filePath, 'rb');

    089 if ($fileHande) {

    090 // setting

    091 ob_end_clean();// clean cache

    092 ob_start();

    093 ini_set('output_buffering', 'Off');

    094 ini_set('zlib.output_compression', 'Off');

    095 $magicQuotes = get_magic_quotes_gpc();

    096 set_magic_quotes_runtime(0);

    097 // init

    098 $lastModified = gmdate('D, d M Y H:i:s', filemtime($this->filePath)).' GMT';

    099 $etag = sprintf('w/"%s:%s"',md5($lastModified),$this->fileSize);

    100 $ranges = $this->getRange();

    101 // headers

    102 header(sprintf('Last-Modified: %s',$lastModified));

    103 header(sprintf('ETag: %s',$etag));

    104 header(sprintf('Content-Type: %s',$this->mimeType));

    105 $disposition = 'attachment';

    106 if (strpos($this->mimeType,'image/') !== FALSE) {

    107 $disposition = 'inline';

    108 }

    109 header(sprintf('Content-Disposition: %s; filename="%s"',$disposition,basename($this->filePath)));

    110

    111 if ($ranges != null) {

    112 if ($this->isLog) {

    113 $this->log(json_encode($ranges).' '.$_SERVER['HTTP_RANGE']);

    114 }

    115 header('HTTP/1.1 206 Partial Content');

    116 header('Accept-Ranges: bytes');

    117 header(sprintf('Content-Length: %u',$ranges['end'] - $ranges['start']));

    118 header(sprintf('Content-Range: bytes %s-%s/%s', $ranges['start'], $ranges['end'],$this->fileSize));

    119 //

    120 fseek($fileHande, sprintf('%u',$ranges['start']));

    121 }else {

    122 header("HTTP/1.1 200 OK");

    123 header(sprintf('Content-Length: %s',$this->fileSize));

    124 }

    125 // read file

    126 $lastSize = 0;

    127 while(!feof($fileHande) && !connection_aborted()) {

    128 $lastSize = sprintf("%u", bcsub($this->fileSize,sprintf("%u",ftell($fileHande))));

    129 if (bccomp($lastSize,self::BUFF_SIZE) > 0) {

    130 $lastSize = self::BUFF_SIZE;

    131 }

    132 echo fread($fileHande, $lastSize);

    133 flush();

    134 ob_flush();

    135 }

    136 set_magic_quotes_runtime($magicQuotes);

    137 ob_end_flush();

    138 }

    139 if ($fileHande != null) {

    140 fclose($fileHande);

    141 }

    142 }

    143 /**

    144 * 设置记录

    145 * @param $isLog 是否记录

    146 */

    147 public function setIsLog($isLog = true) {

    148 $this->isLog = $isLog;

    149 }

    150 /**

    151 * 记录

    152 * @param $msg 记录信息

    153 */

    154 private function log($msg) {

    155 try {

    156 $handle = fopen('transfer_log.txt', 'a');

    157 fwrite($handle, sprintf('%s : %s'.PHP_EOL,date('Y-m-d H:i:s'),$msg));

    158 fclose($handle);

    159 }catch(Exception $e) {

    160 // null;

    161 }

    162 }

    163 }

    164 date_default_timezone_set('Asia/Shanghai');

    165 error_reporting(E_STRICT);

    166 function errorHandler($errno, $errstr, $errfile, $errline) {

    167 echo '

    error:',$errstr,'

    ';

    168 exit();

    169 }

    170 set_error_handler('errorHandler');

    171 define('IS_DEBUG',true);

    172

    173 //

    174 //

    175 $filePath = '/Movie/The.Hurt.Locker.2008.x264.AC3-WAF.mkv';

    176 $mimeType = 'audio/x-matroska';

    177 $range = isset($_SERVER['HTTP_RANGE'])?$_SERVER['HTTP_RANGE']:null;

    178 if (IS_DEBUG) {

    179 // $range = "bytes=1000-1999n2000";

    180 // $range = "bytes=1000-1999,2000";

    181 // $range = "bytes=1000-1999,-2000";

    182 // $range = "bytes=1000-1999,2000-2999";

    183 }

    184 set_time_limit(0);

    185 $transfer = new Transfer($filePath,$mimeType,$range);

    186 if (IS_DEBUG) {

    187 $transfer->setIsLog(true);

    188 }

    189 $transfer->send();

    190 ?>

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:PHP5 中的常量 PHP 面向对象 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • smarty模板引擎从php中获取数据的方法,smarty模板• php利用新浪接口查询ip获取地理位置• PHP中 ADOdb 类库介绍(下)• 创建配置文件 用PHP写出自己的BLOG系统 2• 我的论坛源代码(五)
    1/1

    PHP中文网