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