php 超大文件下载类 支持2g以上文件 支持断点续传
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
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
040 * @param
041 * @param
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
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)
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
146 */
147 public function setIsLog($isLog = true) {
148 $this->isLog = $isLog;
149 }
150 /**
151 * 记录
152 * @param
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 ?>

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。
