MediaWiki  master
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 
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                 'Contributions'             => 'SpecialContributions',
00097                 'Listgrouprights'           => 'SpecialListGroupRights',
00098                 'Listusers'                 => 'SpecialListUsers' ,
00099                 'Listadmins'                => 'SpecialListAdmins',
00100                 'Listbots'                  => 'SpecialListBots',
00101                 'Activeusers'               => 'SpecialActiveUsers',
00102                 'Userrights'                => 'UserrightsPage',
00103                 'EditWatchlist'             => 'SpecialEditWatchlist',
00104 
00105                 // Recent changes and logs
00106                 'Newimages'                 => 'SpecialNewFiles',
00107                 'Log'                       => 'SpecialLog',
00108                 'Watchlist'                 => 'SpecialWatchlist',
00109                 'Newpages'                  => 'SpecialNewpages',
00110                 'Recentchanges'             => 'SpecialRecentchanges',
00111                 'Recentchangeslinked'       => 'SpecialRecentchangeslinked',
00112                 'Tags'                      => 'SpecialTags',
00113 
00114                 // Media reports and uploads
00115                 'Listfiles'                 => 'SpecialListFiles',
00116                 'Filepath'                  => 'SpecialFilepath',
00117                 'MIMEsearch'                => 'MIMEsearchPage',
00118                 'FileDuplicateSearch'       => 'FileDuplicateSearchPage',
00119                 'Upload'                    => 'SpecialUpload',
00120                 'UploadStash'               => 'SpecialUploadStash',
00121 
00122                 // Wiki data and tools
00123                 'Statistics'                => 'SpecialStatistics',
00124                 'Allmessages'               => 'SpecialAllmessages',
00125                 'Version'                   => 'SpecialVersion',
00126                 'Lockdb'                    => 'SpecialLockdb',
00127                 'Unlockdb'                  => 'SpecialUnlockdb',
00128 
00129                 // Redirecting special pages
00130                 'LinkSearch'                => 'LinkSearchPage',
00131                 'Randompage'                => 'Randompage',
00132                 'Randomredirect'            => 'SpecialRandomredirect',
00133 
00134                 // High use pages
00135                 'Mostlinkedcategories'      => 'MostlinkedCategoriesPage',
00136                 'Mostimages'                => 'MostimagesPage',
00137                 'Mostinterwikis'            => 'MostinterwikisPage',
00138                 'Mostlinked'                => 'MostlinkedPage',
00139                 'Mostlinkedtemplates'       => 'MostlinkedTemplatesPage',
00140                 'Mostcategories'            => 'MostcategoriesPage',
00141                 'Mostrevisions'             => 'MostrevisionsPage',
00142 
00143                 // Page tools
00144                 'ComparePages'              => 'SpecialComparePages',
00145                 'Export'                    => 'SpecialExport',
00146                 'Import'                    => 'SpecialImport',
00147                 'Undelete'                  => 'SpecialUndelete',
00148                 'Whatlinkshere'             => 'SpecialWhatlinkshere',
00149                 'MergeHistory'              => 'SpecialMergeHistory',
00150 
00151                 // Other
00152                 'Booksources'               => 'SpecialBookSources',
00153 
00154                 // Unlisted / redirects
00155                 'Blankpage'                 => 'SpecialBlankpage',
00156                 'Blockme'                   => 'SpecialBlockme',
00157                 'Emailuser'                 => 'SpecialEmailUser',
00158                 'Movepage'                  => 'MovePageForm',
00159                 'Mycontributions'           => 'SpecialMycontributions',
00160                 'Mypage'                    => 'SpecialMypage',
00161                 'Mytalk'                    => 'SpecialMytalk',
00162                 'Myuploads'                 => 'SpecialMyuploads',
00163                 'PermanentLink'             => 'SpecialPermanentLink',
00164                 'Revisiondelete'            => 'SpecialRevisionDelete',
00165                 'Specialpages'              => 'SpecialSpecialpages',
00166                 'Userlogout'                => 'SpecialUserlogout',
00167         );
00168 
00169         private static $mAliases;
00170 
00177         static function getList() {
00178                 global $wgSpecialPages;
00179                 global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
00180                 global $wgEnableEmail, $wgEnableJavaScriptTest;
00181 
00182                 if ( !is_object( self::$mList ) ) {
00183                         wfProfileIn( __METHOD__ );
00184 
00185                         if ( !$wgDisableCounters ) {
00186                                 self::$mList['Popularpages'] = 'PopularpagesPage';
00187                         }
00188 
00189                         if ( !$wgDisableInternalSearch ) {
00190                                 self::$mList['Search'] = 'SpecialSearch';
00191                         }
00192 
00193                         if ( $wgEmailAuthentication ) {
00194                                 self::$mList['Confirmemail'] = 'EmailConfirmation';
00195                                 self::$mList['Invalidateemail'] = 'EmailInvalidation';
00196                         }
00197 
00198                         if ( $wgEnableEmail ) {
00199                                 self::$mList['ChangeEmail'] = 'SpecialChangeEmail';
00200                         }
00201 
00202                         if( $wgEnableJavaScriptTest ) {
00203                                 self::$mList['JavaScriptTest'] = 'SpecialJavaScriptTest';
00204                         }
00205 
00206                         // Add extension special pages
00207                         self::$mList = array_merge( self::$mList, $wgSpecialPages );
00208 
00209                         // Run hooks
00210                         // This hook can be used to remove undesired built-in special pages
00211                         wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
00212 
00213                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00214                         settype( self::$mList, 'object' );
00215 
00216                         wfProfileOut( __METHOD__ );
00217                 }
00218                 return self::$mList;
00219         }
00220 
00229         static function getAliasList() {
00230                 if ( !is_object( self::$mAliases ) ) {
00231                         global $wgContLang;
00232                         $aliases = $wgContLang->getSpecialPageAliases();
00233 
00234                         // Objects are passed by reference by default, need to create a copy
00235                         $missingPages = clone self::getList();
00236 
00237                         self::$mAliases = array();
00238                         foreach ( $aliases as $realName => $aliasList ) {
00239                                 foreach ( $aliasList as $alias ) {
00240                                         self::$mAliases[$wgContLang->caseFold( $alias )] = $realName;
00241                                 }
00242                                 unset( $missingPages->$realName );
00243                         }
00244                         foreach ( $missingPages as $name => $stuff ) {
00245                                 self::$mAliases[$wgContLang->caseFold( $name )] = $name;
00246                         }
00247 
00248                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00249                         self::$mAliases = (object)self::$mAliases;
00250                 }
00251                 return self::$mAliases;
00252         }
00253 
00262         public static function resolveAlias( $alias ) {
00263                 global $wgContLang;
00264                 $bits = explode( '/', $alias, 2 );
00265 
00266                 $caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
00267                 $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
00268                 if ( isset( self::getAliasList()->$caseFoldedAlias ) ) {
00269                         $name = self::getAliasList()->$caseFoldedAlias;
00270                 } else {
00271                         return array( null, null );
00272                 }
00273 
00274                 if ( !isset( $bits[1] ) ) { // bug 2087
00275                         $par = null;
00276                 } else {
00277                         $par = $bits[1];
00278                 }
00279 
00280                 return array( $name, $par );
00281         }
00282 
00289         public static function setGroup( $page, $group ) {
00290                 global $wgSpecialPageGroups;
00291                 $name = is_object( $page ) ? $page->getName() : $page;
00292                 $wgSpecialPageGroups[$name] = $group;
00293         }
00294 
00301         public static function getGroup( &$page ) {
00302                 $name = $page->getName();
00303 
00304                 global $wgSpecialPageGroups;
00305                 static $specialPageGroupsCache = array();
00306                 if ( isset( $specialPageGroupsCache[$name] ) ) {
00307                         return $specialPageGroupsCache[$name];
00308                 }
00309                 $msg = wfMessage( 'specialpages-specialpagegroup-' . strtolower( $name ) );
00310                 if ( !$msg->isBlank() ) {
00311                         $group = $msg->text();
00312                 } else {
00313                         $group = isset( $wgSpecialPageGroups[$name] )
00314                                 ? $wgSpecialPageGroups[$name]
00315                                 : '-';
00316                 }
00317                 if ( $group == '-' ) {
00318                         $group = 'other';
00319                 }
00320                 $specialPageGroupsCache[$name] = $group;
00321                 return $group;
00322         }
00323 
00330         public static function exists( $name ) {
00331                 list( $title, /*...*/ ) = self::resolveAlias( $name );
00332                 return property_exists( self::getList(), $title );
00333         }
00334 
00341         public static function getPage( $name ) {
00342                 list( $realName, /*...*/ ) = self::resolveAlias( $name );
00343                 if ( property_exists( self::getList(), $realName ) ) {
00344                         $rec = self::getList()->$realName;
00345                         if ( is_string( $rec ) ) {
00346                                 $className = $rec;
00347                                 return new $className;
00348                         } elseif ( is_array( $rec ) ) {
00349                                 // @deprecated, officially since 1.18, unofficially since forever
00350                                 wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." );
00351                                 $className = array_shift( $rec );
00352                                 self::getList()->$realName = MWFunction::newObj( $className, $rec );
00353                         }
00354                         return self::getList()->$realName;
00355                 } else {
00356                         return null;
00357                 }
00358         }
00359 
00368         public static function getUsablePages( User $user = null ) {
00369                 $pages = array();
00370                 if ( $user === null ) {
00371                         global $wgUser;
00372                         $user = $wgUser;
00373                 }
00374                 foreach ( self::getList() as $name => $rec ) {
00375                         $page = self::getPage( $name );
00376                         if ( $page // not null
00377                                 && $page->isListed()
00378                                 && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
00379                         ) {
00380                                 $pages[$name] = $page;
00381                         }
00382                 }
00383                 return $pages;
00384         }
00385 
00391         public static function getRegularPages() {
00392                 $pages = array();
00393                 foreach ( self::getList() as $name => $rec ) {
00394                         $page = self::getPage( $name );
00395                         if ( $page->isListed() && !$page->isRestricted() ) {
00396                                 $pages[$name] = $page;
00397                         }
00398                 }
00399                 return $pages;
00400         }
00401 
00408         public static function getRestrictedPages() {
00409                 global $wgUser;
00410                 $pages = array();
00411                 foreach ( self::getList() as $name => $rec ) {
00412                         $page = self::getPage( $name );
00413                         if (
00414                                 $page->isListed()
00415                                 && $page->isRestricted()
00416                                 && $page->userCanExecute( $wgUser )
00417                         ) {
00418                                 $pages[$name] = $page;
00419                         }
00420                 }
00421                 return $pages;
00422         }
00423 
00438         public static function executePath( Title &$title, IContextSource &$context, $including = false ) {
00439                 wfProfileIn( __METHOD__ );
00440 
00441                 // @todo FIXME: Redirects broken due to this call
00442                 $bits = explode( '/', $title->getDBkey(), 2 );
00443                 $name = $bits[0];
00444                 if ( !isset( $bits[1] ) ) { // bug 2087
00445                         $par = null;
00446                 } else {
00447                         $par = $bits[1];
00448                 }
00449                 $page = self::getPage( $name );
00450                 // Nonexistent?
00451                 if ( !$page ) {
00452                         $context->getOutput()->setArticleRelated( false );
00453                         $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
00454 
00455                         global $wgSend404Code;
00456                         if ( $wgSend404Code ) {
00457                                 $context->getOutput()->setStatusCode( 404 );
00458                         }
00459 
00460                         $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
00461                         wfProfileOut( __METHOD__ );
00462                         return false;
00463                 }
00464 
00465                 // Page exists, set the context
00466                 $page->setContext( $context );
00467 
00468                 if ( !$including ) {
00469                         // Redirect to canonical alias for GET commands
00470                         // Not for POST, we'd lose the post data, so it's best to just distribute
00471                         // the request. Such POST requests are possible for old extensions that
00472                         // generate self-links without being aware that their default name has
00473                         // changed.
00474                         if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
00475                                 $query = $context->getRequest()->getQueryValues();
00476                                 unset( $query['title'] );
00477                                 $query = wfArrayToCGI( $query );
00478                                 $title = $page->getTitle( $par );
00479                                 $url = $title->getFullUrl( $query );
00480                                 $context->getOutput()->redirect( $url );
00481                                 wfProfileOut( __METHOD__ );
00482                                 return $title;
00483                         } else {
00484                                 $context->setTitle( $page->getTitle( $par ) );
00485                         }
00486 
00487                 } elseif ( !$page->isIncludable() ) {
00488                         wfProfileOut( __METHOD__ );
00489                         return false;
00490                 }
00491 
00492                 $page->including( $including );
00493 
00494                 // Execute special page
00495                 $profName = 'Special:' . $page->getName();
00496                 wfProfileIn( $profName );
00497                 $page->run( $par );
00498                 wfProfileOut( $profName );
00499                 wfProfileOut( __METHOD__ );
00500                 return true;
00501         }
00502 
00518         static function capturePath( Title $title, IContextSource $context ) {
00519                 global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
00520 
00521                 // Save current globals
00522                 $oldTitle = $wgTitle;
00523                 $oldOut = $wgOut;
00524                 $oldRequest = $wgRequest;
00525                 $oldUser = $wgUser;
00526                 $oldLang = $wgLang;
00527 
00528                 // Set the globals to the current context
00529                 $wgTitle = $title;
00530                 $wgOut = $context->getOutput();
00531                 $wgRequest = $context->getRequest();
00532                 $wgUser = $context->getUser();
00533                 $wgLang = $context->getLanguage();
00534 
00535                 // The useful part
00536                 $ret = self::executePath( $title, $context, true );
00537 
00538                 // And restore the old globals
00539                 $wgTitle = $oldTitle;
00540                 $wgOut = $oldOut;
00541                 $wgRequest = $oldRequest;
00542                 $wgUser = $oldUser;
00543                 $wgLang = $oldLang;
00544 
00545                 return $ret;
00546         }
00547 
00556         static function getLocalNameFor( $name, $subpage = false ) {
00557                 global $wgContLang;
00558                 $aliases = $wgContLang->getSpecialPageAliases();
00559 
00560                 if ( isset( $aliases[$name][0] ) ) {
00561                         $name = $aliases[$name][0];
00562                 } else {
00563                         // Try harder in case someone misspelled the correct casing
00564                         $found = false;
00565                         foreach ( $aliases as $n => $values ) {
00566                                 if ( strcasecmp( $name, $n ) === 0 ) {
00567                                         wfWarn( "Found alias defined for $n when searching for " .
00568                                                 "special page aliases for $name. Case mismatch?" );
00569                                         $name = $values[0];
00570                                         $found = true;
00571                                         break;
00572                                 }
00573                         }
00574                         if ( !$found ) {
00575                                 wfWarn( "Did not find alias for special page '$name'. " .
00576                                         "Perhaps no aliases are defined for it?" );
00577                         }
00578                 }
00579                 if ( $subpage !== false && !is_null( $subpage ) ) {
00580                         $name = "$name/$subpage";
00581                 }
00582                 return $wgContLang->ucfirst( $name );
00583         }
00584 
00592         static function getTitleForAlias( $alias ) {
00593                 $name = self::resolveAlias( $alias );
00594                 if ( $name ) {
00595                         return SpecialPage::getTitleFor( $name );
00596                 } else {
00597                         return null;
00598                 }
00599         }
00600 }