MediaWiki  REL1_19
SpecialPageFactory.php
Go to the documentation of this file.
00001 <?php
00030 class SpecialPageFactory {
00031 
00035         private static $mList = array(
00036                 // Maintenance Reports
00037                 'BrokenRedirects'           => 'BrokenRedirectsPage',
00038                 'Deadendpages'              => 'DeadendpagesPage',
00039                 'DoubleRedirects'           => 'DoubleRedirectsPage',
00040                 'Longpages'                 => 'LongpagesPage',
00041                 'Ancientpages'              => 'AncientpagesPage',
00042                 'Lonelypages'               => 'LonelypagesPage',
00043                 'Fewestrevisions'           => 'FewestrevisionsPage',
00044                 'Withoutinterwiki'          => 'WithoutinterwikiPage',
00045                 'Protectedpages'            => 'SpecialProtectedpages',
00046                 'Protectedtitles'           => 'SpecialProtectedtitles',
00047                 'Shortpages'                => 'ShortpagesPage',
00048                 'Uncategorizedcategories'   => 'UncategorizedcategoriesPage',
00049                 'Uncategorizedimages'       => 'UncategorizedimagesPage',
00050                 'Uncategorizedpages'        => 'UncategorizedpagesPage',
00051                 'Uncategorizedtemplates'    => 'UncategorizedtemplatesPage',
00052                 'Unusedcategories'          => 'UnusedcategoriesPage',
00053                 'Unusedimages'              => 'UnusedimagesPage',
00054                 'Unusedtemplates'           => 'UnusedtemplatesPage',
00055                 'Unwatchedpages'            => 'UnwatchedpagesPage',
00056                 'Wantedcategories'          => 'WantedcategoriesPage',
00057                 'Wantedfiles'               => 'WantedfilesPage',
00058                 'Wantedpages'               => 'WantedpagesPage',
00059                 'Wantedtemplates'           => 'WantedtemplatesPage',
00060 
00061                 // List of pages
00062                 'Allpages'                  => 'SpecialAllpages',
00063                 'Prefixindex'               => 'SpecialPrefixindex',
00064                 'Categories'                => 'SpecialCategories',
00065                 'Disambiguations'           => 'DisambiguationsPage',
00066                 'Listredirects'             => 'ListredirectsPage',
00067 
00068                 // Login/create account
00069                 'Userlogin'                 => 'LoginForm',
00070                 'CreateAccount'             => 'SpecialCreateAccount',
00071 
00072                 // Users and rights
00073                 'Block'                     => 'SpecialBlock',
00074                 'Unblock'                   => 'SpecialUnblock',
00075                 'BlockList'                 => 'SpecialBlockList',
00076                 'ChangePassword'            => 'SpecialChangePassword',
00077                 'PasswordReset'             => 'SpecialPasswordReset',
00078                 'DeletedContributions'      => 'DeletedContributionsPage',
00079                 'Preferences'               => 'SpecialPreferences',
00080                 'Contributions'             => 'SpecialContributions',
00081                 'Listgrouprights'           => 'SpecialListGroupRights',
00082                 'Listusers'                 => 'SpecialListUsers' ,
00083                 'Listadmins'                => 'SpecialListAdmins',
00084                 'Listbots'                  => 'SpecialListBots',
00085                 'Activeusers'               => 'SpecialActiveUsers',
00086                 'Userrights'                => 'UserrightsPage',
00087                 'EditWatchlist'             => 'SpecialEditWatchlist',
00088 
00089                 // Recent changes and logs
00090                 'Newimages'                 => 'SpecialNewFiles',
00091                 'Log'                       => 'SpecialLog',
00092                 'Watchlist'                 => 'SpecialWatchlist',
00093                 'Newpages'                  => 'SpecialNewpages',
00094                 'Recentchanges'             => 'SpecialRecentchanges',
00095                 'Recentchangeslinked'       => 'SpecialRecentchangeslinked',
00096                 'Tags'                      => 'SpecialTags',
00097 
00098                 // Media reports and uploads
00099                 'Listfiles'                 => 'SpecialListFiles',
00100                 'Filepath'                  => 'SpecialFilepath',
00101                 'MIMEsearch'                => 'MIMEsearchPage',
00102                 'FileDuplicateSearch'       => 'FileDuplicateSearchPage',
00103                 'Upload'                    => 'SpecialUpload',
00104                 'UploadStash'               => 'SpecialUploadStash',
00105 
00106                 // Wiki data and tools
00107                 'Statistics'                => 'SpecialStatistics',
00108                 'Allmessages'               => 'SpecialAllmessages',
00109                 'Version'                   => 'SpecialVersion',
00110                 'Lockdb'                    => 'SpecialLockdb',
00111                 'Unlockdb'                  => 'SpecialUnlockdb',
00112 
00113                 // Redirecting special pages
00114                 'LinkSearch'                => 'LinkSearchPage',
00115                 'Randompage'                => 'Randompage',
00116                 'Randomredirect'            => 'SpecialRandomredirect',
00117 
00118                 // High use pages
00119                 'Mostlinkedcategories'      => 'MostlinkedCategoriesPage',
00120                 'Mostimages'                => 'MostimagesPage',
00121                 'Mostlinked'                => 'MostlinkedPage',
00122                 'Mostlinkedtemplates'       => 'MostlinkedTemplatesPage',
00123                 'Mostcategories'            => 'MostcategoriesPage',
00124                 'Mostrevisions'             => 'MostrevisionsPage',
00125 
00126                 // Page tools
00127                 'ComparePages'              => 'SpecialComparePages',
00128                 'Export'                    => 'SpecialExport',
00129                 'Import'                    => 'SpecialImport',
00130                 'Undelete'                  => 'SpecialUndelete',
00131                 'Whatlinkshere'             => 'SpecialWhatlinkshere',
00132                 'MergeHistory'              => 'SpecialMergeHistory',
00133 
00134                 // Other
00135                 'Booksources'               => 'SpecialBookSources',
00136 
00137                 // Unlisted / redirects
00138                 'Blankpage'                 => 'SpecialBlankpage',
00139                 'Blockme'                   => 'SpecialBlockme',
00140                 'Emailuser'                 => 'SpecialEmailUser',
00141                 'JavaScriptTest'            => 'SpecialJavaScriptTest',
00142                 'Movepage'                  => 'MovePageForm',
00143                 'Mycontributions'           => 'SpecialMycontributions',
00144                 'Mypage'                    => 'SpecialMypage',
00145                 'Mytalk'                    => 'SpecialMytalk',
00146                 'Myuploads'                 => 'SpecialMyuploads',
00147                 'PermanentLink'             => 'SpecialPermanentLink',
00148                 'Revisiondelete'            => 'SpecialRevisionDelete',
00149                 'Specialpages'              => 'SpecialSpecialpages',
00150                 'Userlogout'                => 'SpecialUserlogout',
00151         );
00152 
00153         private static $mAliases;
00154 
00161         static function getList() {
00162                 global $wgSpecialPages;
00163                 global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
00164                 global $wgEnableEmail;
00165 
00166                 if ( !is_object( self::$mList ) ) {
00167                         wfProfileIn( __METHOD__ );
00168 
00169                         if ( !$wgDisableCounters ) {
00170                                 self::$mList['Popularpages'] = 'PopularpagesPage';
00171                         }
00172 
00173                         if ( !$wgDisableInternalSearch ) {
00174                                 self::$mList['Search'] = 'SpecialSearch';
00175                         }
00176 
00177                         if ( $wgEmailAuthentication ) {
00178                                 self::$mList['Confirmemail'] = 'EmailConfirmation';
00179                                 self::$mList['Invalidateemail'] = 'EmailInvalidation';
00180                         }
00181 
00182                         if ( $wgEnableEmail ) {
00183                                 self::$mList['ChangeEmail'] = 'SpecialChangeEmail';
00184                         }
00185 
00186                         // Add extension special pages
00187                         self::$mList = array_merge( self::$mList, $wgSpecialPages );
00188 
00189                         // Run hooks
00190                         // This hook can be used to remove undesired built-in special pages
00191                         wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
00192 
00193                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00194                         settype( self::$mList, 'object' );
00195 
00196                         wfProfileOut( __METHOD__ );
00197                 }
00198                 return self::$mList;
00199         }
00200 
00209         static function getAliasList() {
00210                 if ( !is_object( self::$mAliases ) ) {
00211                         global $wgContLang;
00212                         $aliases = $wgContLang->getSpecialPageAliases();
00213 
00214                         // Objects are passed by reference by default, need to create a copy
00215                         $missingPages = clone self::getList();
00216 
00217                         self::$mAliases = array();
00218                         foreach ( $aliases as $realName => $aliasList ) {
00219                                 foreach ( $aliasList as $alias ) {
00220                                         self::$mAliases[$wgContLang->caseFold( $alias )] = $realName;
00221                                 }
00222                                 unset( $missingPages->$realName );
00223                         }
00224                         foreach ( $missingPages as $name => $stuff ) {
00225                                 self::$mAliases[$wgContLang->caseFold( $name )] = $name;
00226                         }
00227 
00228                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00229                         self::$mAliases = (object)self::$mAliases;
00230                 }
00231                 return self::$mAliases;
00232         }
00233 
00242         public static function resolveAlias( $alias ) {
00243                 global $wgContLang;
00244                 $bits = explode( '/', $alias, 2 );
00245 
00246                 $caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
00247                 $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
00248                 if ( isset( self::getAliasList()->$caseFoldedAlias ) ) {
00249                         $name = self::getAliasList()->$caseFoldedAlias;
00250                 } else {
00251                         return array( null, null );
00252                 }
00253 
00254                 if ( !isset( $bits[1] ) ) { // bug 2087
00255                         $par = null;
00256                 } else {
00257                         $par = $bits[1];
00258                 }
00259 
00260                 return array( $name, $par );
00261         }
00262 
00269         public static function setGroup( $page, $group ) {
00270                 global $wgSpecialPageGroups;
00271                 $name = is_object( $page ) ? $page->getName() : $page;
00272                 $wgSpecialPageGroups[$name] = $group;
00273         }
00274 
00280         public static function getGroup( &$page ) {
00281                 $name = $page->getName();
00282 
00283                 global $wgSpecialPageGroups;
00284                 static $specialPageGroupsCache = array();
00285                 if ( isset( $specialPageGroupsCache[$name] ) ) {
00286                         return $specialPageGroupsCache[$name];
00287                 }
00288                 $msg = wfMessage( 'specialpages-specialpagegroup-' . strtolower( $name ) );
00289                 if ( !$msg->isBlank() ) {
00290                         $group = $msg->text();
00291                 } else {
00292                         $group = isset( $wgSpecialPageGroups[$name] )
00293                                 ? $wgSpecialPageGroups[$name]
00294                                 : '-';
00295                 }
00296                 if ( $group == '-' ) {
00297                         $group = 'other';
00298                 }
00299                 $specialPageGroupsCache[$name] = $group;
00300                 return $group;
00301         }
00302 
00309         public static function exists( $name ) {
00310                 list( $title, /*...*/ ) = self::resolveAlias( $name );
00311                 return property_exists( self::getList(), $title );
00312         }
00313 
00320         public static function getPage( $name ) {
00321                 list( $realName, /*...*/ ) = self::resolveAlias( $name );
00322                 if ( property_exists( self::getList(), $realName ) ) {
00323                         $rec = self::getList()->$realName;
00324                         if ( is_string( $rec ) ) {
00325                                 $className = $rec;
00326                                 return new $className;
00327                         } elseif ( is_array( $rec ) ) {
00328                                 // @deprecated, officially since 1.18, unofficially since forever
00329                                 wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." );
00330                                 $className = array_shift( $rec );
00331                                 self::getList()->$realName = MWFunction::newObj( $className, $rec );
00332                         }
00333                         return self::getList()->$realName;
00334                 } else {
00335                         return null;
00336                 }
00337         }
00338 
00347         public static function getUsablePages( User $user = null ) {
00348                 $pages = array();
00349                 if ( $user === null ) {
00350                         global $wgUser;
00351                         $user = $wgUser;
00352                 }
00353                 foreach ( self::getList() as $name => $rec ) {
00354                         $page = self::getPage( $name );
00355                         if ( $page // not null
00356                                 && $page->isListed()
00357                                 && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
00358                         ) {
00359                                 $pages[$name] = $page;
00360                         }
00361                 }
00362                 return $pages;
00363         }
00364 
00370         public static function getRegularPages() {
00371                 $pages = array();
00372                 foreach ( self::getList() as $name => $rec ) {
00373                         $page = self::getPage( $name );
00374                         if ( $page->isListed() && !$page->isRestricted() ) {
00375                                 $pages[$name] = $page;
00376                         }
00377                 }
00378                 return $pages;
00379         }
00380 
00387         public static function getRestrictedPages() {
00388                 global $wgUser;
00389                 $pages = array();
00390                 foreach ( self::getList() as $name => $rec ) {
00391                         $page = self::getPage( $name );
00392                         if (
00393                                 $page->isListed()
00394                                 && $page->isRestricted()
00395                                 && $page->userCanExecute( $wgUser )
00396                         ) {
00397                                 $pages[$name] = $page;
00398                         }
00399                 }
00400                 return $pages;
00401         }
00402 
00417         public static function executePath( Title &$title, IContextSource &$context, $including = false ) {
00418                 wfProfileIn( __METHOD__ );
00419 
00420                 // @todo FIXME: Redirects broken due to this call
00421                 $bits = explode( '/', $title->getDBkey(), 2 );
00422                 $name = $bits[0];
00423                 if ( !isset( $bits[1] ) ) { // bug 2087
00424                         $par = null;
00425                 } else {
00426                         $par = $bits[1];
00427                 }
00428                 $page = self::getPage( $name );
00429                 // Nonexistent?
00430                 if ( !$page ) {
00431                         $context->getOutput()->setArticleRelated( false );
00432                         $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
00433 
00434                         global $wgSend404Code;
00435                         if ( $wgSend404Code ) {
00436                                 $context->getOutput()->setStatusCode( 404 );
00437                         }
00438 
00439                         $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
00440                         wfProfileOut( __METHOD__ );
00441                         return false;
00442                 }
00443 
00444                 // Page exists, set the context
00445                 $page->setContext( $context );
00446 
00447                 if ( !$including ) {
00448                         // Redirect to canonical alias for GET commands
00449                         // Not for POST, we'd lose the post data, so it's best to just distribute
00450                         // the request. Such POST requests are possible for old extensions that
00451                         // generate self-links without being aware that their default name has
00452                         // changed.
00453                         if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
00454                                 $query = $context->getRequest()->getQueryValues();
00455                                 unset( $query['title'] );
00456                                 $query = wfArrayToCGI( $query );
00457                                 $title = $page->getTitle( $par );
00458                                 $url = $title->getFullUrl( $query );
00459                                 $context->getOutput()->redirect( $url );
00460                                 wfProfileOut( __METHOD__ );
00461                                 return $title;
00462                         } else {
00463                                 $context->setTitle( $page->getTitle( $par ) );
00464                         }
00465 
00466                 } elseif ( !$page->isIncludable() ) {
00467                         wfProfileOut( __METHOD__ );
00468                         return false;
00469                 }
00470 
00471                 $page->including( $including );
00472 
00473                 // Execute special page
00474                 $profName = 'Special:' . $page->getName();
00475                 wfProfileIn( $profName );
00476                 $page->execute( $par );
00477                 wfProfileOut( $profName );
00478                 wfProfileOut( __METHOD__ );
00479                 return true;
00480         }
00481 
00497         static function capturePath( Title $title, IContextSource $context ) {
00498                 global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
00499 
00500                 // Save current globals
00501                 $oldTitle = $wgTitle;
00502                 $oldOut = $wgOut;
00503                 $oldRequest = $wgRequest;
00504                 $oldUser = $wgUser;
00505                 $oldLang = $wgLang;
00506 
00507                 // Set the globals to the current context
00508                 $wgTitle = $title;
00509                 $wgOut = $context->getOutput();
00510                 $wgRequest = $context->getRequest();
00511                 $wgUser = $context->getUser();
00512                 $wgLang = $context->getLanguage();
00513 
00514                 // The useful part
00515                 $ret = self::executePath( $title, $context, true );
00516 
00517                 // And restore the old globals
00518                 $wgTitle = $oldTitle;
00519                 $wgOut = $oldOut;
00520                 $wgRequest = $oldRequest;
00521                 $wgUser = $oldUser;
00522                 $wgLang = $oldLang;
00523 
00524                 return $ret;
00525         }
00526 
00535         static function getLocalNameFor( $name, $subpage = false ) {
00536                 global $wgContLang;
00537                 $aliases = $wgContLang->getSpecialPageAliases();
00538 
00539                 if ( isset( $aliases[$name][0] ) ) {
00540                         $name = $aliases[$name][0];
00541                 } else {
00542                         // Try harder in case someone misspelled the correct casing
00543                         $found = false;
00544                         foreach ( $aliases as $n => $values ) {
00545                                 if ( strcasecmp( $name, $n ) === 0 ) {
00546                                         wfWarn( "Found alias defined for $n when searching for " .
00547                                                 "special page aliases for $name. Case mismatch?" );
00548                                         $name = $values[0];
00549                                         $found = true;
00550                                         break;
00551                                 }
00552                         }
00553                         if ( !$found ) {
00554                                 wfWarn( "Did not find alias for special page '$name'. " .
00555                                         "Perhaps no aliases are defined for it?" );
00556                         }
00557                 }
00558                 if ( $subpage !== false && !is_null( $subpage ) ) {
00559                         $name = "$name/$subpage";
00560                 }
00561                 return $wgContLang->ucfirst( $name );
00562         }
00563 
00571         static function getTitleForAlias( $alias ) {
00572                 $name = self::resolveAlias( $alias );
00573                 if ( $name ) {
00574                         return SpecialPage::getTitleFor( $name );
00575                 } else {
00576                         return null;
00577                 }
00578         }
00579 }