r94427 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94426‎ | r94427 | r94428 >
Date:19:03, 13 August 2011
Author:demon
Status:ok
Tags:
Comment:
Move wfStreamFile() into a class, update all callers in core (only 3 extensions use it afaict), leave wfStreamFile() as a b/c alias for now.
Yay less global functions, autoloading and less manual require()s.
Modified paths:
  • /trunk/phase3/img_auth.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/StreamFile.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialRevisiondelete.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialUndelete.php (modified) (history)
  • /trunk/phase3/thumb.php (modified) (history)

Diff [purge]

Index: trunk/phase3/thumb.php
@@ -15,8 +15,6 @@
1616
1717 $wgTrivialMimeDetection = true; //don't use fancy mime detection, just check the file extension for jpg/gif/png.
1818
19 -require_once( "$IP/includes/StreamFile.php" );
20 -
2119 wfThumbMain();
2220 wfLogProfilingData();
2321
@@ -126,7 +124,7 @@
127125 $thumbPath = $img->getThumbPath( $thumbName );
128126
129127 if ( is_file( $thumbPath ) ) {
130 - wfStreamFile( $thumbPath, $headers );
 128+ StreamFile::stream( $thumbPath, $headers );
131129 wfProfileOut( __METHOD__ );
132130 return;
133131 }
@@ -155,7 +153,7 @@
156154 $errorMsg = wfMsgHtml( 'thumbnail_error', 'Image was not scaled, ' .
157155 'is the requested width bigger than the source?' );
158156 } else {
159 - wfStreamFile( $thumb->getPath(), $headers );
 157+ StreamFile::stream( $thumb->getPath(), $headers );
160158 }
161159 if ( $errorMsg !== false ) {
162160 wfThumbError( 500, $errorMsg );
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -3197,6 +3197,14 @@
31983198 }
31993199
32003200 /**
 3201+ * Stream a file to the browser. Back-compat alias for StreamFile::stream()
 3202+ * @deprecated since 1.19
 3203+ */
 3204+function wfStreamFile( $fname, $headers = array() ) {
 3205+ StreamFile::stream( $fname, $headers );
 3206+}
 3207+
 3208+/**
32013209 * Should low-performance queries be disabled?
32023210 *
32033211 * @return Boolean
Index: trunk/phase3/includes/AutoLoader.php
@@ -213,6 +213,7 @@
214214 'SquidPurgeClient' => 'includes/SquidPurgeClient.php',
215215 'SquidPurgeClientPool' => 'includes/SquidPurgeClient.php',
216216 'Status' => 'includes/Status.php',
 217+ 'StreamFile' => 'includes/StreamFile.php',
217218 'StringUtils' => 'includes/StringUtils.php',
218219 'StubContLang' => 'includes/StubObject.php',
219220 'StubObject' => 'includes/StubObject.php',
Index: trunk/phase3/includes/StreamFile.php
@@ -4,119 +4,122 @@
55 *
66 * @file
77 */
 8+class StreamFile {
 9+ /**
 10+ * Stream a file to the browser, adding all the headings and fun stuff
 11+ * @param $fname string Full name and path of the file to stream
 12+ * @param $headers array Any additional headers to send
 13+ */
 14+ public static function stream( $fname, $headers = array(), $request = null ) {
 15+ wfSuppressWarnings();
 16+ $stat = stat( $fname );
 17+ wfRestoreWarnings();
 18+ if ( !$stat ) {
 19+ header( 'HTTP/1.0 404 Not Found' );
 20+ header( 'Cache-Control: no-cache' );
 21+ header( 'Content-Type: text/html; charset=utf-8' );
 22+ $encFile = htmlspecialchars( $fname );
 23+ $encScript = htmlspecialchars( $_SERVER['SCRIPT_NAME'] );
 24+ echo "<html><body>
 25+ <h1>File not found</h1>
 26+ <p>Although this PHP script ($encScript) exists, the file requested for output
 27+ ($encFile) does not.</p>
 28+ </body></html>
 29+ ";
 30+ return;
 31+ }
832
9 -/**
10 - * @param $fname string
11 - * @param $headers array
12 - */
13 -function wfStreamFile( $fname, $headers = array() ) {
14 - wfSuppressWarnings();
15 - $stat = stat( $fname );
16 - wfRestoreWarnings();
17 - if ( !$stat ) {
18 - header( 'HTTP/1.0 404 Not Found' );
19 - header( 'Cache-Control: no-cache' );
20 - header( 'Content-Type: text/html; charset=utf-8' );
21 - $encFile = htmlspecialchars( $fname );
22 - $encScript = htmlspecialchars( $_SERVER['SCRIPT_NAME'] );
23 - echo "<html><body>
24 -<h1>File not found</h1>
25 -<p>Although this PHP script ($encScript) exists, the file requested for output
26 -($encFile) does not.</p>
27 -</body></html>
28 -";
29 - return;
30 - }
 33+ header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $stat['mtime'] ) . ' GMT' );
3134
32 - header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $stat['mtime'] ) . ' GMT' );
 35+ // Cancel output buffering and gzipping if set
 36+ wfResetOutputBuffers();
