MediaWiki  master
SpecialPageFactory.php
Go to the documentation of this file.
1 <?php
26 
27 use Hooks;
28 use IContextSource;
29 use Language;
32 use Profiler;
33 use RequestContext;
34 use SpecialPage;
35 use Title;
36 use User;
38 
68  private const CORE_LIST = [
69  // Maintenance Reports
70  'BrokenRedirects' => \SpecialBrokenRedirects::class,
71  'Deadendpages' => \SpecialDeadendPages::class,
72  'DoubleRedirects' => \SpecialDoubleRedirects::class,
73  'Longpages' => \SpecialLongPages::class,
74  'Ancientpages' => \SpecialAncientPages::class,
75  'Lonelypages' => \SpecialLonelyPages::class,
76  'Fewestrevisions' => \SpecialFewestRevisions::class,
77  'Withoutinterwiki' => \SpecialWithoutInterwiki::class,
78  'Protectedpages' => \SpecialProtectedpages::class,
79  'Protectedtitles' => \SpecialProtectedtitles::class,
80  'Shortpages' => \SpecialShortPages::class,
81  'Uncategorizedcategories' => \SpecialUncategorizedCategories::class,
82  'Uncategorizedimages' => \SpecialUncategorizedImages::class,
83  'Uncategorizedpages' => \SpecialUncategorizedPages::class,
84  'Uncategorizedtemplates' => \SpecialUncategorizedTemplates::class,
85  'Unusedcategories' => \SpecialUnusedCategories::class,
86  'Unusedimages' => \SpecialUnusedImages::class,
87  'Unusedtemplates' => \SpecialUnusedTemplates::class,
88  'Unwatchedpages' => \SpecialUnwatchedPages::class,
89  'Wantedcategories' => \SpecialWantedCategories::class,
90  'Wantedfiles' => \WantedFilesPage::class,
91  'Wantedpages' => \WantedPagesPage::class,
92  'Wantedtemplates' => \SpecialWantedTemplates::class,
93 
94  // List of pages
95  'Allpages' => \SpecialAllPages::class,
96  'Prefixindex' => \SpecialPrefixindex::class,
97  'Categories' => \SpecialCategories::class,
98  'Listredirects' => \SpecialListRedirects::class,
99  'PagesWithProp' => \SpecialPagesWithProp::class,
100  'TrackingCategories' => \SpecialTrackingCategories::class,
101 
102  // Authentication
103  'Userlogin' => \SpecialUserLogin::class,
104  'Userlogout' => \SpecialUserLogout::class,
105  'CreateAccount' => \SpecialCreateAccount::class,
106  'LinkAccounts' => \SpecialLinkAccounts::class,
107  'UnlinkAccounts' => \SpecialUnlinkAccounts::class,
108  'ChangeCredentials' => \SpecialChangeCredentials::class,
109  'RemoveCredentials' => \SpecialRemoveCredentials::class,
110 
111  // Users and rights
112  'Activeusers' => \SpecialActiveUsers::class,
113  'Block' => \SpecialBlock::class,
114  'Unblock' => \SpecialUnblock::class,
115  'BlockList' => \SpecialBlockList::class,
116  'AutoblockList' => \SpecialAutoblockList::class,
117  'ChangePassword' => \SpecialChangePassword::class,
118  'BotPasswords' => \SpecialBotPasswords::class,
119  'PasswordReset' => \SpecialPasswordReset::class,
120  'DeletedContributions' => \SpecialDeletedContributions::class,
121  'Preferences' => \SpecialPreferences::class,
122  'ResetTokens' => \SpecialResetTokens::class,
123  'Contributions' => \SpecialContributions::class,
124  'Listgrouprights' => \SpecialListGroupRights::class,
125  'Listgrants' => \SpecialListGrants::class,
126  'Listusers' => \SpecialListUsers::class,
127  'Listadmins' => \SpecialListAdmins::class,
128  'Listbots' => \SpecialListBots::class,
129  'Userrights' => \UserrightsPage::class,
130  'EditWatchlist' => \SpecialEditWatchlist::class,
131  'PasswordPolicies' => \SpecialPasswordPolicies::class,
132 
133  // Recent changes and logs
134  'Newimages' => \SpecialNewFiles::class,
135  'Log' => \SpecialLog::class,
136  'Watchlist' => \SpecialWatchlist::class,
137  'Newpages' => \SpecialNewpages::class,
138  'Recentchanges' => \SpecialRecentChanges::class,
139  'Recentchangeslinked' => \SpecialRecentChangesLinked::class,
140  'Tags' => \SpecialTags::class,
141 
142  // Media reports and uploads
143  'Listfiles' => \SpecialListFiles::class,
144  'Filepath' => \SpecialFilepath::class,
145  'MediaStatistics' => \SpecialMediaStatistics::class,
146  'MIMEsearch' => \SpecialMIMESearch::class,
147  'FileDuplicateSearch' => \SpecialFileDuplicateSearch::class,
148  'Upload' => \SpecialUpload::class,
149  'UploadStash' => \SpecialUploadStash::class,
150  'ListDuplicatedFiles' => \SpecialListDuplicatedFiles::class,
151 
152  // Data and tools
153  'ApiSandbox' => \SpecialApiSandbox::class,
154  'Statistics' => \SpecialStatistics::class,
155  'Allmessages' => \SpecialAllMessages::class,
156  'Version' => \SpecialVersion::class,
157  'Lockdb' => \SpecialLockdb::class,
158  'Unlockdb' => \SpecialUnlockdb::class,
159 
160  // Redirecting special pages
161  'LinkSearch' => \SpecialLinkSearch::class,
162  'Randompage' => \RandomPage::class,
163  'RandomInCategory' => \SpecialRandomInCategory::class,
164  'Randomredirect' => \SpecialRandomredirect::class,
165  'Randomrootpage' => \SpecialRandomrootpage::class,
166  'GoToInterwiki' => \SpecialGoToInterwiki::class,
167 
168  // High use pages
169  'Mostlinkedcategories' => \SpecialMostLinkedCategories::class,
170  'Mostimages' => \MostimagesPage::class,
171  'Mostinterwikis' => \SpecialMostInterwikis::class,
172  'Mostlinked' => \SpecialMostLinked::class,
173  'Mostlinkedtemplates' => \SpecialMostLinkedTemplates::class,
174  'Mostcategories' => \SpecialMostCategories::class,
175  'Mostrevisions' => \SpecialMostRevisions::class,
176 
177  // Page tools
178  'ComparePages' => \SpecialComparePages::class,
179  'Export' => \SpecialExport::class,
180  'Import' => \SpecialImport::class,
181  'Undelete' => \SpecialUndelete::class,
182  'Whatlinkshere' => \SpecialWhatLinksHere::class,
183  'MergeHistory' => \SpecialMergeHistory::class,
184  'ExpandTemplates' => \SpecialExpandTemplates::class,
185 
186  // Other
187  'Booksources' => \SpecialBookSources::class,
188 
189  // Unlisted / redirects
190  'ApiHelp' => \SpecialApiHelp::class,
191  'Blankpage' => \SpecialBlankpage::class,
192  'Diff' => \SpecialDiff::class,
193  'EditTags' => [
194  'class' => \SpecialEditTags::class,
195  'services' => [
196  'PermissionManager',
197  ],
198  ],
199  'Emailuser' => \SpecialEmailUser::class,
200  'Movepage' => \MovePageForm::class,
201  'Mycontributions' => \SpecialMycontributions::class,
202  'MyLanguage' => \SpecialMyLanguage::class,
203  'Mypage' => \SpecialMypage::class,
204  'Mytalk' => \SpecialMytalk::class,
205  'Myuploads' => \SpecialMyuploads::class,
206  'AllMyUploads' => \SpecialAllMyUploads::class,
207  'NewSection' => \SpecialNewSection::class,
208  'PermanentLink' => \SpecialPermanentLink::class,
209  'Redirect' => \SpecialRedirect::class,
210  'Revisiondelete' => [
211  'class' => \SpecialRevisionDelete::class,
212  'services' => [
213  'PermissionManager',
214  ],
215  ],
216  'RunJobs' => \SpecialRunJobs::class,
217  'Specialpages' => \SpecialSpecialpages::class,
218  'PageData' => \SpecialPageData::class,
219  ];
220 
222  private $list;
223 
225  private $aliases;
226 
228  private $options;
229 
231  private $contLang;
232 
234  private $objectFactory;
235 
240  public const CONSTRUCTOR_OPTIONS = [
241  'ContentHandlerUseDB',
242  'DisableInternalSearch',
243  'EmailAuthentication',
244  'EnableEmail',
245  'EnableJavaScriptTest',
246  'EnableSpecialMute',
247  'PageLanguageUseDB',
248  'SpecialPages',
249  ];
250 
256  public function __construct(
259  ObjectFactory $objectFactory
260  ) {
261  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
262  $this->options = $options;
263  $this->contLang = $contLang;
264  $this->objectFactory = $objectFactory;
265  }
266 
273  public function getNames() : array {
274  return array_keys( $this->getPageList() );
275  }
276 
282  private function getPageList() : array {
283  if ( !is_array( $this->list ) ) {
284  $this->list = self::CORE_LIST;
285 
286  if ( !$this->options->get( 'DisableInternalSearch' ) ) {
287  $this->list['Search'] = \SpecialSearch::class;
288  }
289 
290  if ( $this->options->get( 'EmailAuthentication' ) ) {
291  $this->list['Confirmemail'] = \SpecialConfirmEmail::class;
292  $this->list['Invalidateemail'] = \SpecialEmailInvalidate::class;
293  }
294 
295  if ( $this->options->get( 'EnableEmail' ) ) {
296  $this->list['ChangeEmail'] = \SpecialChangeEmail::class;
297  }
298 
299  if ( $this->options->get( 'EnableJavaScriptTest' ) ) {
300  $this->list['JavaScriptTest'] = \SpecialJavaScriptTest::class;
301  }
302 
303  if ( $this->options->get( 'EnableSpecialMute' ) ) {
304  $this->list['Mute'] = \SpecialMute::class;
305  }
306 
307  if ( $this->options->get( 'PageLanguageUseDB' ) ) {
308  $this->list['PageLanguage'] = \SpecialPageLanguage::class;
309  }
310 
311  if ( $this->options->get( 'ContentHandlerUseDB' ) ) {
312  $this->list['ChangeContentModel'] = \SpecialChangeContentModel::class;
313  }
314 
315  // Add extension special pages
316  $this->list = array_merge( $this->list, $this->options->get( 'SpecialPages' ) );
317 
318  // This hook can be used to disable unwanted core special pages
319  // or conditionally register special pages.
320  Hooks::run( 'SpecialPage_initList', [ &$this->list ] );
321 
322  }
323 
324  return $this->list;
325  }
326 
333  private function getAliasList() : array {
334  if ( is_null( $this->aliases ) ) {
335  $aliases = $this->contLang->getSpecialPageAliases();
336  $pageList = $this->getPageList();
337 
338  $this->aliases = [];
339  $keepAlias = [];
340 
341  // Force every canonical name to be an alias for itself.
342  foreach ( $pageList as $name => $stuff ) {
343  $caseFoldedAlias = $this->contLang->caseFold( $name );
344  $this->aliases[$caseFoldedAlias] = $name;
345  $keepAlias[$caseFoldedAlias] = 'canonical';
346  }
347 
348  // Check for $aliases being an array since Language::getSpecialPageAliases can return null
349  if ( is_array( $aliases ) ) {
350  foreach ( $aliases as $realName => $aliasList ) {
351  $aliasList = array_values( $aliasList );
352  foreach ( $aliasList as $i => $alias ) {
353  $caseFoldedAlias = $this->contLang->caseFold( $alias );
354 
355  if ( isset( $this->aliases[$caseFoldedAlias] ) &&
356  $realName === $this->aliases[$caseFoldedAlias]
357  ) {
358  // Ignore same-realName conflicts
359  continue;
360  }
361 
362  if ( !isset( $keepAlias[$caseFoldedAlias] ) ) {
363  $this->aliases[$caseFoldedAlias] = $realName;
364  if ( !$i ) {
365  $keepAlias[$caseFoldedAlias] = 'first';
366  }
367  } elseif ( !$i ) {
368  wfWarn( "First alias '$alias' for $realName conflicts with " .
369  "{$keepAlias[$caseFoldedAlias]} alias for " .
370  $this->aliases[$caseFoldedAlias]
371  );
372  }
373  }
374  }
375  }
376  }
377 
378  return $this->aliases;
379  }
380 
389  public function resolveAlias( $alias ) {
390  $bits = explode( '/', $alias, 2 );
391 
392  $caseFoldedAlias = $this->contLang->caseFold( $bits[0] );
393  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
394  $aliases = $this->getAliasList();
395  if ( !isset( $aliases[$caseFoldedAlias] ) ) {
396  return [ null, null ];
397  }
398  $name = $aliases[$caseFoldedAlias];
399  $par = $bits[1] ?? null; // T4087
400 
401  return [ $name, $par ];
402  }
403 
410  public function exists( $name ) {
411  list( $title, /*...*/ ) = $this->resolveAlias( $name );
412 
413  $specialPageList = $this->getPageList();
414  return isset( $specialPageList[$title] );
415  }
416 
423  public function getPage( $name ) {
424  list( $realName, /*...*/ ) = $this->resolveAlias( $name );
425 
426  $specialPageList = $this->getPageList();
427 
428  if ( isset( $specialPageList[$realName] ) ) {
429  $rec = $specialPageList[$realName];
430 
431  if ( $rec instanceof SpecialPage ) {
432  wfDeprecated(
433  "a SpecialPage instance (for $realName) in " .
434  '$wgSpecialPages or from the SpecialPage_initList hook',
435  '1.34'
436  );
437 
438  $page = $rec; // XXX: we should deep clone here
439  } elseif ( is_array( $rec ) || is_string( $rec ) || is_callable( $rec ) ) {
440  $page = $this->objectFactory->createObject(
441  $rec,
442  [
443  'allowClassName' => true,
444  'allowCallable' => true
445  ]
446  );
447  } else {
448  $page = null;
449  }
450 
451  if ( $page instanceof SpecialPage ) {
452  return $page;
453  }
454 
455  // It's not a classname, nor a callback, nor a legacy constructor array,
456  // nor a special page object. Give up.
457  wfLogWarning( "Cannot instantiate special page $realName: bad spec!" );
458  }
459 
460  return null;
461  }
462 
471  public function getUsablePages( User $user ) : array {
472  $pages = [];
473  foreach ( $this->getPageList() as $name => $rec ) {
474  $page = $this->getPage( $name );
475  if ( $page ) { // not null
476  $page->setContext( RequestContext::getMain() );
477  if ( $page->isListed()
478  && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
479  ) {
480  $pages[$name] = $page;
481  }
482  }
483  }
484 
485  return $pages;
486  }
487 
493  public function getRegularPages() : array {
494  $pages = [];
495  foreach ( $this->getPageList() as $name => $rec ) {
496  $page = $this->getPage( $name );
497  if ( $page && $page->isListed() && !$page->isRestricted() ) {
498  $pages[$name] = $page;
499  }
500  }
501 
502  return $pages;
503  }
504 
512  public function getRestrictedPages( User $user ) : array {
513  $pages = [];
514  foreach ( $this->getPageList() as $name => $rec ) {
515  $page = $this->getPage( $name );
516  if ( $page
517  && $page->isListed()
518  && $page->isRestricted()
519  && $page->userCanExecute( $user )
520  ) {
521  $pages[$name] = $page;
522  }
523  }
524 
525  return $pages;
526  }
527 
543  public function executePath( Title &$title, IContextSource &$context, $including = false,
544  LinkRenderer $linkRenderer = null
545  ) {
546  // @todo FIXME: Redirects broken due to this call
547  $bits = explode( '/', $title->getDBkey(), 2 );
548  $name = $bits[0];
549  $par = $bits[1] ?? null; // T4087
550 
551  $page = $this->getPage( $name );
552  if ( !$page ) {
553  $context->getOutput()->setArticleRelated( false );
554  $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
555 
556  global $wgSend404Code;
557  if ( $wgSend404Code ) {
558  $context->getOutput()->setStatusCode( 404 );
559  }
560 
561  $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
562 
563  return false;
564  }
565 
566  if ( !$including ) {
567  // Narrow DB query expectations for this HTTP request
568  $trxLimits = $context->getConfig()->get( 'TrxProfilerLimits' );
569  $trxProfiler = Profiler::instance()->getTransactionProfiler();
570  if ( $context->getRequest()->wasPosted() && !$page->doesWrites() ) {
571  $trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ );
572  $context->getRequest()->markAsSafeRequest();
573  }
574  }
575 
576  // Page exists, set the context
577  $page->setContext( $context );
578 
579  if ( !$including ) {
580  // Redirect to canonical alias for GET commands
581  // Not for POST, we'd lose the post data, so it's best to just distribute
582  // the request. Such POST requests are possible for old extensions that
583  // generate self-links without being aware that their default name has
584  // changed.
585  if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
586  $query = $context->getRequest()->getQueryValues();
587  unset( $query['title'] );
588  $title = $page->getPageTitle( $par );
589  $url = $title->getFullURL( $query );
590  $context->getOutput()->redirect( $url );
591 
592  return $title;
593  }
594 
595  // @phan-suppress-next-line PhanUndeclaredMethod
596  $context->setTitle( $page->getPageTitle( $par ) );
597  } elseif ( !$page->isIncludable() ) {
598  return false;
599  }
600 
601  $page->including( $including );
602  if ( $linkRenderer ) {
603  $page->setLinkRenderer( $linkRenderer );
604  }
605 
606  // Execute special page
607  $page->run( $par );
608 
609  return true;
610  }
611 
627  public function capturePath(
628  Title $title, IContextSource $context, LinkRenderer $linkRenderer = null
629  ) {
630  global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
631  $main = RequestContext::getMain();
632 
633  // Save current globals and main context
634  $glob = [
635  'title' => $wgTitle,
636  'output' => $wgOut,
637  'request' => $wgRequest,
638  'user' => $wgUser,
639  'language' => $wgLang,
640  ];
641  $ctx = [
642  'title' => $main->getTitle(),
643  'output' => $main->getOutput(),
644  'request' => $main->getRequest(),
645  'user' => $main->getUser(),
646  'language' => $main->getLanguage(),
647  ];
648  if ( $main->canUseWikiPage() ) {
649  $ctx['wikipage'] = $main->getWikiPage();
650  }
651 
652  // Override
653  $wgTitle = $title;
654  $wgOut = $context->getOutput();
655  $wgRequest = $context->getRequest();
656  $wgUser = $context->getUser();
657  $wgLang = $context->getLanguage();
658  $main->setTitle( $title );
659  $main->setOutput( $context->getOutput() );
660  $main->setRequest( $context->getRequest() );
661  $main->setUser( $context->getUser() );
662  $main->setLanguage( $context->getLanguage() );
663 
664  // The useful part
665  $ret = $this->executePath( $title, $context, true, $linkRenderer );
666 
667  // Restore old globals and context
668  $wgTitle = $glob['title'];
669  $wgOut = $glob['output'];
670  $wgRequest = $glob['request'];
671  $wgUser = $glob['user'];
672  $wgLang = $glob['language'];
673  $main->setTitle( $ctx['title'] );
674  $main->setOutput( $ctx['output'] );
675  $main->setRequest( $ctx['request'] );
676  $main->setUser( $ctx['user'] );
677  $main->setLanguage( $ctx['language'] );
678  if ( isset( $ctx['wikipage'] ) ) {
679  $main->setWikiPage( $ctx['wikipage'] );
680  }
681 
682  return $ret;
683  }
684 
692  public function getLocalNameFor( $name, $subpage = false ) {
693  $aliases = $this->contLang->getSpecialPageAliases();
694  $aliasList = $this->getAliasList();
695 
696  // Find the first alias that maps back to $name
697  if ( isset( $aliases[$name] ) ) {
698  $found = false;
699  foreach ( $aliases[$name] as $alias ) {
700  $caseFoldedAlias = $this->contLang->caseFold( $alias );
701  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
702  if ( isset( $aliasList[$caseFoldedAlias] ) &&
703  $aliasList[$caseFoldedAlias] === $name
704  ) {
705  $name = $alias;
706  $found = true;
707  break;
708  }
709  }
710  if ( !$found ) {
711  wfWarn( "Did not find a usable alias for special page '$name'. " .
712  "It seems all defined aliases conflict?" );
713  }
714  } else {
715  // Check if someone misspelled the correct casing
716  if ( is_array( $aliases ) ) {
717  foreach ( $aliases as $n => $values ) {
718  if ( strcasecmp( $name, $n ) === 0 ) {
719  wfWarn( "Found alias defined for $n when searching for " .
720  "special page aliases for $name. Case mismatch?" );
721  return $this->getLocalNameFor( $n, $subpage );
722  }
723  }
724  }
725 
726  wfWarn( "Did not find alias for special page '$name'. " .
727  "Perhaps no aliases are defined for it?" );
728  }
729 
730  if ( $subpage !== false && !is_null( $subpage ) ) {
731  // Make sure it's in dbkey form
732  $subpage = str_replace( ' ', '_', $subpage );
733  $name = "$name/$subpage";
734  }
735 
736  return $this->contLang->ucfirst( $name );
737  }
738 
745  public function getTitleForAlias( $alias ) {
746  list( $name, $subpage ) = $this->resolveAlias( $alias );
747  if ( $name != null ) {
748  return SpecialPage::getTitleFor( $name, $subpage );
749  }
750 
751  return null;
752  }
753 }
getRestrictedPages(User $user)
Return categorised listable special pages which are available for the current user, but not for everyone.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
capturePath(Title $title, IContextSource $context, LinkRenderer $linkRenderer=null)
Just like executePath() but will override global variables and execute the page in "inclusion" mode...
static instance()
Singleton.
Definition: Profiler.php:63
executePath(Title &$title, IContextSource &$context, $including=false, LinkRenderer $linkRenderer=null)
Execute a special page path.
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
getUsablePages(User $user)
Return categorised listable special pages which are available for the current user, and everyone.
A class for passing options to services.
exists( $name)
Check if a given name exist as a special page or as a special page alias.
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
getConfig()
Get the site configuration.
$wgLang
Definition: Setup.php:857
Class that generates HTML links for pages.
Factory for handling the special page list and generating SpecialPage objects.
static getMain()
Get the RequestContext object associated with the main request.
IContextSource $context
Definition: MediaWiki.php:37
getDBkey()
Get the main part with underscores.
Definition: Title.php:1016
getPageList()
Get the special page list as an array.
getLocalNameFor( $name, $subpage=false)
Get the local name for a specified canonical name.
getNames()
Returns a list of canonical special page names.
getFullURL( $query='', $query2=false, $proto=PROTO_RELATIVE)
Get a real URL referring to this title, with interwiki link and fragment.
Definition: Title.php:2108
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:83
getRegularPages()
Return categorised listable special pages for all users.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys, without regard for order.
const array $list
Special page name => class name.
getTitleForAlias( $alias)
Get a title for a given alias.
__construct(ServiceOptions $options, Language $contLang, ObjectFactory $objectFactory)
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
getPage( $name)
Find the object with a given name and return it (or NULL)
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:728
$wgOut
Definition: Setup.php:862
if(! $wgRequest->checkUrlExtension()) if(isset( $_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] !='') $wgTitle
Definition: api.php:58
getAliasList()
Initialise and return the list of special page aliases.
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code, mangling or hiding MediaWiki&#39;s output.
const CORE_LIST
List of special page names to the subclass of SpecialPage which handles them.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200