MediaWiki  REL1_20
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                 'JavaScriptTest'            => 'SpecialJavaScriptTest',
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;
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                         // Add extension special pages
00204                         self::$mList = array_merge( self::$mList, $wgSpecialPages );
00205 
00206                         // Run hooks
00207                         // This hook can be used to remove undesired built-in special pages
00208                         wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
00209 
00210                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00211                         settype( self::$mList, 'object' );
00212 
00213                         wfProfileOut( __METHOD__ );
00214                 }
00215                 return self::$mList;
00216         }
00217 
00226         static function getAliasList() {
00227                 if ( !is_object( self::$mAliases ) ) {
00228                         global $wgContLang;
00229                         $aliases = $wgContLang->getSpecialPageAliases();
00230 
00231                         // Objects are passed by reference by default, need to create a copy
00232                         $missingPages = clone self::getList();
00233 
00234                         self::$mAliases = array();
00235                         foreach ( $aliases as $realName => $aliasList ) {
00236                                 foreach ( $aliasList as $alias ) {
00237                                         self::$mAliases[$wgContLang->caseFold( $alias )] = $realName;
00238                                 }
00239                                 unset( $missingPages->$realName );
00240                         }
00241                         foreach ( $missingPages as $name => $stuff ) {
00242                                 self::$mAliases[$wgContLang->caseFold( $name )] = $name;
00243                         }
00244 
00245                         // Cast to object: func()[$key] doesn't work, but func()->$key does
00246                         self::$mAliases = (object)self::$mAliases;
00247                 }
00248                 return self::$mAliases;
00249         }
00250 
00259         public static function resolveAlias( $alias ) {
00260                 global $wgContLang;
00261                 $bits = explode( '/', $alias, 2 );
00262 
00263                 $caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
00264                 $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
00265                 if ( isset( self::getAliasList()->$caseFoldedAlias ) ) {
00266                         $name = self::getAliasList()->$caseFoldedAlias;
00267                 } else {
00268                         return array( null, null );
00269                 }
00270 
00271                 if ( !isset( $bits[1] ) ) { // bug 2087
00272                         $par = null;
00273                 } else {
00274                         $par = $bits[1];
00275                 }
00276 
00277                 return array( $name, $par );
00278         }
00279 
00286         public static function setGroup( $page, $group ) {
00287                 global $wgSpecialPageGroups;
00288                 $name = is_object( $page ) ? $page->getName() : $page;
00289                 $wgSpecialPageGroups[$name] = $group;
00290         }
00291 
00298         public static function getGroup( &$page ) {
00299                 $name = $page->getName();
00300 
00301                 global $wgSpecialPageGroups;
00302                 static $specialPageGroupsCache = array();
00303                 if ( isset( $specialPageGroupsCache[$name] ) ) {
00304                         return $specialPageGroupsCache[$name];
00305                 }
00306                 $msg = wfMessage( 'specialpages-specialpagegroup-' . strtolower( $name ) );
00307                 if ( !$msg->isBlank() ) {
00308                         $group = $msg->text();
00309                 } else {
00310                         $group = isset( $wgSpecialPageGroups[$name] )
00311                                 ? $wgSpecialPageGroups[$name]
00312                                 : '-';
00313                 }
00314                 if ( $group == '-' ) {
00315                         $group = 'other';
00316                 }
00317                 $specialPageGroupsCache[$name] = $group;
00318                 return $group;
00319         }
00320 
00327         public static function exists( $name ) {
00328                 list( $title, /*...*/ ) = self::resolveAlias( $name );
00329                 return property_exists( self::getList(), $title );
00330         }
00331 
00338         public static function getPage( $name ) {
00339                 list( $realName, /*...*/ ) = self::resolveAlias( $name );
00340                 if ( property_exists( self::getList(), $realName ) ) {
00341                         $rec = self::getList()->$realName;
00342                         if ( is_string( $rec ) ) {
00343                                 $className = $rec;
00344                                 return new $className;
00345                         } elseif ( is_array( $rec ) ) {
00346                                 // @deprecated, officially since 1.18, unofficially since forever
00347                                 wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." );
00348                                 $className = array_shift( $rec );
00349                                 self::getList()->$realName = MWFunction::newObj( $className, $rec );
00350                         }
00351                         return self::getList()->$realName;
00352                 } else {
00353                         return null;
00354                 }
00355         }
00356 
00365         public static function getUsablePages( User $user = null ) {
00366                 $pages = array();
00367                 if ( $user === null ) {
00368                         global $wgUser;
00369                         $user = $wgUser;
00370                 }
00371                 foreach ( self::getList() as $name => $rec ) {
00372                         $page = self::getPage( $name );
00373                         if ( $page // not null
00374                                 && $page->isListed()
00375                                 && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
00376                         ) {
00377                                 $pages[$name] = $page;
00378                         }
00379                 }
00380                 return $pages;
00381         }
00382 
00388         public static function getRegularPages() {
00389                 $pages = array();
00390                 foreach ( self::getList() as $name => $rec ) {
00391                         $page = self::getPage( $name );
00392                         if ( $page->isListed() && !$page->isRestricted() ) {
00393                                 $pages[$name] = $page;
00394                         }
00395                 }
00396                 return $pages;
00397         }
00398 
00405         public static function getRestrictedPages() {
00406                 global $wgUser;
00407                 $pages = array();
00408                 foreach ( self::getList() as $name => $rec ) {
00409                         $page = self::getPage( $name );
00410                         if (
00411                                 $page->isListed()
00412                                 && $page->isRestricted()
00413                                 && $page->userCanExecute( $wgUser )
00414                         ) {
00415                                 $pages[$name] = $page;
00416                         }
00417                 }
00418                 return $pages;
00419         }
00420 
00435         public static function executePath( Title &$title, IContextSource &$context, $including = false ) {
00436                 wfProfileIn( __METHOD__ );
00437 
00438                 // @todo FIXME: Redirects broken due to this call
00439                 $bits = explode( '/', $title->getDBkey(), 2 );
00440                 $name = $bits[0];
00441                 if ( !isset( $bits[1] ) ) { // bug 2087
00442                         $par = null;
00443                 } else {
00444                         $par = $bits[1];
00445                 }
00446                 $page = self::getPage( $name );
00447                 // Nonexistent?
00448                 if ( !$page ) {
00449                         $context->getOutput()->setArticleRelated( false );
00450                         $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
00451 
00452                         global $wgSend404Code;
00453                         if ( $wgSend404Code ) {
00454                                 $context->getOutput()->setStatusCode( 404 );
00455                         }
00456 
00457                         $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
00458                         wfProfileOut( __METHOD__ );
00459                         return false;
00460                 }
00461 
00462                 // Page exists, set the context
00463                 $page->setContext( $context );
00464 
00465                 if ( !$including ) {
00466                         // Redirect to canonical alias for GET commands
00467                         // Not for POST, we'd lose the post data, so it's best to just distribute
00468                         // the request. Such POST requests are possible for old extensions that
00469                         // generate self-links without being aware that their default name has
00470                         // changed.
00471                         if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
00472                                 $query = $context->getRequest()->getQueryValues();
00473                                 unset( $query['title'] );
00474                                 $query = wfArrayToCGI( $query );
00475                                 $title = $page->getTitle( $par );
00476                                 $url = $title->getFullUrl( $query );
00477                                 $context->getOutput()->redirect( $url );
00478                                 wfProfileOut( __METHOD__ );
00479                                 return $title;
00480                         } else {
00481                                 $context->setTitle( $page->getTitle( $par ) );
00482                         }
00483 
00484                 } elseif ( !$page->isIncludable() ) {
00485                         wfProfileOut( __METHOD__ );
00486                         return false;
00487                 }
00488 
00489                 $page->including( $including );
00490 
00491                 // Execute special page
00492                 $profName = 'Special:' . $page->getName();
00493                 wfProfileIn( $profName );
00494                 $page->run( $par );
00495                 wfProfileOut( $profName );
00496                 wfProfileOut( __METHOD__ );
00497                 return true;
00498         }
00499 
00515         static function capturePath( Title $title, IContextSource $context ) {
00516                 global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
00517 
00518                 // Save current globals
00519                 $oldTitle = $wgTitle;
00520                 $oldOut = $wgOut;
00521                 $oldRequest = $wgRequest;
00522                 $oldUser = $wgUser;
00523                 $oldLang = $wgLang;
00524 
00525                 // Set the globals to the current context
00526                 $wgTitle = $title;
00527                 $wgOut = $context->getOutput();
00528                 $wgRequest = $context->getRequest();
00529                 $wgUser = $context->getUser();
00530                 $wgLang = $context->getLanguage();
00531 
00532                 // The useful part
00533                 $ret = self::executePath( $title, $context, true );
00534 
00535                 // And restore the old globals
00536                 $wgTitle = $oldTitle;
00537                 $wgOut = $oldOut;
00538                 $wgRequest = $oldRequest;
00539                 $wgUser = $oldUser;
00540                 $wgLang = $oldLang;
00541 
00542                 return $ret;
00543         }
00544 
00553         static function getLocalNameFor( $name, $subpage = false ) {
00554                 global $wgContLang;
00555                 $aliases = $wgContLang->getSpecialPageAliases();
00556 
00557                 if ( isset( $aliases[$name][0] ) ) {
00558                         $name = $aliases[$name][0];
00559                 } else {
00560                         // Try harder in case someone misspelled the correct casing
00561                         $found = false;
00562                         foreach ( $aliases as $n => $values ) {
00563                                 if ( strcasecmp( $name, $n ) === 0 ) {
00564                                         wfWarn( "Found alias defined for $n when searching for " .
00565                                                 "special page aliases for $name. Case mismatch?" );
00566                                         $name = $values[0];
00567                                         $found = true;
00568                                         break;
00569                                 }
00570                         }
00571                         if ( !$found ) {
00572                                 wfWarn( "Did not find alias for special page '$name'. " .
00573                                         "Perhaps no aliases are defined for it?" );
00574                         }
00575                 }
00576                 if ( $subpage !== false && !is_null( $subpage ) ) {
00577                         $name = "$name/$subpage";
00578                 }
00579                 return $wgContLang->ucfirst( $name );
00580         }
00581 
00589         static function getTitleForAlias( $alias ) {
00590                 $name = self::resolveAlias( $alias );
00591                 if ( $name ) {
00592                         return SpecialPage::getTitleFor( $name );
00593                 } else {
00594                         return null;
00595                 }
00596         }
00597 }