3337
34 - // Cancel output buffering and gzipping if set
35 - wfResetOutputBuffers();
 38+ $type = self::getType( $fname );
 39+ if ( $type && $type != 'unknown/unknown' ) {
 40+ header( "Content-type: $type" );
 41+ } else {
 42+ header( 'Content-type: application/x-wiki' );
 43+ }
3644
37 - $type = wfGetType( $fname );
38 - if ( $type and $type!="unknown/unknown") {
39 - header("Content-type: $type");
40 - } else {
41 - header('Content-type: application/x-wiki');
42 - }
43 -
44 - // Don't stream it out as text/html if there was a PHP error
45 - if ( headers_sent() ) {
46 - echo "Headers already sent, terminating.\n";
47 - return;
48 - }
49 -
50 - global $wgLanguageCode;
51 - header( "Content-Disposition: inline;filename*=utf-8'$wgLanguageCode'" . urlencode( basename( $fname ) ) );
52 -
53 - foreach ( $headers as $header ) {
54 - header( $header );
55 - }
56 -
57 - if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
58 - $modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
59 - $sinceTime = strtotime( $modsince );
60 - if ( $stat['mtime'] <= $sinceTime ) {
61 - ini_set('zlib.output_compression', 0);
62 - header( "HTTP/1.0 304 Not Modified" );
 45+ // Don't stream it out as text/html if there was a PHP error
 46+ if ( headers_sent() ) {
 47+ echo "Headers already sent, terminating.\n";
6348 return;
6449 }
65 - }
6650
67 - header( 'Content-Length: ' . $stat['size'] );
 51+ global $wgLanguageCode;
 52+ header( "Content-Disposition: inline;filename*=utf-8'$wgLanguageCode'" . urlencode( basename( $fname ) ) );
6853
69 - readfile( $fname );
70 -}
 54+ foreach ( $headers as $header ) {
 55+ header( $header );
 56+ }
7157
72 -/**
73 - * @param $filename string
74 - * @param $safe bool
75 - * @return null|string
76 - */
77 -function wfGetType( $filename, $safe = true ) {
78 - global $wgTrivialMimeDetection;
 58+ if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
 59+ $modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
 60+ $sinceTime = strtotime( $modsince );
 61+ if ( $stat['mtime'] <= $sinceTime ) {
 62+ ini_set( 'zlib.output_compression', 0 );
 63+ header( "HTTP/1.0 304 Not Modified" );
 64+ return;
 65+ }
 66+ }
7967
80 - $ext = strrchr($filename, '.');
81 - $ext = $ext === false ? '' : strtolower( substr( $ext, 1 ) );
 68+ header( 'Content-Length: ' . $stat['size'] );
