<? Php Tutorial
002 /**
003 * <SPAN class = t_tag onclick = tagshow (event) href = "tag. php? Name = % CE % C4 % BC % FE "> File </SPAN> Transmission. Resumable data transfer is supported.
004*2 GB or more ultra-large files are also valid
005 * @ author MoXie
006 */
007 class Transfer {
008 /**
009 * buffer unit
010 */
011 const BUFF_SIZE = 5120; // 1024*5
012 /**
013 * file address
014 * @ var <String>
015 */
016 private $ filePath;
017 /**
018 * file size
019 * @ var <String> Php oversized number <SPAN class = t_tag onclick = tagshow (event) href = "tag. php? Name = % D7 % D6 % B7 % FB "> Character </SPAN> string description
020 */
021 private $ fileSize;
022 /**
023 * file type
024 * @ var <String>
025 */
026 private $ mimeType;
027 /**
028 * Request region (range)
029 * @ var <String>
030 */
031 private $ range;
032 /**
033 * whether to write logs
034 * @ var <Boolean>
035 */
036 private $ isLog = false;
037 /**
038 *
039 * @ param <String> $ filePath file path
040 * @ param <String> $ mimeType file type
041 * @ param <String> $ range request region (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 * obtain the file region
051 * @ return <Map> {'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 * send a file to the client
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 maid ();
135}
136 set_magic_quotes_runtime ($ magicQuotes );
137 ob_end_flush ();
138}
139 if ($ fileHande! = Null ){
140 fclose ($ fileHande );
141}
142}
143 /**
144 * Set Records
145 * @ param <Boolean> $ whether isLog is recorded
146 */
147 public function setIsLog ($ isLog = true ){
148 $ this-> isLog = $ isLog;
149}
150 /**
151 * Records
152 * @ param <String> $ msg record information
153 */
154 private function log ($ msg ){
155 try {
156 $ handle = fopen('transfer_log.txt ', 'A ');
157 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 ));
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 '<p> error:', $ errstr, '</p> ';
168 exit ();
169}
170 set_error_handler ('errorhandler ');
171 define ('is _ debug', true );
172
173 //
174 //
175 $ filePath = '/Movie/vie ';
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 ";
181 // $ range = "bytes = 1000-1999,-2000 ";
182 // $ range = "bytes = 1000-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?>