MediaWiki
REL1_24
|
00001 <?php 00046 class SpecialPageFactory { 00050 private static $list = array( 00051 // Maintenance Reports 00052 'BrokenRedirects' => 'BrokenRedirectsPage', 00053 'Deadendpages' => 'DeadendPagesPage', 00054 'DoubleRedirects' => 'DoubleRedirectsPage', 00055 'Longpages' => 'LongPagesPage', 00056 'Ancientpages' => 'AncientPagesPage', 00057 'Lonelypages' => 'LonelyPagesPage', 00058 'Fewestrevisions' => 'FewestrevisionsPage', 00059 'Withoutinterwiki' => 'WithoutInterwikiPage', 00060 'Protectedpages' => 'SpecialProtectedpages', 00061 'Protectedtitles' => 'SpecialProtectedtitles', 00062 'Shortpages' => 'ShortpagesPage', 00063 'Uncategorizedcategories' => 'UncategorizedCategoriesPage', 00064 'Uncategorizedimages' => 'UncategorizedImagesPage', 00065 'Uncategorizedpages' => 'UncategorizedPagesPage', 00066 'Uncategorizedtemplates' => 'UncategorizedTemplatesPage', 00067 'Unusedcategories' => 'UnusedCategoriesPage', 00068 'Unusedimages' => 'UnusedimagesPage', 00069 'Unusedtemplates' => 'UnusedtemplatesPage', 00070 'Unwatchedpages' => 'UnwatchedpagesPage', 00071 'Wantedcategories' => 'WantedCategoriesPage', 00072 'Wantedfiles' => 'WantedFilesPage', 00073 'Wantedpages' => 'WantedPagesPage', 00074 'Wantedtemplates' => 'WantedTemplatesPage', 00075 00076 // List of pages 00077 'Allpages' => 'SpecialAllpages', 00078 'Prefixindex' => 'SpecialPrefixindex', 00079 'Categories' => 'SpecialCategories', 00080 'Listredirects' => 'ListredirectsPage', 00081 'PagesWithProp' => 'SpecialPagesWithProp', 00082 'TrackingCategories' => 'SpecialTrackingCategories', 00083 00084 // Login/create account 00085 'Userlogin' => 'LoginForm', 00086 'CreateAccount' => 'SpecialCreateAccount', 00087 00088 // Users and rights 00089 'Block' => 'SpecialBlock', 00090 'Unblock' => 'SpecialUnblock', 00091 'BlockList' => 'SpecialBlockList', 00092 'ChangePassword' => 'SpecialChangePassword', 00093 'PasswordReset' => 'SpecialPasswordReset', 00094 'DeletedContributions' => 'DeletedContributionsPage', 00095 'Preferences' => 'SpecialPreferences', 00096 'ResetTokens' => 'SpecialResetTokens', 00097 'Contributions' => 'SpecialContributions', 00098 'Listgrouprights' => 'SpecialListGroupRights', 00099 'Listusers' => 'SpecialListUsers', 00100 'Listadmins' => 'SpecialListAdmins', 00101 'Listbots' => 'SpecialListBots', 00102 '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 'MediaStatistics' => 'MediaStatisticsPage', 00118 'MIMEsearch' => 'MIMEsearchPage', 00119 'FileDuplicateSearch' => 'FileDuplicateSearchPage', 00120 'Upload' => 'SpecialUpload', 00121 'UploadStash' => 'SpecialUploadStash', 00122 'ListDuplicatedFiles' => 'ListDuplicatedFilesPage', 00123 00124 // Data and tools 00125 'Statistics' => 'SpecialStatistics', 00126 'Allmessages' => 'SpecialAllmessages', 00127 'Version' => 'SpecialVersion', 00128 'Lockdb' => 'SpecialLockdb', 00129 'Unlockdb' => 'SpecialUnlockdb', 00130 00131 // Redirecting special pages 00132 'LinkSearch' => 'LinkSearchPage', 00133 'Randompage' => 'RandomPage', 00134 'RandomInCategory' => 'SpecialRandomInCategory', 00135 'Randomredirect' => 'SpecialRandomredirect', 00136 00137 // High use pages 00138 'Mostlinkedcategories' => 'MostlinkedCategoriesPage', 00139 'Mostimages' => 'MostimagesPage', 00140 'Mostinterwikis' => 'MostinterwikisPage', 00141 'Mostlinked' => 'MostlinkedPage', 00142 'Mostlinkedtemplates' => 'MostlinkedTemplatesPage', 00143 'Mostcategories' => 'MostcategoriesPage', 00144 'Mostrevisions' => 'MostrevisionsPage', 00145 00146 // Page tools 00147 'ComparePages' => 'SpecialComparePages', 00148 'Export' => 'SpecialExport', 00149 'Import' => 'SpecialImport', 00150 'Undelete' => 'SpecialUndelete', 00151 'Whatlinkshere' => 'SpecialWhatLinksHere', 00152 'MergeHistory' => 'SpecialMergeHistory', 00153 'ExpandTemplates' => 'SpecialExpandTemplates', 00154 00155 // Other 00156 'Booksources' => 'SpecialBookSources', 00157 00158 // Unlisted / redirects 00159 'Blankpage' => 'SpecialBlankpage', 00160 'Diff' => 'SpecialDiff', 00161 'Emailuser' => 'SpecialEmailUser', 00162 'Movepage' => 'MovePageForm', 00163 'Mycontributions' => 'SpecialMycontributions', 00164 'MyLanguage' => 'SpecialMyLanguage', 00165 'Mypage' => 'SpecialMypage', 00166 'Mytalk' => 'SpecialMytalk', 00167 'Myuploads' => 'SpecialMyuploads', 00168 'AllMyUploads' => 'SpecialAllMyUploads', 00169 'PermanentLink' => 'SpecialPermanentLink', 00170 'Redirect' => 'SpecialRedirect', 00171 'Revisiondelete' => 'SpecialRevisionDelete', 00172 'RunJobs' => 'SpecialRunJobs', 00173 'Specialpages' => 'SpecialSpecialpages', 00174 'Userlogout' => 'SpecialUserlogout', 00175 ); 00176 00177 private static $aliases; 00178 00183 public static function resetList() { 00184 self::$list = null; 00185 self::$aliases = null; 00186 } 00187 00194 public static function getNames() { 00195 return array_keys( self::getPageList() ); 00196 } 00197 00204 public static function getList() { 00205 wfDeprecated( __FUNCTION__, '1.24' ); 00206 return self::getPageList(); 00207 } 00208 00214 private static function getPageList() { 00215 global $wgSpecialPages; 00216 global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication; 00217 global $wgEnableEmail, $wgEnableJavaScriptTest; 00218 global $wgPageLanguageUseDB; 00219 00220 if ( !is_object( self::$list ) ) { 00221 wfProfileIn( __METHOD__ ); 00222 00223 if ( !$wgDisableCounters ) { 00224 self::$list['Popularpages'] = 'PopularPagesPage'; 00225 } 00226 00227 if ( !$wgDisableInternalSearch ) { 00228 self::$list['Search'] = 'SpecialSearch'; 00229 } 00230 00231 if ( $wgEmailAuthentication ) { 00232 self::$list['Confirmemail'] = 'EmailConfirmation'; 00233 self::$list['Invalidateemail'] = 'EmailInvalidation'; 00234 } 00235 00236 if ( $wgEnableEmail ) { 00237 self::$list['ChangeEmail'] = 'SpecialChangeEmail'; 00238 } 00239 00240 if ( $wgEnableJavaScriptTest ) { 00241 self::$list['JavaScriptTest'] = 'SpecialJavaScriptTest'; 00242 } 00243 00244 if ( $wgPageLanguageUseDB ) { 00245 self::$list['PageLanguage'] = 'SpecialPageLanguage'; 00246 } 00247 00248 self::$list['Activeusers'] = 'SpecialActiveUsers'; 00249 00250 // Add extension special pages 00251 self::$list = array_merge( self::$list, $wgSpecialPages ); 00252 00253 // Run hooks 00254 // This hook can be used to remove undesired built-in special pages 00255 wfRunHooks( 'SpecialPage_initList', array( &self::$list ) ); 00256 00257 wfProfileOut( __METHOD__ ); 00258 } 00259 00260 return self::$list; 00261 } 00262 00271 private static function getAliasListObject() { 00272 if ( !is_object( self::$aliases ) ) { 00273 global $wgContLang; 00274 $aliases = $wgContLang->getSpecialPageAliases(); 00275 00276 $missingPages = self::getPageList(); 00277 00278 self::$aliases = array(); 00279 // Check for $aliases being an array since Language::getSpecialPageAliases can return null 00280 if ( is_array( $aliases ) ) { 00281 foreach ( $aliases as $realName => $aliasList ) { 00282 foreach ( $aliasList as $alias ) { 00283 self::$aliases[$wgContLang->caseFold( $alias )] = $realName; 00284 } 00285 unset( $missingPages->$realName ); 00286 } 00287 } 00288 foreach ( $missingPages as $name => $stuff ) { 00289 self::$aliases[$wgContLang->caseFold( $name )] = $name; 00290 } 00291 00292 // Cast to object: func()[$key] doesn't work, but func()->$key does 00293 self::$aliases = (object)self::$aliases; 00294 } 00295 00296 return self::$aliases; 00297 } 00298 00307 public static function resolveAlias( $alias ) { 00308 global $wgContLang; 00309 $bits = explode( '/', $alias, 2 ); 00310 00311 $caseFoldedAlias = $wgContLang->caseFold( $bits[0] ); 00312 $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias ); 00313 if ( isset( self::getAliasListObject()->$caseFoldedAlias ) ) { 00314 $name = self::getAliasListObject()->$caseFoldedAlias; 00315 } else { 00316 return array( null, null ); 00317 } 00318 00319 if ( !isset( $bits[1] ) ) { // bug 2087 00320 $par = null; 00321 } else { 00322 $par = $bits[1]; 00323 } 00324 00325 return array( $name, $par ); 00326 } 00327 00335 public static function setGroup( $page, $group ) { 00336 wfDeprecated( __METHOD__, '1.21' ); 00337 00338 global $wgSpecialPageGroups; 00339 $name = is_object( $page ) ? $page->getName() : $page; 00340 $wgSpecialPageGroups[$name] = $group; 00341 } 00342 00350 public static function getGroup( &$page ) { 00351 wfDeprecated( __METHOD__, '1.21' ); 00352 00353 return $page->getFinalGroupName(); 00354 } 00355 00362 public static function exists( $name ) { 00363 list( $title, /*...*/ ) = self::resolveAlias( $name ); 00364 00365 $specialPageList = self::getPageList(); 00366 return isset( $specialPageList[$title] ); 00367 } 00368 00375 public static function getPage( $name ) { 00376 list( $realName, /*...*/ ) = self::resolveAlias( $name ); 00377 00378 $specialPageList = self::getPageList(); 00379 00380 if ( isset( $specialPageList[$realName] ) ) { 00381 $rec = $specialPageList[$realName]; 00382 00383 if ( is_string( $rec ) ) { 00384 $className = $rec; 00385 $page = new $className; 00386 } elseif ( is_callable( $rec ) ) { 00387 // Use callback to instantiate the special page 00388 $page = call_user_func( $rec ); 00389 } elseif ( is_array( $rec ) ) { 00390 $className = array_shift( $rec ); 00391 // @deprecated, officially since 1.18, unofficially since forever 00392 wfDeprecated( "Array syntax for \$wgSpecialPages is deprecated ($className), " . 00393 "define a subclass of SpecialPage instead.", '1.18' ); 00394 $page = MWFunction::newObj( $className, $rec ); 00395 } elseif ( $rec instanceof SpecialPage ) { 00396 $page = $rec; //XXX: we should deep clone here 00397 } else { 00398 $page = null; 00399 } 00400 00401 if ( $page instanceof SpecialPage ) { 00402 return $page; 00403 } else { 00404 // It's not a classname, nor a callback, nor a legacy constructor array, 00405 // nor a special page object. Give up. 00406 wfLogWarning( "Cannot instantiate special page $realName: bad spec!" ); 00407 return null; 00408 } 00409 00410 } else { 00411 return null; 00412 } 00413 } 00414 00423 public static function getUsablePages( User $user = null ) { 00424 $pages = array(); 00425 if ( $user === null ) { 00426 global $wgUser; 00427 $user = $wgUser; 00428 } 00429 foreach ( self::getPageList() as $name => $rec ) { 00430 $page = self::getPage( $name ); 00431 if ( $page ) { // not null 00432 $page->setContext( RequestContext::getMain() ); 00433 if ( $page->isListed() 00434 && ( !$page->isRestricted() || $page->userCanExecute( $user ) ) 00435 ) { 00436 $pages[$name] = $page; 00437 } 00438 } 00439 } 00440 00441 return $pages; 00442 } 00443 00449 public static function getRegularPages() { 00450 $pages = array(); 00451 foreach ( self::getPageList() as $name => $rec ) { 00452 $page = self::getPage( $name ); 00453 if ( $page->isListed() && !$page->isRestricted() ) { 00454 $pages[$name] = $page; 00455 } 00456 } 00457 00458 return $pages; 00459 } 00460 00468 public static function getRestrictedPages( User $user = null ) { 00469 $pages = array(); 00470 if ( $user === null ) { 00471 global $wgUser; 00472 $user = $wgUser; 00473 } 00474 foreach ( self::getPageList() as $name => $rec ) { 00475 $page = self::getPage( $name ); 00476 if ( 00477 $page->isListed() 00478 && $page->isRestricted() 00479 && $page->userCanExecute( $user ) 00480 ) { 00481 $pages[$name] = $page; 00482 } 00483 } 00484 00485 return $pages; 00486 } 00487 00502 public static function executePath( Title &$title, IContextSource &$context, $including = false ) { 00503 wfProfileIn( __METHOD__ ); 00504 00505 // @todo FIXME: Redirects broken due to this call 00506 $bits = explode( '/', $title->getDBkey(), 2 ); 00507 $name = $bits[0]; 00508 if ( !isset( $bits[1] ) ) { // bug 2087 00509 $par = null; 00510 } else { 00511 $par = $bits[1]; 00512 } 00513 $page = self::getPage( $name ); 00514 // Nonexistent? 00515 if ( !$page ) { 00516 $context->getOutput()->setArticleRelated( false ); 00517 $context->getOutput()->setRobotPolicy( 'noindex,nofollow' ); 00518 00519 global $wgSend404Code; 00520 if ( $wgSend404Code ) { 00521 $context->getOutput()->setStatusCode( 404 ); 00522 } 00523 00524 $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); 00525 wfProfileOut( __METHOD__ ); 00526 00527 return false; 00528 } 00529 00530 // Page exists, set the context 00531 $page->setContext( $context ); 00532 00533 if ( !$including ) { 00534 // Redirect to canonical alias for GET commands 00535 // Not for POST, we'd lose the post data, so it's best to just distribute 00536 // the request. Such POST requests are possible for old extensions that 00537 // generate self-links without being aware that their default name has 00538 // changed. 00539 if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) { 00540 $query = $context->getRequest()->getQueryValues(); 00541 unset( $query['title'] ); 00542 $title = $page->getPageTitle( $par ); 00543 $url = $title->getFullURL( $query ); 00544 $context->getOutput()->redirect( $url ); 00545 wfProfileOut( __METHOD__ ); 00546 00547 return $title; 00548 } else { 00549 $context->setTitle( $page->getPageTitle( $par ) ); 00550 } 00551 } elseif ( !$page->isIncludable() ) { 00552 wfProfileOut( __METHOD__ ); 00553 00554 return false; 00555 } 00556 00557 $page->including( $including ); 00558 00559 // Execute special page 00560 $profName = 'Special:' . $page->getName(); 00561 wfProfileIn( $profName ); 00562 $page->run( $par ); 00563 wfProfileOut( $profName ); 00564 wfProfileOut( __METHOD__ ); 00565 00566 return true; 00567 } 00568 00583 public static function capturePath( Title $title, IContextSource $context ) { 00584 global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang; 00585 00586 // Save current globals 00587 $oldTitle = $wgTitle; 00588 $oldOut = $wgOut; 00589 $oldRequest = $wgRequest; 00590 $oldUser = $wgUser; 00591 $oldLang = $wgLang; 00592 00593 // Set the globals to the current context 00594 $wgTitle = $title; 00595 $wgOut = $context->getOutput(); 00596 $wgRequest = $context->getRequest(); 00597 $wgUser = $context->getUser(); 00598 $wgLang = $context->getLanguage(); 00599 00600 // The useful part 00601 $ret = self::executePath( $title, $context, true ); 00602 00603 // And restore the old globals 00604 $wgTitle = $oldTitle; 00605 $wgOut = $oldOut; 00606 $wgRequest = $oldRequest; 00607 $wgUser = $oldUser; 00608 $wgLang = $oldLang; 00609 00610 return $ret; 00611 } 00612 00620 public static function getLocalNameFor( $name, $subpage = false ) { 00621 global $wgContLang; 00622 $aliases = $wgContLang->getSpecialPageAliases(); 00623 00624 if ( isset( $aliases[$name][0] ) ) { 00625 $name = $aliases[$name][0]; 00626 } else { 00627 // Try harder in case someone misspelled the correct casing 00628 $found = false; 00629 // Check for $aliases being an array since Language::getSpecialPageAliases can return null 00630 if ( is_array( $aliases ) ) { 00631 foreach ( $aliases as $n => $values ) { 00632 if ( strcasecmp( $name, $n ) === 0 ) { 00633 wfWarn( "Found alias defined for $n when searching for " . 00634 "special page aliases for $name. Case mismatch?" ); 00635 $name = $values[0]; 00636 $found = true; 00637 break; 00638 } 00639 } 00640 } 00641 if ( !$found ) { 00642 wfWarn( "Did not find alias for special page '$name'. " . 00643 "Perhaps no aliases are defined for it?" ); 00644 } 00645 } 00646 if ( $subpage !== false && !is_null( $subpage ) ) { 00647 $name = "$name/$subpage"; 00648 } 00649 00650 return $wgContLang->ucfirst( $name ); 00651 } 00652 00659 public static function getTitleForAlias( $alias ) { 00660 list( $name, $subpage ) = self::resolveAlias( $alias ); 00661 if ( $name != null ) { 00662 return SpecialPage::getTitleFor( $name, $subpage ); 00663 } else { 00664 return null; 00665 } 00666 } 00667 }