【www.gdgbn.com--网页编辑器下载】
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) < 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
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 ?>