MediaWiki  REL1_21
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                 'Disambiguations'           => 'DisambiguationsPage',
00082                 'Listredirects'             => 'ListredirectsPage',
00083                 'PagesWithProp'             => 'SpecialPagesWithProp',
00084 
00085                 // Login/create account
00086                 'Userlogin'                 => 'LoginForm',
00087                 'CreateAccount'             => 'SpecialCreateAccount',
00088 
00089                 // Users and rights
00090                 'Block'                     => 'SpecialBlock',
00091                 'Unblock'                   => 'SpecialUnblock',
00092                 'BlockList'                 => 'SpecialBlockList',
00093                 'ChangePassword'            => 'SpecialChangePassword',
00094                 'PasswordReset'             => 'SpecialPasswordReset',
00095                 'DeletedContributions'      => 'DeletedContributionsPage',
00096                 'Preferences'               => 'SpecialPreferences',
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                 'Randomredirect'            => 'SpecialRandomredirect',
00134 
00135                 // High use pages
00136                 'Mostlinkedcategories'      => 'MostlinkedCategoriesPage',
00137                 'Mostimages'                => 'MostimagesPage',
00138                 'Mostinterwikis'            => 'MostinterwikisPage',
00139                 'Mostlinked'                => 'MostlinkedPage',
00140                 'Mostlinkedtemplates'       => 'MostlinkedTemplatesPage',
00141                 'Mostcategories'            => 'MostcategoriesPage',
00142                 'Mostrevisions'             => 'MostrevisionsPage',
00143 
00144                 // Page tools
00145                 'ComparePages'              => 'SpecialComparePages',
00146                 'Export'                    => 'SpecialExport',
00147                 'Import'                    => 'SpecialImport',
00148                 'Undelete'                  => 'SpecialUndelete',
00149                 'Whatlinkshere'             => 'SpecialWhatlinkshere',
00150                 'MergeHistory'              => 'SpecialMergeHistory',
00151 
00152                 // Other
00153                 'Booksources'               => 'SpecialBookSources',
00154 
00155                 // Unlisted / redirects
00156                 'Blankpage'                 => 'SpecialBlankpage',
00157                 'Blockme'                   => 'SpecialBlockme',
00158                 'Emailuser'                 => 'SpecialEmailUser',
00159                 'Movepage'                  => 'MovePageForm',
00160                 'Mycontributions'           => 'SpecialMycontributions',
00161                 'Mypage'                    => 'SpecialMypage',
00162                 'Mytalk'                    => 'SpecialMytalk',
00163                 'Myuploads'                 => 'SpecialMyuploads',
00164                 'PermanentLink'             => 'SpecialPermanentLink',
00165                 'Revisiondelete'            => 'SpecialRevisionDelete',
00166                 'Specialpages'              => 'SpecialSpecialpages',
00167                 'Userlogout'                => 'SpecialUserlogout',
00168         );
00169 
00170         private static $mAliases;
00171 
00178         static function getList() {
00179                 global $wgSpecialPages;
00180                 global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
00181                 global $wgEnableEmail, $wgEnableJavaScriptTest;
00182 
00183                 if ( !is_object( self::$mList ) ) {
00184                         wfProfileIn( __METHOD__ );
00185 
00186                         if ( !$wgDisableCounters ) {
00187                                 self::$mList['Popularpages'] = 'PopularpagesPage';
00188                         }
00189 
00190                         if ( !$wgDisableInternalSearch ) {
00191                                 self::$mList['Search'] = 'SpecialSearch';
00192                         }
00193 
00194                         if ( $wgEmailAuthentication ) {
00195                                 self::$mList['Confirmemail'] = 'EmailConfirmation';
00196                                 self::$mList['Invalidateemail'] = 'EmailInvalidation';
00197                         }
00198 
00199                         if ( $wgEnableEmail ) {
00200                                 self::$mList['ChangeEmail'] = 'SpecialChangeEmail';
00201                         }
00202 
00203                         if( $wgEnableJavaScriptTest ) {
00204                                 self::$mList['JavaScriptTest'] = 'SpecialJavaScriptTest';
00205                         }
00206 
00207                         // Add extension special pages
00208                         self::$mList = array_merge( self::$mList, $wgSpecialPages );
00209 
00210                         // Run hooks
00211                         // This hook can be used to remove undesired built-in special pages
00212                         wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
00213 
00214                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00215                         settype( self::$mList, 'object' );
00216 
00217                         wfProfileOut( __METHOD__ );
00218                 }
00219                 return self::$mList;
00220         }
00221 
00230         static function getAliasList() {
00231                 if ( !is_object( self::$mAliases ) ) {
00232                         global $wgContLang;
00233                         $aliases = $wgContLang->getSpecialPageAliases();
00234 
00235                         // Objects are passed by reference by default, need to create a copy
00236                         $missingPages = clone self::getList();
00237 
00238                         self::$mAliases = array();
00239                         foreach ( $aliases as $realName => $aliasList ) {
00240                                 foreach ( $aliasList as $alias ) {
00241                                         self::$mAliases[$wgContLang->caseFold( $alias )] = $realName;
00242                                 }
00243                                 unset( $missingPages->$realName );
00244                         }
00245                         foreach ( $missingPages as $name => $stuff ) {
00246                                 self::$mAliases[$wgContLang->caseFold( $name )] = $name;
00247                         }
00248 
00249                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00250                         self::$mAliases = (object)self::$mAliases;
00251                 }
00252                 return self::$mAliases;
00253         }
00254 
00263         public static function resolveAlias( $alias ) {
00264                 global $wgContLang;
00265                 $bits = explode( '/', $alias, 2 );
00266 
00267                 $caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
00268                 $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
00269                 if ( isset( self::getAliasList()->$caseFoldedAlias ) ) {
00270                         $name = self::getAliasList()->$caseFoldedAlias;
00271                 } else {
00272                         return array( null, null );
00273                 }
00274 
00275                 if ( !isset( $bits[1] ) ) { // bug 2087
00276                         $par = null;
00277                 } else {
00278                         $par = $bits[1];
00279                 }
00280 
00281                 return array( $name, $par );
00282         }
00283 
00291         public static function setGroup( $page, $group ) {
00292                 wfDeprecated( __METHOD__, '1.21' );
00293 
00294                 global $wgSpecialPageGroups;
00295                 $name = is_object( $page ) ? $page->getName() : $page;
00296                 $wgSpecialPageGroups[$name] = $group;
00297         }
00298 
00306         public static function getGroup( &$page ) {
00307                 wfDeprecated( __METHOD__, '1.21' );
00308 
00309                 return $page->getFinalGroupName();
00310         }
00311 
00318         public static function exists( $name ) {
00319                 list( $title, /*...*/ ) = self::resolveAlias( $name );
00320                 return property_exists( self::getList(), $title );
00321         }
00322 
00329         public static function getPage( $name ) {
00330                 list( $realName, /*...*/ ) = self::resolveAlias( $name );
00331                 if ( property_exists( self::getList(), $realName ) ) {
00332                         $rec = self::getList()->$realName;
00333                         if ( is_string( $rec ) ) {
00334                                 $className = $rec;
00335                                 return new $className;
00336                         } elseif ( is_array( $rec ) ) {
00337                                 // @deprecated, officially since 1.18, unofficially since forever
00338                                 wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." );
00339                                 $className = array_shift( $rec );
00340                                 self::getList()->$realName = MWFunction::newObj( $className, $rec );
00341                         }
00342                         return self::getList()->$realName;
00343                 } else {
00344                         return null;
00345                 }
00346         }
00347 
00356         public static function getUsablePages( User $user = null ) {
00357                 $pages = array();
00358                 if ( $user === null ) {
00359                         global $wgUser;
00360                         $user = $wgUser;
00361                 }
00362                 foreach ( self::getList() as $name => $rec ) {
00363                         $page = self::getPage( $name );
00364                         if ( $page ) { // not null
00365                                 $page->setContext( RequestContext::getMain() );
00366                                 if ( $page->isListed()
00367                                         && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
00368                                 ) {
00369                                         $pages[$name] = $page;
00370                                 }
00371                         }
00372                 }
00373                 return $pages;
00374         }
00375 
00381         public static function getRegularPages() {
00382                 $pages = array();
00383                 foreach ( self::getList() as $name => $rec ) {
00384                         $page = self::getPage( $name );
00385                         if ( $page->isListed() && !$page->isRestricted() ) {
00386                                 $pages[$name] = $page;
00387                         }
00388                 }
00389                 return $pages;
00390         }
00391 
00398         public static function getRestrictedPages() {
00399                 global $wgUser;
00400                 $pages = array();
00401                 foreach ( self::getList() as $name => $rec ) {
00402                         $page = self::getPage( $name );
00403                         if (
00404                                 $page->isListed()
00405                                 && $page->isRestricted()
00406                                 && $page->userCanExecute( $wgUser )
00407                         ) {
00408                                 $pages[$name] = $page;
00409                         }
00410                 }
00411                 return $pages;
00412         }
00413 
00428         public static function executePath( Title &$title, IContextSource &$context, $including = false ) {
00429                 wfProfileIn( __METHOD__ );
00430 
00431                 // @todo FIXME: Redirects broken due to this call
00432                 $bits = explode( '/', $title->getDBkey(), 2 );
00433                 $name = $bits[0];
00434                 if ( !isset( $bits[1] ) ) { // bug 2087
00435                         $par = null;
00436                 } else {
00437                         $par = $bits[1];
00438                 }
00439                 $page = self::getPage( $name );
00440                 // Nonexistent?
00441                 if ( !$page ) {
00442                         $context->getOutput()->setArticleRelated( false );
00443                         $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
00444 
00445                         global $wgSend404Code;
00446                         if ( $wgSend404Code ) {
00447                                 $context->getOutput()->setStatusCode( 404 );
00448                         }
00449 
00450                         $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
00451                         wfProfileOut( __METHOD__ );
00452                         return false;
00453                 }
00454 
00455                 // Page exists, set the context
00456                 $page->setContext( $context );
00457 
00458                 if ( !$including ) {
00459                         // Redirect to canonical alias for GET commands
00460                         // Not for POST, we'd lose the post data, so it's best to just distribute
00461                         // the request. Such POST requests are possible for old extensions that
00462                         // generate self-links without being aware that their default name has
00463                         // changed.
00464                         if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
00465                                 $query = $context->getRequest()->getQueryValues();
00466                                 unset( $query['title'] );
00467                                 $query = wfArrayToCgi( $query );
00468                                 $title = $page->getTitle( $par );
00469                                 $url = $title->getFullUrl( $query );
00470                                 $context->getOutput()->redirect( $url );
00471                                 wfProfileOut( __METHOD__ );
00472                                 return $title;
00473                         } else {
00474                                 $context->setTitle( $page->getTitle( $par ) );
00475                         }
00476 
00477                 } elseif ( !$page->isIncludable() ) {
00478                         wfProfileOut( __METHOD__ );
00479                         return false;
00480                 }
00481 
00482                 $page->including( $including );
00483 
00484                 // Execute special page
00485                 $profName = 'Special:' . $page->getName();
00486                 wfProfileIn( $profName );
00487                 $page->run( $par );
00488                 wfProfileOut( $profName );
00489                 wfProfileOut( __METHOD__ );
00490                 return true;
00491         }
00492 
00508         static function capturePath( Title $title, IContextSource $context ) {
00509                 global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
00510 
00511                 // Save current globals
00512                 $oldTitle = $wgTitle;
00513                 $oldOut = $wgOut;
00514                 $oldRequest = $wgRequest;
00515                 $oldUser = $wgUser;
00516                 $oldLang = $wgLang;
00517 
00518                 // Set the globals to the current context
00519                 $wgTitle = $title;
00520                 $wgOut = $context->getOutput();
00521                 $wgRequest = $context->getRequest();
00522                 $wgUser = $context->getUser();
00523                 $wgLang = $context->getLanguage();
00524 
00525                 // The useful part
00526                 $ret = self::executePath( $title, $context, true );
00527 
00528                 // And restore the old globals
00529                 $wgTitle = $oldTitle;
00530                 $wgOut = $oldOut;
00531                 $wgRequest = $oldRequest;
00532                 $wgUser = $oldUser;
00533                 $wgLang = $oldLang;
00534 
00535                 return $ret;
00536         }
00537 
00546         static function getLocalNameFor( $name, $subpage = false ) {
00547                 global $wgContLang;
00548                 $aliases = $wgContLang->getSpecialPageAliases();
00549 
00550                 if ( isset( $aliases[$name][0] ) ) {
00551                         $name = $aliases[$name][0];
00552                 } else {
00553                         // Try harder in case someone misspelled the correct casing
00554                         $found = false;
00555                         foreach ( $aliases as $n => $values ) {
00556                                 if ( strcasecmp( $name, $n ) === 0 ) {
00557                                         wfWarn( "Found alias defined for $n when searching for " .
00558                                                 "special page aliases for $name. Case mismatch?" );
00559                                         $name = $values[0];
00560                                         $found = true;
00561                                         break;
00562                                 }
00563                         }
00564                         if ( !$found ) {
00565                                 wfWarn( "Did not find alias for special page '$name'. " .
00566                                         "Perhaps no aliases are defined for it?" );
00567                         }
00568                 }
00569                 if ( $subpage !== false && !is_null( $subpage ) ) {
00570                         $name = "$name/$subpage";
00571                 }
00572                 return $wgContLang->ucfirst( $name );
00573         }
00574 
00582         static function getTitleForAlias( $alias ) {
00583                 $name = self::resolveAlias( $alias );
00584                 if ( $name ) {
00585                         return SpecialPage::getTitleFor( $name );
00586                 } else {
00587                         return null;
00588                 }
00589         }
00590 }