MediaWiki  REL1_22
SpecialPageFactory.php
Go to the documentation of this file.
00001 <?php
00046 class SpecialPageFactory {
00047 
00051     private static $mList = array(
00052         // Maintenance Reports
00053         'BrokenRedirects'           => 'BrokenRedirectsPage',
00054         'Deadendpages'              => 'DeadendpagesPage',
00055         'DoubleRedirects'           => 'DoubleRedirectsPage',
00056         'Longpages'                 => 'LongpagesPage',
00057         'Ancientpages'              => 'AncientpagesPage',
00058         'Lonelypages'               => 'LonelypagesPage',
00059         'Fewestrevisions'           => 'FewestrevisionsPage',
00060         'Withoutinterwiki'          => 'WithoutinterwikiPage',
00061         'Protectedpages'            => 'SpecialProtectedpages',
00062         'Protectedtitles'           => 'SpecialProtectedtitles',
00063         'Shortpages'                => 'ShortpagesPage',
00064         'Uncategorizedcategories'   => 'UncategorizedcategoriesPage',
00065         'Uncategorizedimages'       => 'UncategorizedimagesPage',
00066         'Uncategorizedpages'        => 'UncategorizedpagesPage',
00067         'Uncategorizedtemplates'    => 'UncategorizedtemplatesPage',
00068         'Unusedcategories'          => 'UnusedcategoriesPage',
00069         'Unusedimages'              => 'UnusedimagesPage',
00070         'Unusedtemplates'           => 'UnusedtemplatesPage',
00071         'Unwatchedpages'            => 'UnwatchedpagesPage',
00072         'Wantedcategories'          => 'WantedcategoriesPage',
00073         'Wantedfiles'               => 'WantedfilesPage',
00074         'Wantedpages'               => 'WantedpagesPage',
00075         'Wantedtemplates'           => 'WantedtemplatesPage',
00076 
00077         // List of pages
00078         'Allpages'                  => 'SpecialAllpages',
00079         'Prefixindex'               => 'SpecialPrefixindex',
00080         'Categories'                => 'SpecialCategories',
00081         'Listredirects'             => 'ListredirectsPage',
00082         'PagesWithProp'             => 'SpecialPagesWithProp',
00083 
00084         // Login/create account
00085         'Userlogin'                 => 'LoginForm',
00086         'CreateAccount'             => 'SpecialCreateAccount',
00087 
00088         // Users and rights
00089         'Block'                     => 'SpecialBlock',
00090         'Unblock'                   => 'SpecialUnblock',
00091         'BlockList'                 => 'SpecialBlockList',
00092         'ChangePassword'            => 'SpecialChangePassword',
00093         'PasswordReset'             => 'SpecialPasswordReset',
00094         'DeletedContributions'      => 'DeletedContributionsPage',
00095         'Preferences'               => 'SpecialPreferences',
00096         'ResetTokens'               => 'SpecialResetTokens',
00097         'Contributions'             => 'SpecialContributions',
00098         'Listgrouprights'           => 'SpecialListGroupRights',
00099         'Listusers'                 => 'SpecialListUsers',
00100         'Listadmins'                => 'SpecialListAdmins',
00101         'Listbots'                  => 'SpecialListBots',
00102         'Activeusers'               => 'SpecialActiveUsers',
00103         'Userrights'                => 'UserrightsPage',
00104         'EditWatchlist'             => 'SpecialEditWatchlist',
00105 
00106         // Recent changes and logs
00107         'Newimages'                 => 'SpecialNewFiles',
00108         'Log'                       => 'SpecialLog',
00109         'Watchlist'                 => 'SpecialWatchlist',
00110         'Newpages'                  => 'SpecialNewpages',
00111         'Recentchanges'             => 'SpecialRecentchanges',
00112         'Recentchangeslinked'       => 'SpecialRecentchangeslinked',
00113         'Tags'                      => 'SpecialTags',
00114 
00115         // Media reports and uploads
00116         'Listfiles'                 => 'SpecialListFiles',
00117         'Filepath'                  => 'SpecialFilepath',
00118         'MIMEsearch'                => 'MIMEsearchPage',
00119         'FileDuplicateSearch'       => 'FileDuplicateSearchPage',
00120         'Upload'                    => 'SpecialUpload',
00121         'UploadStash'               => 'SpecialUploadStash',
00122 
00123         // Data and tools
00124         'Statistics'                => 'SpecialStatistics',
00125         'Allmessages'               => 'SpecialAllmessages',
00126         'Version'                   => 'SpecialVersion',
00127         'Lockdb'                    => 'SpecialLockdb',
00128         'Unlockdb'                  => 'SpecialUnlockdb',
00129 
00130         // Redirecting special pages
00131         'LinkSearch'                => 'LinkSearchPage',
00132         'Randompage'                => 'Randompage',
00133         'RandomInCategory'          => 'SpecialRandomInCategory',
00134         'Randomredirect'            => 'SpecialRandomredirect',
00135 
00136         // High use pages
00137         'Mostlinkedcategories'      => 'MostlinkedCategoriesPage',
00138         'Mostimages'                => 'MostimagesPage',
00139         'Mostinterwikis'            => 'MostinterwikisPage',
00140         'Mostlinked'                => 'MostlinkedPage',
00141         'Mostlinkedtemplates'       => 'MostlinkedTemplatesPage',
00142         'Mostcategories'            => 'MostcategoriesPage',
00143         'Mostrevisions'             => 'MostrevisionsPage',
00144 
00145         // Page tools
00146         'ComparePages'              => 'SpecialComparePages',
00147         'Export'                    => 'SpecialExport',
00148         'Import'                    => 'SpecialImport',
00149         'Undelete'                  => 'SpecialUndelete',
00150         'Whatlinkshere'             => 'SpecialWhatlinkshere',
00151         'MergeHistory'              => 'SpecialMergeHistory',
00152 
00153         // Other
00154         'Booksources'               => 'SpecialBookSources',
00155 
00156         // Unlisted / redirects
00157         'Blankpage'                 => 'SpecialBlankpage',
00158         'Emailuser'                 => 'SpecialEmailUser',
00159         'Movepage'                  => 'MovePageForm',
00160         'Mycontributions'           => 'SpecialMycontributions',
00161         'Mypage'                    => 'SpecialMypage',
00162         'Mytalk'                    => 'SpecialMytalk',
00163         'Myuploads'                 => 'SpecialMyuploads',
00164         'AllMyUploads'              => 'SpecialAllMyUploads',
00165         'PermanentLink'             => 'SpecialPermanentLink',
00166         'Redirect'                  => 'SpecialRedirect',
00167         'Revisiondelete'            => 'SpecialRevisionDelete',
00168         'Specialpages'              => 'SpecialSpecialpages',
00169         'Userlogout'                => 'SpecialUserlogout',
00170     );
00171 
00172     private static $mAliases;
00173 
00180     static function getList() {
00181         global $wgSpecialPages;
00182         global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
00183         global $wgEnableEmail, $wgEnableJavaScriptTest;
00184 
00185         if ( !is_object( self::$mList ) ) {
00186             wfProfileIn( __METHOD__ );
00187 
00188             if ( !$wgDisableCounters ) {
00189                 self::$mList['Popularpages'] = 'PopularpagesPage';
00190             }
00191 
00192             if ( !$wgDisableInternalSearch ) {
00193                 self::$mList['Search'] = 'SpecialSearch';
00194             }
00195 
00196             if ( $wgEmailAuthentication ) {
00197                 self::$mList['Confirmemail'] = 'EmailConfirmation';
00198                 self::$mList['Invalidateemail'] = 'EmailInvalidation';
00199             }
00200 
00201             if ( $wgEnableEmail ) {
00202                 self::$mList['ChangeEmail'] = 'SpecialChangeEmail';
00203             }
00204 
00205             if ( $wgEnableJavaScriptTest ) {
00206                 self::$mList['JavaScriptTest'] = 'SpecialJavaScriptTest';
00207             }
00208 
00209             // Add extension special pages
00210             self::$mList = array_merge( self::$mList, $wgSpecialPages );
00211 
00212             // Run hooks
00213             // This hook can be used to remove undesired built-in special pages
00214             wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
00215 
00216             // Cast to object: func()[$key] doesn't work, but func()->$key does
00217             settype( self::$mList, 'object' );
00218 
00219             wfProfileOut( __METHOD__ );
00220         }
00221         return self::$mList;
00222     }
00223 
00232     static function getAliasList() {
00233         if ( !is_object( self::$mAliases ) ) {
00234             global $wgContLang;
00235             $aliases = $wgContLang->getSpecialPageAliases();
00236 
00237             // Objects are passed by reference by default, need to create a copy
00238             $missingPages = clone self::getList();
00239 
00240             self::$mAliases = array();
00241             foreach ( $aliases as $realName => $aliasList ) {
00242                 foreach ( $aliasList as $alias ) {
00243                     self::$mAliases[$wgContLang->caseFold( $alias )] = $realName;
00244                 }
00245                 unset( $missingPages->$realName );
00246             }
00247             foreach ( $missingPages as $name => $stuff ) {
00248                 self::$mAliases[$wgContLang->caseFold( $name )] = $name;
00249             }
00250 
00251             // Cast to object: func()[$key] doesn't work, but func()->$key does
00252             self::$mAliases = (object)self::$mAliases;
00253         }
00254         return self::$mAliases;
00255     }
00256 
00265     public static function resolveAlias( $alias ) {
00266         global $wgContLang;
00267         $bits = explode( '/', $alias, 2 );
00268 
00269         $caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
00270         $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
00271         if ( isset( self::getAliasList()->$caseFoldedAlias ) ) {
00272             $name = self::getAliasList()->$caseFoldedAlias;
00273         } else {
00274             return array( null, null );
00275         }
00276 
00277         if ( !isset( $bits[1] ) ) { // bug 2087
00278             $par = null;
00279         } else {
00280             $par = $bits[1];
00281         }
00282 
00283         return array( $name, $par );
00284     }
00285 
00293     public static function setGroup( $page, $group ) {
00294         wfDeprecated( __METHOD__, '1.21' );
00295 
00296         global $wgSpecialPageGroups;
00297         $name = is_object( $page ) ? $page->getName() : $page;
00298         $wgSpecialPageGroups[$name] = $group;
00299     }
00300 
00308     public static function getGroup( &$page ) {
00309         wfDeprecated( __METHOD__, '1.21' );
00310 
00311         return $page->getFinalGroupName();
00312     }
00313 
00320     public static function exists( $name ) {
00321         list( $title, /*...*/ ) = self::resolveAlias( $name );
00322         return property_exists( self::getList(), $title );
00323     }
00324 
00331     public static function getPage( $name ) {
00332         list( $realName, /*...*/ ) = self::resolveAlias( $name );
00333         if ( property_exists( self::getList(), $realName ) ) {
00334             $rec = self::getList()->$realName;
00335             if ( is_string( $rec ) ) {
00336                 $className = $rec;
00337                 return new $className;
00338             } elseif ( is_array( $rec ) ) {
00339                 // @deprecated, officially since 1.18, unofficially since forever
00340                 wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." );
00341                 $className = array_shift( $rec );
00342                 self::getList()->$realName = MWFunction::newObj( $className, $rec );
00343             }
00344             return self::getList()->$realName;
00345         } else {
00346             return null;
00347         }
00348     }
00349 
00358     public static function getUsablePages( User $user = null ) {
00359         $pages = array();
00360         if ( $user === null ) {
00361             global $wgUser;
00362             $user = $wgUser;
00363         }
00364         foreach ( self::getList() as $name => $rec ) {
00365             $page = self::getPage( $name );
00366             if ( $page ) { // not null
00367                 $page->setContext( RequestContext::getMain() );
00368                 if ( $page->isListed()
00369                     && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
00370                 ) {
00371                     $pages[$name] = $page;
00372                 }
00373             }
00374         }
00375         return $pages;
00376     }
00377 
00383     public static function getRegularPages() {
00384         $pages = array();
00385         foreach ( self::getList() as $name => $rec ) {
00386             $page = self::getPage( $name );
00387             if ( $page->isListed() && !$page->isRestricted() ) {
00388                 $pages[$name] = $page;
00389             }
00390         }
00391         return $pages;
00392     }
00393 
00400     public static function getRestrictedPages() {
00401         global $wgUser;
00402         $pages = array();
00403         foreach ( self::getList() as $name => $rec ) {
00404             $page = self::getPage( $name );
00405             if (
00406                 $page->isListed()
00407                 && $page->isRestricted()
00408                 && $page->userCanExecute( $wgUser )
00409             ) {
00410                 $pages[$name] = $page;
00411             }
00412         }
00413         return $pages;
00414     }
00415 
00430     public static function executePath( Title &$title, IContextSource &$context, $including = false ) {
00431         wfProfileIn( __METHOD__ );
00432 
00433         // @todo FIXME: Redirects broken due to this call
00434         $bits = explode( '/', $title->getDBkey(), 2 );
00435         $name = $bits[0];
00436         if ( !isset( $bits[1] ) ) { // bug 2087
00437             $par = null;
00438         } else {
00439             $par = $bits[1];
00440         }
00441         $page = self::getPage( $name );
00442         // Nonexistent?
00443         if ( !$page ) {
00444             $context->getOutput()->setArticleRelated( false );
00445             $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
00446 
00447             global $wgSend404Code;
00448             if ( $wgSend404Code ) {
00449                 $context->getOutput()->setStatusCode( 404 );
00450             }
00451 
00452             $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
00453             wfProfileOut( __METHOD__ );
00454             return false;
00455         }
00456 
00457         // Page exists, set the context
00458         $page->setContext( $context );
00459 
00460         if ( !$including ) {
00461             // Redirect to canonical alias for GET commands
00462             // Not for POST, we'd lose the post data, so it's best to just distribute
00463             // the request. Such POST requests are possible for old extensions that
00464             // generate self-links without being aware that their default name has
00465             // changed.
00466             if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
00467                 $query = $context->getRequest()->getQueryValues();
00468                 unset( $query['title'] );
00469                 $title = $page->getTitle( $par );
00470                 $url = $title->getFullURL( $query );
00471                 $context->getOutput()->redirect( $url );
00472                 wfProfileOut( __METHOD__ );
00473                 return $title;
00474             } else {
00475                 $context->setTitle( $page->getTitle( $par ) );
00476             }
00477 
00478         } elseif ( !$page->isIncludable() ) {
00479             wfProfileOut( __METHOD__ );
00480             return false;
00481         }
00482 
00483         $page->including( $including );
00484 
00485         // Execute special page
00486         $profName = 'Special:' . $page->getName();
00487         wfProfileIn( $profName );
00488         $page->run( $par );
00489         wfProfileOut( $profName );
00490         wfProfileOut( __METHOD__ );
00491         return true;
00492     }
00493 
00509     static function capturePath( Title $title, IContextSource $context ) {
00510         global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
00511 
00512         // Save current globals
00513         $oldTitle = $wgTitle;
00514         $oldOut = $wgOut;
00515         $oldRequest = $wgRequest;
00516         $oldUser = $wgUser;
00517         $oldLang = $wgLang;
00518 
00519         // Set the globals to the current context
00520         $wgTitle = $title;
00521         $wgOut = $context->getOutput();
00522         $wgRequest = $context->getRequest();
00523         $wgUser = $context->getUser();
00524         $wgLang = $context->getLanguage();
00525 
00526         // The useful part
00527         $ret = self::executePath( $title, $context, true );
00528 
00529         // And restore the old globals
00530         $wgTitle = $oldTitle;
00531         $wgOut = $oldOut;
00532         $wgRequest = $oldRequest;
00533         $wgUser = $oldUser;
00534         $wgLang = $oldLang;
00535 
00536         return $ret;
00537     }
00538 
00547     static function getLocalNameFor( $name, $subpage = false ) {
00548         global $wgContLang;
00549         $aliases = $wgContLang->getSpecialPageAliases();
00550 
00551         if ( isset( $aliases[$name][0] ) ) {
00552             $name = $aliases[$name][0];
00553         } else {
00554             // Try harder in case someone misspelled the correct casing
00555             $found = false;
00556             foreach ( $aliases as $n => $values ) {
00557                 if ( strcasecmp( $name, $n ) === 0 ) {
00558                     wfWarn( "Found alias defined for $n when searching for " .
00559                         "special page aliases for $name. Case mismatch?" );
00560                     $name = $values[0];
00561                     $found = true;
00562                     break;
00563                 }
00564             }
00565             if ( !$found ) {
00566                 wfWarn( "Did not find alias for special page '$name'. " .
00567                     "Perhaps no aliases are defined for it?" );
00568             }
00569         }
00570         if ( $subpage !== false && !is_null( $subpage ) ) {
00571             $name = "$name/$subpage";
00572         }
00573         return $wgContLang->ucfirst( $name );
00574     }
00575 
00583     static function getTitleForAlias( $alias ) {
00584         $name = self::resolveAlias( $alias );
00585         if ( $name ) {
00586             return SpecialPage::getTitleFor( $name );
00587         } else {
00588             return null;
00589         }
00590     }
00591 }