0 && $ok ) { $bytes = min( $remaining, 8 * 1024 ); $data = fread( $handle, $bytes ); $remaining -= $bytes; $ok = ( $data !== false ); print $data; } } else { return false; } } else { return readfile( $fname ) !== false; // faster } return true; } /** * Send out a standard 404 message for a file * * @param string $fname Full name and path of the file to stream * @param integer $flags Bitfield of STREAM_* constants * @since 1.24 */ public static function send404Message( $fname, $flags = 0 ) { if ( ( $flags & self::STREAM_HEADLESS ) == 0 ) { HttpStatus::header( 404 ); header( 'Cache-Control: no-cache' ); header( 'Content-Type: text/html; charset=utf-8' ); } $encFile = htmlspecialchars( $fname ); $encScript = htmlspecialchars( $_SERVER['SCRIPT_NAME'] ); echo "

File not found

Although this PHP script ($encScript) exists, the file requested for output ($encFile) does not.

"; } /** * Convert a Range header value to an absolute (start, end) range tuple * * @param string $range Range header value * @param integer $size File size * @return array|string Returns error string on failure (start, end, length) * @since 1.24 */ public static function parseRange( $range, $size ) { $m = []; if ( preg_match( '#^bytes=(\d*)-(\d*)$#', $range, $m ) ) { list( , $start, $end ) = $m; if ( $start === '' && $end === '' ) { $absRange = [ 0, $size - 1 ]; } elseif ( $start === '' ) { $absRange = [ $size - $end, $size - 1 ]; } elseif ( $end === '' ) { $absRange = [ $start, $size - 1 ]; } else { $absRange = [ $start, $end ]; } if ( $absRange[0] >= 0 && $absRange[1] >= $absRange[0] ) { if ( $absRange[0] < $size ) { $absRange[1] = min( $absRange[1], $size - 1 ); // stop at EOF $absRange[2] = $absRange[1] - $absRange[0] + 1; return $absRange; } elseif ( $absRange[0] == 0 && $size == 0 ) { return 'unrecognized'; // the whole file should just be sent } } return 'invalid'; } return 'unrecognized'; } /** * Determine the file type of a file based on the path * * @param string $filename Storage path or file system path * @param bool $safe Whether to do retroactive upload blacklist checks * @return null|string */ public static function contentTypeFromPath( $filename, $safe = true ) { global $wgTrivialMimeDetection; $ext = strrchr( $filename, '.' ); $ext = $ext === false ? '' : strtolower( substr( $ext, 1 ) ); # trivial detection by file extension, # used for thumbnails (thumb.php) if ( $wgTrivialMimeDetection ) { switch ( $ext ) { case 'gif': return 'image/gif'; case 'png': return 'image/png'; case 'jpg': return 'image/jpeg'; case 'jpeg': return 'image/jpeg'; } return 'unknown/unknown'; } $magic = MimeMagic::singleton(); // Use the extension only, rather than magic numbers, to avoid opening // up vulnerabilities due to uploads of files with allowed extensions // but disallowed types. $type = $magic->guessTypesForExtension( $ext ); /** * Double-check some security settings that were done on upload but might * have changed since. */ if ( $safe ) { global $wgFileBlacklist, $wgCheckFileExtensions, $wgStrictFileExtensions, $wgFileExtensions, $wgVerifyMimeType, $wgMimeTypeBlacklist; list( , $extList ) = UploadBase::splitExtensions( $filename ); if ( UploadBase::checkFileExtensionList( $extList, $wgFileBlacklist ) ) { return 'unknown/unknown'; } if ( $wgCheckFileExtensions && $wgStrictFileExtensions && !UploadBase::checkFileExtensionList( $extList, $wgFileExtensions ) ) { return 'unknown/unknown'; } if ( $wgVerifyMimeType && in_array( strtolower( $type ), $wgMimeTypeBlacklist ) ) { return 'unknown/unknown'; } } return $type; } }