php 超大文件下载类 支持2g以上文件 支持断点续传
<?php
**
* <SPAN class=t_tag onclick=tagshow(event) href="tag.php?name=%CE%C4%BC%FE">文件</SPAN>传输,支持断点续传。
* 2g以上超大文件也有效
* @author MoXie
*/
class Transfer {
**
* 缓冲单元
*/
const BUFF_SIZE = 5120; / 1024 * 5
**
* 文件地址
* @var <String>
*/
private $filePath;
**
* 文件大小
* @var <String> php超大数字 <SPAN class=t_tag onclick=tagshow(event) href="tag.php?name=%D7%D6%B7%FB">字符</SPAN>串形式描述
*/
private $fileSize;
**
* 文件类型
* @var <String>
*/
private $mimeType;
**
* 请求区域(范围)
* @var <String>
*/
private $range;
**
* 是否写入日志
* @var <Boolean>
*/
private $isLog = false;
**
*
* @param <String> $filePath 文件路径
* @param <String> $mimeType 文件类型
* @param <String> $range 请求区域(范围)
*/
function __construct($filePath, $mimeType = null , $range = null) {
$this->filePath = $filePath;
$this->fileSize = sprintf('%u',filesize($filePath));
$this->mimeType = ($mimeType != null)?$mimeType:"application/octet-stream"; / bin
$this->range = trim($range);
}
**
* 获取文件区域
* @return <Map> {'start':long,'end':long} or null
*/
private function getRange() {
**
* Range: bytes=-128
* Range: bytes=-128
* Range: bytes=28-175,382-399,510-541,644-744,977-980
* Range: bytes=28-175n380
* type 1
* RANGE: bytes=1000-9999
* RANGE: bytes=2000-9999
* type 2
* RANGE: bytes=1000-1999
* RANGE: bytes=2000-2999
* RANGE: bytes=3000-3999
*/
if (!empty($this->range)) {
$range = preg_replace('/[s|,].*/','',$this->range);
$range = explode('-',substr($range,6));
if (count($range) < 2 ) {
$range[1] = $this->fileSize; / Range: bytes=-100
}
$range = array_combine(array('start','end'),$range);
if (empty($range['start'])) {
$range['start'] = 0;
}
if (!isset ($range['end']) || empty($range['end'])) {
$range['end'] = $this->fileSize;
}
return $range;
}
return null;
}
**
* 向客户端发送文件
*/
public function send() {
$fileHande = fopen($this->filePath, 'rb');
if ($fileHande) {
/ setting
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);
/ init
$lastModified = gmdate('D, d M Y H:i:s', filemtime($this->filePath)).' GMT';
$etag = sprintf('w/"%s:%s"',md5($lastModified),$this->fileSize);
$ranges = $this->getRange();
/ headers
header(sprintf('Last-Modified: %s',$lastModified));
header(sprintf('ETag: %s',$etag));
header(sprintf('Content-Type: %s',$this->mimeType));
$disposition = 'attachment';
if (strpos($this->mimeType,'image/') !== FALSE) {
$disposition = 'inline';
}
header(sprintf('Content-Disposition: %s; filename="%s"',$disposition,basename($this->filePath)));
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->fileSize));
/
fseek($fileHande, sprintf('%u',$ranges['start']));
}else {
header("HTTP/1.1 200 OK");
header(sprintf('Content-Length: %s',$this->fileSize));
}
/ read file
$lastSize = 0;
while(!feof($fileHande) && !connection_aborted()) {
$lastSize = sprintf("%u", bcsub($this->fileSize,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);
}
}
**
* 设置记录
* @param <Boolean> $isLog 是否记录
*/
public function setIsLog($isLog = true) {
$this->isLog = $isLog;
}
**
* 记录
* @param <String> $msg 记录信息
*/
private function log($msg) {
try {
$handle = fopen('transfer_log.txt', 'a');
fwrite($handle, sprintf('%s : %s'."<SPAN class=t_tag onclick=tagshow(event) href=\"tag.php?name=php\">php</SPAN>_EOL",date('Y-m-d H:i:s'),$msg));
fclose($handle);
}catch(Exception $e) {
/ null;
}
}
}
date_default_timezone_set('Asia/Shanghai');
error_reporting(E_STRICT);
function errorHandler($errno, $errstr, $errfile, $errline) {
echo '<p>error:',$errstr,'</p>';
exit();
}
set_error_handler('errorHandler');
define('IS_DEbug',true);
/
/
$filePath = '/Movie/The.Hurt.Locker.2008.x264.AC3-WAF.mkv';
$mimeType = 'audio/x-matroska';
$range = isset($_SERVER['HTTP_RANGE'])?$_SERVER['HTTP_RANGE']:null;
if (IS_DEbug) {
/ $range = "bytes=1000-1999n2000";
/ $range = "bytes=1000-1999,2000";
/ $range = "bytes=1000-1999,-2000";
/ $range = "bytes=1000-1999,2000-2999";
}
set_time_limit(0);
$transfer = new Transfer($filePath,$mimeType,$range);
if (IS_DEbug) {
$transfer->setIsLog(true);
}
$transfer->send();
评论
TwikooValine