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