54 'BrokenRedirects' => BrokenRedirectsPage::class,
55 'Deadendpages' => DeadendPagesPage::class,
56 'DoubleRedirects' => DoubleRedirectsPage::class,
57 'Longpages' => LongPagesPage::class,
58 'Ancientpages' => AncientPagesPage::class,
59 'Lonelypages' => LonelyPagesPage::class,
60 'Fewestrevisions' => FewestrevisionsPage::class,
61 'Withoutinterwiki' => WithoutInterwikiPage::class,
62 'Protectedpages' => SpecialProtectedpages::class,
63 'Protectedtitles' => SpecialProtectedtitles::class,
64 'Shortpages' => ShortPagesPage::class,
65 'Uncategorizedcategories' => UncategorizedCategoriesPage::class,
66 'Uncategorizedimages' => UncategorizedImagesPage::class,
67 'Uncategorizedpages' => UncategorizedPagesPage::class,
68 'Uncategorizedtemplates' => UncategorizedTemplatesPage::class,
69 'Unusedcategories' => UnusedCategoriesPage::class,
70 'Unusedimages' => UnusedimagesPage::class,
71 'Unusedtemplates' => UnusedtemplatesPage::class,
72 'Unwatchedpages' => UnwatchedpagesPage::class,
73 'Wantedcategories' => WantedCategoriesPage::class,
74 'Wantedfiles' => WantedFilesPage::class,
75 'Wantedpages' => WantedPagesPage::class,
76 'Wantedtemplates' => WantedTemplatesPage::class,
79 'Allpages' => SpecialAllPages::class,
80 'Prefixindex' => SpecialPrefixindex::class,
81 'Categories' => SpecialCategories::class,
82 'Listredirects' => ListredirectsPage::class,
83 'PagesWithProp' => SpecialPagesWithProp::class,
84 'TrackingCategories' => SpecialTrackingCategories::class,
87 'Userlogin' => SpecialUserLogin::class,
88 'Userlogout' => SpecialUserLogout::class,
89 'CreateAccount' => SpecialCreateAccount::class,
90 'LinkAccounts' => SpecialLinkAccounts::class,
91 'UnlinkAccounts' => SpecialUnlinkAccounts::class,
92 'ChangeCredentials' => SpecialChangeCredentials::class,
93 'RemoveCredentials' => SpecialRemoveCredentials::class,
96 'Activeusers' => SpecialActiveUsers::class,
97 'Block' => SpecialBlock::class,
98 'Unblock' => SpecialUnblock::class,
99 'BlockList' => SpecialBlockList::class,
100 'AutoblockList' => SpecialAutoblockList::class,
101 'ChangePassword' => SpecialChangePassword::class,
102 'BotPasswords' => SpecialBotPasswords::class,
103 'PasswordReset' => SpecialPasswordReset::class,
104 'DeletedContributions' => DeletedContributionsPage::class,
105 'Preferences' => SpecialPreferences::class,
106 'ResetTokens' => SpecialResetTokens::class,
107 'Contributions' => SpecialContributions::class,
108 'Listgrouprights' => SpecialListGroupRights::class,
109 'Listgrants' => SpecialListGrants::class,
110 'Listusers' => SpecialListUsers::class,
111 'Listadmins' => SpecialListAdmins::class,
112 'Listbots' => SpecialListBots::class,
113 'Userrights' => UserrightsPage::class,
114 'EditWatchlist' => SpecialEditWatchlist::class,
117 'Newimages' => SpecialNewFiles::class,
118 'Log' => SpecialLog::class,
119 'Watchlist' => SpecialWatchlist::class,
120 'Newpages' => SpecialNewpages::class,
121 'Recentchanges' => SpecialRecentChanges::class,
122 'Recentchangeslinked' => SpecialRecentChangesLinked::class,
123 'Tags' => SpecialTags::class,
126 'Listfiles' => SpecialListFiles::class,
127 'Filepath' => SpecialFilepath::class,
128 'MediaStatistics' => MediaStatisticsPage::class,
129 'MIMEsearch' => MIMEsearchPage::class,
130 'FileDuplicateSearch' => FileDuplicateSearchPage::class,
131 'Upload' => SpecialUpload::class,
132 'UploadStash' => SpecialUploadStash::class,
133 'ListDuplicatedFiles' => ListDuplicatedFilesPage::class,
136 'ApiSandbox' => SpecialApiSandbox::class,
137 'Statistics' => SpecialStatistics::class,
138 'Allmessages' => SpecialAllMessages::class,
139 'Version' => SpecialVersion::class,
140 'Lockdb' => SpecialLockdb::class,
141 'Unlockdb' => SpecialUnlockdb::class,
144 'LinkSearch' => LinkSearchPage::class,
145 'Randompage' => RandomPage::class,
146 'RandomInCategory' => SpecialRandomInCategory::class,
147 'Randomredirect' => SpecialRandomredirect::class,
148 'Randomrootpage' => SpecialRandomrootpage::class,
149 'GoToInterwiki' => SpecialGoToInterwiki::class,
152 'Mostlinkedcategories' => MostlinkedCategoriesPage::class,
153 'Mostimages' => MostimagesPage::class,
154 'Mostinterwikis' => MostinterwikisPage::class,
155 'Mostlinked' => MostlinkedPage::class,
156 'Mostlinkedtemplates' => MostlinkedTemplatesPage::class,
157 'Mostcategories' => MostcategoriesPage::class,
158 'Mostrevisions' => MostrevisionsPage::class,
161 'ComparePages' => SpecialComparePages::class,
162 'Export' => SpecialExport::class,
163 'Import' => SpecialImport::class,
164 'Undelete' => SpecialUndelete::class,
165 'Whatlinkshere' => SpecialWhatLinksHere::class,
166 'MergeHistory' => SpecialMergeHistory::class,
167 'ExpandTemplates' => SpecialExpandTemplates::class,
170 'Booksources' => SpecialBookSources::class,
173 'ApiHelp' => SpecialApiHelp::class,
174 'Blankpage' => SpecialBlankpage::class,
175 'Diff' => SpecialDiff::class,
176 'EditTags' => SpecialEditTags::class,
177 'Emailuser' => SpecialEmailUser::class,
178 'Movepage' => MovePageForm::class,
179 'Mycontributions' => SpecialMycontributions::class,
180 'MyLanguage' => SpecialMyLanguage::class,
181 'Mypage' => SpecialMypage::class,
182 'Mytalk' => SpecialMytalk::class,
183 'Myuploads' => SpecialMyuploads::class,
184 'AllMyUploads' => SpecialAllMyUploads::class,
185 'PermanentLink' => SpecialPermanentLink::class,
186 'Redirect' => SpecialRedirect::class,
187 'Revisiondelete' => SpecialRevisionDelete::class,
188 'RunJobs' => SpecialRunJobs::class,
189 'Specialpages' => SpecialSpecialpages::class,
190 'PageData' => SpecialPageData::class,
202 self::$aliases =
null;
212 return array_keys( self::getPageList() );
226 if ( !is_array( self::$list ) ) {
230 self::$list[
'Search'] = SpecialSearch::class;
234 self::$list[
'Confirmemail'] = EmailConfirmation::class;
235 self::$list[
'Invalidateemail'] = EmailInvalidation::class;
239 self::$list[
'ChangeEmail'] = SpecialChangeEmail::class;
243 self::$list[
'JavaScriptTest'] = SpecialJavaScriptTest::class;
247 self::$list[
'PageLanguage'] = SpecialPageLanguage::class;
250 self::$list[
'ChangeContentModel'] = SpecialChangeContentModel::class;
258 Hooks::run(
'SpecialPage_initList', [ &self::$list ] );
272 if ( is_null( self::$aliases ) ) {
281 foreach ( $pageList as $name => $stuff ) {
283 self::$aliases[$caseFoldedAlias] =
$name;
284 $keepAlias[$caseFoldedAlias] =
'canonical';
289 foreach (
$aliases as $realName => $aliasList ) {
290 $aliasList = array_values( $aliasList );
291 foreach ( $aliasList as $i => $alias ) {
292 $caseFoldedAlias =
$wgContLang->caseFold( $alias );
294 if ( isset( self::$aliases[$caseFoldedAlias] ) &&
295 $realName === self::$aliases[$caseFoldedAlias]
301 if ( !isset( $keepAlias[$caseFoldedAlias] ) ) {
302 self::$aliases[$caseFoldedAlias] = $realName;
304 $keepAlias[$caseFoldedAlias] =
'first';
307 wfWarn(
"First alias '$alias' for $realName conflicts with " .
308 "{$keepAlias[$caseFoldedAlias]} alias for " .
309 self::$aliases[$caseFoldedAlias]
330 $bits = explode(
'/', $alias, 2 );
332 $caseFoldedAlias =
$wgContLang->caseFold( $bits[0] );
333 $caseFoldedAlias = str_replace(
' ',
'_', $caseFoldedAlias );
335 if ( isset(
$aliases[$caseFoldedAlias] ) ) {
338 return [
null, null ];
341 if ( !isset( $bits[1] ) ) {
347 return [
$name, $par ];
360 return isset( $specialPageList[$title] );
374 if ( isset( $specialPageList[$realName] ) ) {
375 $rec = $specialPageList[$realName];
377 if ( is_callable( $rec ) ) {
379 $page = call_user_func( $rec );
380 } elseif ( is_string( $rec ) ) {
382 $page =
new $className;
383 } elseif ( is_array( $rec ) ) {
384 $className = array_shift( $rec );
386 wfDeprecated(
"Array syntax for \$wgSpecialPages is deprecated ($className), " .
387 "define a subclass of SpecialPage instead.",
'1.18' );
388 $page = ObjectFactory::getObjectFromSpec( [
389 'class' => $className,
391 'closure_expansion' =>
false,
404 wfLogWarning(
"Cannot instantiate special page $realName: bad spec!" );
423 if ( $user ===
null ) {
427 foreach ( self::getPageList() as $name => $rec ) {
431 if ( $page->isListed()
432 && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
434 $pages[
$name] = $page;
449 foreach ( self::getPageList() as $name => $rec ) {
451 if ( $page && $page->isListed() && !$page->isRestricted() ) {
452 $pages[
$name] = $page;
468 if ( $user ===
null ) {
472 foreach ( self::getPageList() as $name => $rec ) {
476 && $page->isRestricted()
477 && $page->userCanExecute( $user )
479 $pages[
$name] = $page;
505 $bits = explode(
'/', $title->getDBkey(), 2 );
507 if ( !isset( $bits[1] ) ) {
515 $context->getOutput()->setArticleRelated(
false );
516 $context->getOutput()->setRobotPolicy(
'noindex,nofollow' );
520 $context->getOutput()->setStatusCode( 404 );
523 $context->getOutput()->showErrorPage(
'nosuchspecialpage',
'nospecialpagetext' );
530 $trxLimits =
$context->getConfig()->get(
'TrxProfilerLimits' );
531 $trxProfiler = Profiler::instance()->getTransactionProfiler();
532 if (
$context->getRequest()->wasPosted() && !$page->doesWrites() ) {
533 $trxProfiler->setExpectations( $trxLimits[
'POST-nonwrite'], __METHOD__ );
534 $context->getRequest()->markAsSafeRequest();
547 if ( $name != $page->getLocalName() && !
$context->getRequest()->wasPosted() ) {
550 $title = $page->getPageTitle( $par );
551 $url = $title->getFullURL(
$query );
552 $context->getOutput()->redirect( $url );
556 $context->setTitle( $page->getPageTitle( $par ) );
558 } elseif ( !$page->isIncludable() ) {
562 $page->including( $including );
603 'title' => $main->getTitle(),
604 'output' => $main->getOutput(),
605 'request' => $main->getRequest(),
606 'user' => $main->getUser(),
607 'language' => $main->getLanguage(),
616 $main->setTitle( $title );
617 $main->setOutput(
$context->getOutput() );
618 $main->setRequest(
$context->getRequest() );
619 $main->setUser(
$context->getUser() );
620 $main->setLanguage(
$context->getLanguage() );
631 $main->setTitle( $ctx[
'title'] );
632 $main->setOutput( $ctx[
'output'] );
633 $main->setRequest( $ctx[
'request'] );
634 $main->setUser( $ctx[
'user'] );
635 $main->setLanguage( $ctx[
'language'] );
655 foreach (
$aliases[$name] as $alias ) {
656 $caseFoldedAlias =
$wgContLang->caseFold( $alias );
657 $caseFoldedAlias = str_replace(
' ',
'_', $caseFoldedAlias );
658 if ( isset( $aliasList[$caseFoldedAlias] ) &&
659 $aliasList[$caseFoldedAlias] === $name
667 wfWarn(
"Did not find a usable alias for special page '$name'. " .
668 "It seems all defined aliases conflict?" );
673 foreach (
$aliases as $n => $values ) {
674 if ( strcasecmp( $name, $n ) === 0 ) {
675 wfWarn(
"Found alias defined for $n when searching for " .
676 "special page aliases for $name. Case mismatch?" );
682 wfWarn(
"Did not find alias for special page '$name'. " .
683 "Perhaps no aliases are defined for it?" );
686 if ( $subpage !==
false && !is_null( $subpage ) ) {
688 $subpage = str_replace(
' ',
'_', $subpage );
689 $name =
"$name/$subpage";
703 if ( $name !=
null ) {
704 return SpecialPage::getTitleFor( $name, $subpage );