8269
83 - # trivial detection by file extension,
84 - # used for thumbnails (thumb.php)
85 - if ($wgTrivialMimeDetection) {
86 - switch ($ext) {
87 - case 'gif': return 'image/gif';
88 - case 'png': return 'image/png';
89 - case 'jpg': return 'image/jpeg';
90 - case 'jpeg': return 'image/jpeg';
91 - }
92 -
93 - return 'unknown/unknown';
 70+ readfile( $fname );
9471 }
95 -
96 - $magic = MimeMagic::singleton();
97 - // Use the extension only, rather than magic numbers, to avoid opening
98 - // up vulnerabilities due to uploads of files with allowed extensions
99 - // but disallowed types.
100 - $type = $magic->guessTypesForExtension( $ext );
10172
10273 /**
103 - * Double-check some security settings that were done on upload but might
104 - * have changed since.
 74+ * Determine the filetype we're dealing with
 75+ * @param $filename string
 76+ * @param $safe bool
 77+ * @return null|string
10578 */
106 - if ( $safe ) {
107 - global $wgFileBlacklist, $wgCheckFileExtensions, $wgStrictFileExtensions,
108 - $wgFileExtensions, $wgVerifyMimeType, $wgMimeTypeBlacklist;
109 - list( , $extList ) = UploadBase::splitExtensions( $filename );
110 - if ( UploadBase::checkFileExtensionList( $extList, $wgFileBlacklist ) ) {
 79+ private static function getType( $filename, $safe = true ) {
 80+ global $wgTrivialMimeDetection;
 81+
 82+ $ext = strrchr( $filename, '.' );
 83+ $ext = $ext === false ? '' : strtolower( substr( $ext, 1 ) );
 84+
 85+ # trivial detection by file extension,
 86+ # used for thumbnails (thumb.php)
 87+ if ( $wgTrivialMimeDetection ) {
 88+ switch ( $ext ) {
 89+ case 'gif': return 'image/gif';
 90+ case 'png': return 'image/png';
 91+ case 'jpg': return 'image/jpeg';
 92+ case 'jpeg': return 'image/jpeg';
 93+ }
 94+
11195 return 'unknown/unknown';
11296 }
113 - if ( $wgCheckFileExtensions && $wgStrictFileExtensions
114 - && !UploadBase::checkFileExtensionList( $extList, $wgFileExtensions ) )
115 - {
116 - return 'unknown/unknown';
 97+
 98+ $magic = MimeMagic::singleton();
 99+ // Use the extension only, rather than magic numbers, to avoid opening
 100+ // up vulnerabilities due to uploads of files with allowed extensions
 101+ // but disallowed types.
 102+ $type = $magic->guessTypesForExtension( $ext );
 103+
 104+ /**
 105+ * Double-check some security settings that were done on upload but might
 106+ * have changed since.
 107+ */
 108+ if ( $safe ) {
 109+ global $wgFileBlacklist, $wgCheckFileExtensions, $wgStrictFileExtensions,
 110+ $wgFileExtensions, $wgVerifyMimeType, $wgMimeTypeBlacklist;
 111+ list( , $extList ) = UploadBase::splitExtensions( $filename );
 112+ if ( UploadBase::checkFileExtensionList( $extList, $wgFileBlacklist ) ) {
 113+ return 'unknown/unknown';
 114+ }
 115+ if ( $wgCheckFileExtensions && $wgStrictFileExtensions
 116+ && !UploadBase::checkFileExtensionList( $extList, $wgFileExtensions ) )
 117+ {
 118+ return 'unknown/unknown';
 119+ }
 120+ if ( $wgVerifyMimeType && in_array( strtolower( $type ), $wgMimeTypeBlacklist ) ) {
 121+ return 'unknown/unknown';
 122+ }
117123 }
118 - if ( $wgVerifyMimeType && in_array( strtolower( $type ), $wgMimeTypeBlacklist ) ) {
119 - return 'unknown/unknown';
120 - }
 124+ return $type;
121125 }
122 - return $type;
123126 }
Index: trunk/phase3/includes/specials/SpecialUndelete.php
@@ -1013,11 +1013,9 @@
10141014 $response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
10151015 $response->header( 'Pragma: no-cache' );
10161016
1017 - global $IP;
1018 - require_once( "$IP/includes/StreamFile.php" );
10191017 $repo = RepoGroup::singleton()->getLocalRepo();
10201018 $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
1021 - wfStreamFile( $path );
 1019+ StreamFile::stream( $path );
10221020 }
10231021
10241022 private function showHistory() {
Index: trunk/phase3/includes/specials/SpecialRevisiondelete.php
@@ -316,12 +316,9 @@
317317 $this->getRequest()->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
318318 $this->getRequest()->response()->header( 'Pragma: no-cache' );
319319
320 - # Stream the file to the client
321 - global $IP;
322 - require_once( "$IP/includes/StreamFile.php" );
323320 $key = $oimage->getStorageKey();
324321 $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
325 - wfStreamFile( $path );
 322+ StreamFile::stream( $path );
326323 }
327324
328325 /**
Index: trunk/phase3/img_auth.php
@@ -32,7 +32,6 @@
3333 require ( dirname( __FILE__ ) . '/includes/WebStart.php' );
3434 }
3535 wfProfileIn( 'img_auth.php' );
36 -require_once( dirname( __FILE__ ) . '/includes/StreamFile.php' );
3736
3837 $wgActionPaths[] = $_SERVER['SCRIPT_NAME'];
3938 // See if this is a public Wiki (no protections)
@@ -95,7 +94,7 @@
9695
9796 // Stream the requested file
9897 wfDebugLog( 'img_auth', "Streaming `".$filename."`." );
99 -wfStreamFile( $filename, array( 'Cache-Control: private', 'Vary: Cookie' ) );
 98+StreamFile::stream( $filename, array( 'Cache-Control: private', 'Vary: Cookie' ) );
10099 wfLogProfilingData();
101100
102101 /**

Status & tagging log