MediaWiki
REL1_20
|
00001 <?php 00026 class StreamFile { 00027 const READY_STREAM = 1; 00028 const NOT_MODIFIED = 2; 00029 00040 public static function stream( $fname, $headers = array(), $sendErrors = true ) { 00041 wfProfileIn( __METHOD__ ); 00042 00043 if ( FileBackend::isStoragePath( $fname ) ) { // sanity 00044 throw new MWException( __FUNCTION__ . " given storage path '$fname'." ); 00045 } 00046 00047 wfSuppressWarnings(); 00048 $stat = stat( $fname ); 00049 wfRestoreWarnings(); 00050 00051 $res = self::prepareForStream( $fname, $stat, $headers, $sendErrors ); 00052 if ( $res == self::NOT_MODIFIED ) { 00053 $ok = true; // use client cache 00054 } elseif ( $res == self::READY_STREAM ) { 00055 wfProfileIn( __METHOD__ . '-send' ); 00056 $ok = readfile( $fname ); 00057 wfProfileOut( __METHOD__ . '-send' ); 00058 } else { 00059 $ok = false; // failed 00060 } 00061 00062 wfProfileOut( __METHOD__ ); 00063 return $ok; 00064 } 00065 00079 public static function prepareForStream( 00080 $path, $info, $headers = array(), $sendErrors = true 00081 ) { 00082 if ( !is_array( $info ) ) { 00083 if ( $sendErrors ) { 00084 header( 'HTTP/1.0 404 Not Found' ); 00085 header( 'Cache-Control: no-cache' ); 00086 header( 'Content-Type: text/html; charset=utf-8' ); 00087 $encFile = htmlspecialchars( $path ); 00088 $encScript = htmlspecialchars( $_SERVER['SCRIPT_NAME'] ); 00089 echo "<html><body> 00090 <h1>File not found</h1> 00091 <p>Although this PHP script ($encScript) exists, the file requested for output 00092 ($encFile) does not.</p> 00093 </body></html> 00094 "; 00095 } 00096 return false; 00097 } 00098 00099 // Sent Last-Modified HTTP header for client-side caching 00100 header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $info['mtime'] ) ); 00101 00102 // Cancel output buffering and gzipping if set 00103 wfResetOutputBuffers(); 00104 00105 $type = self::contentTypeFromPath( $path ); 00106 if ( $type && $type != 'unknown/unknown' ) { 00107 header( "Content-type: $type" ); 00108 } else { 00109 // Send a content type which is not known to Internet Explorer, to 00110 // avoid triggering IE's content type detection. Sending a standard 00111 // unknown content type here essentially gives IE license to apply 00112 // whatever content type it likes. 00113 header( 'Content-type: application/x-wiki' ); 00114 } 00115 00116 // Don't stream it out as text/html if there was a PHP error 00117 if ( headers_sent() ) { 00118 echo "Headers already sent, terminating.\n"; 00119 return false; 00120 } 00121 00122 // Send additional headers 00123 foreach ( $headers as $header ) { 00124 header( $header ); 00125 } 00126 00127 // Don't send if client has up to date cache 00128 if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { 00129 $modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); 00130 if ( wfTimestamp( TS_UNIX, $info['mtime'] ) <= strtotime( $modsince ) ) { 00131 ini_set( 'zlib.output_compression', 0 ); 00132 header( "HTTP/1.0 304 Not Modified" ); 00133 return self::NOT_MODIFIED; // ok 00134 } 00135 } 00136 00137 header( 'Content-Length: ' . $info['size'] ); 00138 00139 return self::READY_STREAM; // ok 00140 } 00141 00149 public static function contentTypeFromPath( $filename, $safe = true ) { 00150 global $wgTrivialMimeDetection; 00151 00152 $ext = strrchr( $filename, '.' ); 00153 $ext = $ext === false ? '' : strtolower( substr( $ext, 1 ) ); 00154 00155 # trivial detection by file extension, 00156 # used for thumbnails (thumb.php) 00157 if ( $wgTrivialMimeDetection ) { 00158 switch ( $ext ) { 00159 case 'gif': return 'image/gif'; 00160 case 'png': return 'image/png'; 00161 case 'jpg': return 'image/jpeg'; 00162 case 'jpeg': return 'image/jpeg'; 00163 } 00164 00165 return 'unknown/unknown'; 00166 } 00167 00168 $magic = MimeMagic::singleton(); 00169 // Use the extension only, rather than magic numbers, to avoid opening 00170 // up vulnerabilities due to uploads of files with allowed extensions 00171 // but disallowed types. 00172 $type = $magic->guessTypesForExtension( $ext ); 00173 00178 if ( $safe ) { 00179 global $wgFileBlacklist, $wgCheckFileExtensions, $wgStrictFileExtensions, 00180 $wgFileExtensions, $wgVerifyMimeType, $wgMimeTypeBlacklist; 00181 list( , $extList ) = UploadBase::splitExtensions( $filename ); 00182 if ( UploadBase::checkFileExtensionList( $extList, $wgFileBlacklist ) ) { 00183 return 'unknown/unknown'; 00184 } 00185 if ( $wgCheckFileExtensions && $wgStrictFileExtensions 00186 && !UploadBase::checkFileExtensionList( $extList, $wgFileExtensions ) ) 00187 { 00188 return 'unknown/unknown'; 00189 } 00190 if ( $wgVerifyMimeType && in_array( strtolower( $type ), $wgMimeTypeBlacklist ) ) { 00191 return 'unknown/unknown'; 00192 } 00193 } 00194 return $type; 00195 } 00196 }