MediaWiki  REL1_24
img_auth.php
Go to the documentation of this file.
00001 <?php
00040 define( 'MW_NO_OUTPUT_COMPRESSION', 1 );
00041 require __DIR__ . '/includes/WebStart.php';
00042 wfProfileIn( 'img_auth.php' );
00043 
00044 # Set action base paths so that WebRequest::getPathInfo()
00045 # recognizes the "X" as the 'title' in ../img_auth.php/X urls.
00046 $wgArticlePath = false; # Don't let a "/*" article path clober our action path
00047 $wgActionPaths = array( "$wgUploadPath/" );
00048 
00049 wfImageAuthMain();
00050 wfProfileOut( 'img_auth.php' );
00051 wfLogProfilingData();
00052 // Commit and close up!
00053 $factory = wfGetLBFactory();
00054 $factory->commitMasterChanges();
00055 $factory->shutdown();
00056 
00057 function wfImageAuthMain() {
00058     global $wgImgAuthUrlPathMap;
00059 
00060     $request = RequestContext::getMain()->getRequest();
00061     $publicWiki = in_array( 'read', User::getGroupPermissions( array( '*' ) ), true );
00062 
00063     // Get the requested file path (source file or thumbnail)
00064     $matches = WebRequest::getPathInfo();
00065     if ( !isset( $matches['title'] ) ) {
00066         wfForbidden( 'img-auth-accessdenied', 'img-auth-nopathinfo' );
00067         return;
00068     }
00069     $path = $matches['title'];
00070     if ( $path && $path[0] !== '/' ) {
00071         // Make sure $path has a leading /
00072         $path = "/" . $path;
00073     }
00074 
00075     // Check for bug 28235: QUERY_STRING overriding the correct extension
00076     $whitelist = array();
00077     $extension = FileBackend::extensionFromPath( $path, 'rawcase' );
00078     if ( $extension != '' ) {
00079         $whitelist[] = $extension;
00080     }
00081     if ( !$request->checkUrlExtension( $whitelist ) ) {
00082         return;
00083     }
00084 
00085     // Various extensions may have their own backends that need access.
00086     // Check if there is a special backend and storage base path for this file.
00087     foreach ( $wgImgAuthUrlPathMap as $prefix => $storageDir ) {
00088         $prefix = rtrim( $prefix, '/' ) . '/'; // implicit trailing slash
00089         if ( strpos( $path, $prefix ) === 0 ) {
00090             $be = FileBackendGroup::singleton()->backendFromPath( $storageDir );
00091             $filename = $storageDir . substr( $path, strlen( $prefix ) ); // strip prefix
00092             // Check basic user authorization
00093             if ( !RequestContext::getMain()->getUser()->isAllowed( 'read' ) ) {
00094                 wfForbidden( 'img-auth-accessdenied', 'img-auth-noread', $path );
00095                 return;
00096             }
00097             if ( $be->fileExists( array( 'src' => $filename ) ) ) {
00098                 wfDebugLog( 'img_auth', "Streaming `" . $filename . "`." );
00099                 $be->streamFile( array( 'src' => $filename ),
00100                     array( 'Cache-Control: private', 'Vary: Cookie' ) );
00101             } else {
00102                 wfForbidden( 'img-auth-accessdenied', 'img-auth-nofile', $path );
00103             }
00104             return;
00105         }
00106     }
00107 
00108     // Get the local file repository
00109     $repo = RepoGroup::singleton()->getRepo( 'local' );
00110     $zone = strstr( ltrim( $path, '/' ), '/', true );
00111 
00112     // Get the full file storage path and extract the source file name.
00113     // (e.g. 120px-Foo.png => Foo.png or page2-120px-Foo.png => Foo.png).
00114     // This only applies to thumbnails/transcoded, and each of them should
00115     // be under a folder that has the source file name.
00116     if ( $zone === 'thumb' || $zone === 'transcoded' ) {
00117         $name = wfBaseName( dirname( $path ) );
00118         $filename = $repo->getZonePath( $zone ) . substr( $path, strlen( "/" . $zone ) );
00119         // Check to see if the file exists
00120         if ( !$repo->fileExists( $filename ) ) {
00121             wfForbidden( 'img-auth-accessdenied', 'img-auth-nofile', $filename );
00122             return;
00123         }
00124     } else {
00125         $name = wfBaseName( $path ); // file is a source file
00126         $filename = $repo->getZonePath( 'public' ) . $path;
00127         // Check to see if the file exists and is not deleted
00128         $bits = explode( '!', $name, 2 );
00129         if ( substr( $path, 0, 9 ) === '/archive/' && count( $bits ) == 2 ) {
00130             $file = $repo->newFromArchiveName( $bits[1], $name );
00131         } else {
00132             $file = $repo->newFile( $name );
00133         }
00134         if ( !$file->exists() || $file->isDeleted( File::DELETED_FILE ) ) {
00135             wfForbidden( 'img-auth-accessdenied', 'img-auth-nofile', $filename );
00136             return;
00137         }
00138     }
00139 
00140     $headers = array(); // extra HTTP headers to send
00141 
00142     if ( !$publicWiki ) {
00143         // For private wikis, run extra auth checks and set cache control headers
00144         $headers[] = 'Cache-Control: private';
00145         $headers[] = 'Vary: Cookie';
00146 
00147         $title = Title::makeTitleSafe( NS_FILE, $name );
00148         if ( !$title instanceof Title ) { // files have valid titles
00149             wfForbidden( 'img-auth-accessdenied', 'img-auth-badtitle', $name );
00150             return;
00151         }
00152 
00153         // Run hook for extension authorization plugins
00155         $result = null;
00156         if ( !wfRunHooks( 'ImgAuthBeforeStream', array( &$title, &$path, &$name, &$result ) ) ) {
00157             wfForbidden( $result[0], $result[1], array_slice( $result, 2 ) );
00158             return;
00159         }
00160 
00161         // Check user authorization for this title
00162         // Checks Whitelist too
00163         if ( !$title->userCan( 'read' ) ) {
00164             wfForbidden( 'img-auth-accessdenied', 'img-auth-noread', $name );
00165             return;
00166         }
00167     }
00168 
00169     if ( $request->getCheck( 'download' ) ) {
00170         $headers[] = 'Content-Disposition: attachment';
00171     }
00172 
00173     // Stream the requested file
00174     wfDebugLog( 'img_auth', "Streaming `" . $filename . "`." );
00175     $repo->streamFile( $filename, $headers );
00176 }
00177 
00185 function wfForbidden( $msg1, $msg2 ) {
00186     global $wgImgAuthDetails;
00187 
00188     $args = func_get_args();
00189     array_shift( $args );
00190     array_shift( $args );
00191     $args = ( isset( $args[0] ) && is_array( $args[0] ) ) ? $args[0] : $args;
00192 
00193     $msgHdr = wfMessage( $msg1 )->escaped();
00194     $detailMsgKey = $wgImgAuthDetails ? $msg2 : 'badaccess-group0';
00195     $detailMsg = wfMessage( $detailMsgKey, $args )->escaped();
00196 
00197     wfDebugLog( 'img_auth',
00198         "wfForbidden Hdr: " . wfMessage( $msg1 )->inLanguage( 'en' )->text() . " Msg: " .
00199             wfMessage( $msg2, $args )->inLanguage( 'en' )->text()
00200     );
00201 
00202     header( 'HTTP/1.0 403 Forbidden' );
00203     header( 'Cache-Control: no-cache' );
00204     header( 'Content-Type: text/html; charset=utf-8' );
00205     echo <<<ENDS
00206 <html>
00207 <body>
00208 <h1>$msgHdr</h1>
00209 <p>$detailMsg</p>
00210 </body>
00211 </html>
00212 ENDS;
00213 }