MediaWiki
REL1_21
|
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 }