MediaWiki master
Article.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Page;
8
9use LogicException;
16use MediaWiki\Debug\DeprecationHelper;
21use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
50use StatusValue;
52use Wikimedia\IPUtils;
53use Wikimedia\NonSerializable\NonSerializableTrait;
54use Wikimedia\Parsoid\Parsoid;
56
66class Article implements Page {
67 use ProtectedHookAccessorTrait;
68 use NonSerializableTrait;
69 use DeprecationHelper;
70
76 private $mContext;
77
79 protected $mPage;
80
85 public $mOldId;
86
88 public $mRedirectedFrom = null;
89
91 public $mRedirectUrl = false;
92
97 private $fetchResult = null;
98
104 public $mParserOutput = null;
105
111 protected $viewIsRenderAction = false;
112
114 private RevisionStore $revisionStore;
115 private UserNameUtils $userNameUtils;
116 private UserOptionsLookup $userOptionsLookup;
117 private CommentFormatter $commentFormatter;
118 private WikiPageFactory $wikiPageFactory;
119 private JobQueueGroup $jobQueueGroup;
120 private ArchivedRevisionLookup $archivedRevisionLookup;
121 private RecentChangeLookup $recentChangeLookup;
125 private bool $useLegacyPostprocCache;
126
133 private $mRevisionRecord = null;
134
135 private bool $parsoidPostprocCacheAvailable;
136 private bool $legacyPostprocCacheAvailable;
137
142 public function __construct( Title $title, $oldId = null ) {
143 $this->deprecatePublicProperty( 'mContext', '1.35', __CLASS__ );
144
145 $this->mOldId = $oldId;
146 $this->mPage = $this->newPage( $title );
147
148 $services = MediaWikiServices::getInstance();
149 $this->linkRenderer = $services->getLinkRenderer();
150 $this->revisionStore = $services->getRevisionStore();
151 $this->userNameUtils = $services->getUserNameUtils();
152 $this->userOptionsLookup = $services->getUserOptionsLookup();
153 $this->commentFormatter = $services->getCommentFormatter();
154 $this->wikiPageFactory = $services->getWikiPageFactory();
155 $this->jobQueueGroup = $services->getJobQueueGroup();
156 $this->archivedRevisionLookup = $services->getArchivedRevisionLookup();
157 $this->recentChangeLookup = $services->getRecentChangeLookup();
158 $this->dbProvider = $services->getConnectionProvider();
159 $this->blockStore = $services->getDatabaseBlockStore();
160 $this->restrictionStore = $services->getRestrictionStore();
161 $this->parsoidPostprocCacheAvailable =
163 $this->legacyPostprocCacheAvailable =
165 $this->useLegacyPostprocCache = false;
166 }
167
172 protected function newPage( Title $title ) {
173 return new WikiPage( $title );
174 }
175
180 public static function newFromID( $id ): ?static {
181 $t = Title::newFromID( $id );
182 return $t === null ? null : new static( $t );
183 }
184
191 public static function newFromTitle( $title, IContextSource $context ): static {
192 if ( $title->getNamespace() === NS_MEDIA ) {
193 // XXX: This should not be here, but where should it go?
194 $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
195 }
196
197 $page = null;
198 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
199 // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
200 ->onArticleFromTitle( $title, $page, $context );
201
202 $page ??= match ( $title->getNamespace() ) {
203 NS_FILE => new ImagePage( $title ),
204 NS_CATEGORY => new CategoryPage( $title ),
205 default => new Article( $title )
206 };
207 $page->setContext( $context );
208
209 return $page;
210 }
211
219 public static function newFromWikiPage( WikiPage $page, IContextSource $context ) {
220 $article = self::newFromTitle( $page->getTitle(), $context );
221 $article->mPage = $page; // override to keep process cached vars
222 return $article;
223 }
224
230 public function getRedirectedFrom() {
231 return $this->mRedirectedFrom;
232 }
233
238 public function setRedirectedFrom( Title $from ) {
239 $this->mRedirectedFrom = $from;
240 }
241
247 public function getTitle() {
248 return $this->mPage->getTitle();
249 }
250
257 public function getPage() {
258 return $this->mPage;
259 }
260
261 public function clear() {
262 $this->mRedirectedFrom = null; # Title object if set
263 $this->mRedirectUrl = false;
264 $this->mRevisionRecord = null;
265 $this->fetchResult = null;
266
267 // TODO hard-deprecate direct access to public fields
268
269 $this->mPage->clear();
270 }
271
279 public function getOldID() {
280 if ( $this->mOldId === null ) {
281 $this->mOldId = $this->getOldIDFromRequest();
282 }
283
284 return $this->mOldId;
285 }
286
292 public function getOldIDFromRequest() {
293 $this->mRedirectUrl = false;
294
295 $request = $this->getContext()->getRequest();
296 $oldid = $request->getIntOrNull( 'oldid' );
297
298 if ( $oldid === null ) {
299 return 0;
300 }
301
302 if ( $oldid !== 0 ) {
303 # Load the given revision and check whether the page is another one.
304 # In that case, update this instance to reflect the change.
305 if ( $oldid === $this->mPage->getLatest() ) {
306 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
307 } else {
308 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
309 if ( $this->mRevisionRecord !== null ) {
310 $revPageId = $this->mRevisionRecord->getPageId();
311 // Revision title doesn't match the page title given?
312 if ( $this->mPage->getId() !== $revPageId ) {
313 $this->mPage = $this->wikiPageFactory->newFromID( $revPageId );
314 }
315 }
316 }
317 }
318
319 $oldRev = $this->mRevisionRecord;
320 if ( $request->getRawVal( 'direction' ) === 'next' ) {
321 $nextid = 0;
322 if ( $oldRev ) {
323 $nextRev = $this->revisionStore->getNextRevision( $oldRev );
324 if ( $nextRev ) {
325 $nextid = $nextRev->getId();
326 }
327 }
328 if ( $nextid ) {
329 $oldid = $nextid;
330 $this->mRevisionRecord = null;
331 } else {
332 $this->mRedirectUrl = $this->getTitle()->getFullURL( 'redirect=no' );
333 }
334 } elseif ( $request->getRawVal( 'direction' ) === 'prev' ) {
335 $previd = 0;
336 if ( $oldRev ) {
337 $prevRev = $this->revisionStore->getPreviousRevision( $oldRev );
338 if ( $prevRev ) {
339 $previd = $prevRev->getId();
340 }
341 }
342 if ( $previd ) {
343 $oldid = $previd;
344 $this->mRevisionRecord = null;
345 }
346 }
347
348 return $oldid;
349 }
350
360 public function fetchRevisionRecord() {
361 if ( $this->fetchResult ) {
362 return $this->mRevisionRecord;
363 }
364
365 $oldid = $this->getOldID();
366
367 // $this->mRevisionRecord might already be fetched by getOldIDFromRequest()
368 if ( !$this->mRevisionRecord ) {
369 if ( !$oldid ) {
370 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
371
372 if ( !$this->mRevisionRecord ) {
373 wfDebug( __METHOD__ . " failed to find page data for title " .
374 $this->getTitle()->getPrefixedText() );
375
376 // Output for this case is done by showMissingArticle().
377 $this->fetchResult = StatusValue::newFatal( 'noarticletext' );
378 return null;
379 }
380 } else {
381 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
382
383 if ( !$this->mRevisionRecord ) {
384 wfDebug( __METHOD__ . " failed to load revision, rev_id $oldid" );
385
386 $this->fetchResult = StatusValue::newFatal( $this->getMissingRevisionMsg( $oldid ) );
387 return null;
388 }
389 }
390 }
391
392 if ( !$this->mRevisionRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getContext()->getAuthority() ) ) {
393 wfDebug( __METHOD__ . " failed to retrieve content of revision " . $this->mRevisionRecord->getId() );
394
395 // Output for this case is done by showDeletedRevisionHeader().
396 // title used in wikilinks, should not contain whitespaces
397 $this->fetchResult = new StatusValue();
398 $title = $this->getTitle()->getPrefixedDBkey();
399
400 if ( $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
401 $this->fetchResult->fatal( 'rev-suppressed-text' );
402 } else {
403 $this->fetchResult->fatal( 'rev-deleted-text-permission', $title );
404 }
405
406 return null;
407 }
408
409 $this->fetchResult = StatusValue::newGood( $this->mRevisionRecord );
410 return $this->mRevisionRecord;
411 }
412
418 public function isCurrent() {
419 # If no oldid, this is the current version.
420 if ( $this->getOldID() == 0 ) {
421 return true;
422 }
423
424 return $this->mPage->exists() &&
425 $this->mRevisionRecord &&
426 $this->mRevisionRecord->isCurrent();
427 }
428
437 public function getRevIdFetched() {
438 if ( $this->fetchResult && $this->fetchResult->isOK() ) {
440 $rev = $this->fetchResult->getValue();
441 return $rev->getId();
442 } else {
443 return $this->mPage->getLatest();
444 }
445 }
446
451 public function view() {
452 $context = $this->getContext();
453 $useFileCache = $context->getConfig()->get( MainConfigNames::UseFileCache );
454
455 # Get variables from query string
456 # As side effect this will load the revision and update the title
457 # in a revision ID is passed in the request, so this should remain
458 # the first call of this method even if $oldid is used way below.
459 $oldid = $this->getOldID();
460
461 $authority = $context->getAuthority();
462 # Another check in case getOldID() is altering the title
463 $permissionStatus = PermissionStatus::newEmpty();
464 if ( !$authority
465 ->authorizeRead( 'read', $this->getTitle(), $permissionStatus )
466 ) {
467 wfDebug( __METHOD__ . ": denied on secondary read check" );
468 throw new PermissionsError( 'read', $permissionStatus );
469 }
470
471 $outputPage = $context->getOutput();
472 # getOldID() may as well want us to redirect somewhere else
473 if ( $this->mRedirectUrl ) {
474 $outputPage->redirect( $this->mRedirectUrl );
475 wfDebug( __METHOD__ . ": redirecting due to oldid" );
476
477 return;
478 }
479
480 # If we got diff in the query, we want to see a diff page instead of the article.
481 if ( $context->getRequest()->getCheck( 'diff' ) ) {
482 wfDebug( __METHOD__ . ": showing diff page" );
483 $this->showDiffPage();
484 return;
485 }
486
487 $this->showProtectionIndicator();
488
489 # Set page title (may be overridden from ParserOutput if title conversion is enabled or DISPLAYTITLE is used)
490 $outputPage->setPageTitle( Parser::formatPageTitle(
491 str_replace( '_', ' ', $this->getTitle()->getNsText() ),
492 ':',
493 $this->getTitle()->getText(),
494 $this->getTitle()->getPageLanguage()
495 ) );
496
497 $outputPage->setArticleFlag( true );
498 # Allow frames by default
499 $outputPage->getMetadata()->setPreventClickjacking( false );
500
501 $parserOptions = $this->getParserOptions( $oldid );
502
503 $poOptions = [];
504 # Render printable version, use printable version cache
505 if ( $outputPage->isPrintable() ) {
506 $parserOptions->setIsPrintable( true );
507 $parserOptions->setSuppressSectionEditLinks();
508 $this->addMessageBoxStyles( $outputPage );
509 $outputPage->prependHTML(
510 Html::warningBox(
511 $outputPage->msg( 'printableversion-deprecated-warning' )->escaped()
512 )
513 );
514 } elseif ( $this->viewIsRenderAction || !$this->isCurrent() ||
515 !$authority->probablyCan( 'edit', $this->getTitle() )
516 ) {
517 $parserOptions->setSuppressSectionEditLinks();
518 }
519
520 # Try client and file cache
521 if ( $oldid === 0 && $this->mPage->checkTouched() ) {
522 # Try to stream the output from file cache
523 if ( $useFileCache && $this->tryFileCache() ) {
524 wfDebug( __METHOD__ . ": done file cache" );
525 # tell wgOut that output is taken care of
526 $outputPage->disable();
527 $this->mPage->doViewUpdates( $authority );
528
529 return;
530 }
531 }
532
533 $this->showRedirectedFromHeader();
534 $this->showNamespaceHeader();
535
536 if ( $this->viewIsRenderAction ) {
537 $poOptions += [ 'absoluteURLs' => true ];
538 }
539 $poOptions += [ 'includeDebugInfo' => true ];
540
541 try {
542 $continue =
543 $this->generateContentOutput( $authority, $parserOptions, $oldid, $outputPage, $poOptions );
544 } catch ( BadRevisionException ) {
545 $continue = false;
546 $this->showViewError( wfMessage( 'badrevision' )->text() );
547 }
548
549 if ( !$continue ) {
550 return;
551 }
552
553 # For the main page, overwrite the <title> element with the con-
554 # tents of 'pagetitle-view-mainpage' instead of the default (if
555 # that's not empty).
556 # This message always exists because it is in the i18n files
557 if ( $this->getTitle()->isMainPage() ) {
558 $msg = $context->msg( 'pagetitle-view-mainpage' )->inContentLanguage();
559 if ( !$msg->isDisabled() ) {
560 $outputPage->setHTMLTitle( $msg->text() );
561 }
562 }
563
564 // Enable 1-day CDN cache on this response
565 //
566 // To reduce impact of lost or delayed HTTP purges, the adaptive TTL will
567 // raise the TTL for pages not recently edited, upto $wgCdnMaxAge.
568 // This could use getTouched(), but that could be scary for major template edits.
569 $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), 86_400 );
570
571 $this->showViewFooter();
572 $this->mPage->doViewUpdates( $authority, $this->fetchRevisionRecord() );
573
574 # Load the postEdit module if the user just saved this revision
575 # See also EditPage::setPostEditCookie
576 $request = $context->getRequest();
577 $cookieKey = EditPage::POST_EDIT_COOKIE_KEY_PREFIX . $this->getRevIdFetched();
578 $postEdit = $request->getCookie( $cookieKey );
579 if ( $postEdit ) {
580 # Clear the cookie. This also prevents caching of the response.
581 $request->response()->clearCookie( $cookieKey );
582 $outputPage->addJsConfigVars( 'wgPostEdit', $postEdit );
583 $outputPage->addModules( 'mediawiki.action.view.postEdit' ); // FIXME: test this
584 if ( $this->getContext()->getConfig()->get( MainConfigNames::EnableEditRecovery )
585 && $this->userOptionsLookup->getOption( $this->getContext()->getUser(), 'editrecovery' )
586 ) {
587 $outputPage->addModules( 'mediawiki.editRecovery.postEdit' );
588 }
589 }
590 }
591
595 public function showProtectionIndicator(): void {
596 $title = $this->getTitle();
597 $context = $this->getContext();
598 $outputPage = $context->getOutput();
599
600 $protectionIndicatorsAreEnabled = $context->getConfig()
601 ->get( MainConfigNames::EnableProtectionIndicators );
602
603 if ( !$protectionIndicatorsAreEnabled || $title->isMainPage() ) {
604 return;
605 }
606
607 $protection = $this->restrictionStore->getRestrictions( $title, 'edit' );
608
609 $cascadeProtection = $this->restrictionStore->getCascadeProtectionSources( $title )[1];
610
611 $isCascadeProtected = array_key_exists( 'edit', $cascadeProtection );
612
613 if ( !$protection && !$isCascadeProtected ) {
614 return;
615 }
616
617 if ( $isCascadeProtected ) {
618 // Cascade-protected pages are protected at the sysop level. So it
619 // should not matter if we take the protection level of the first
620 // or last page that is being cascaded to the current page.
621 $protectionLevel = $cascadeProtection['edit'][0];
622 } else {
623 $protectionLevel = $protection[0];
624 }
625
626 // Protection levels are stored in the database as plain text, but
627 // they are expected to be valid protection levels. So we should be able to
628 // safely use them. However phan thinks this could be a XSS problem so we
629 // are being paranoid and escaping them once more.
630 $protectionLevel = htmlspecialchars( $protectionLevel );
631
632 $protectionExpiry = $this->restrictionStore->getRestrictionExpiry( $title, 'edit' );
633 $formattedProtectionExpiry = $context->getLanguage()
634 ->formatExpiry( $protectionExpiry ?? '' );
635
636 $protectionMsgKey = 'protection-indicator-title';
637 if ( $protectionExpiry === 'infinity' || !$protectionExpiry ) {
638 $protectionMsgKey = 'protection-indicator-title-infinity';
639 }
640
641 // Potential values: 'protection-sysop', 'protection-autoconfirmed',
642 // 'protection-sysop-cascade' etc.
643 // If the wiki has more protection levels, the additional ids that get
644 // added take the form 'protection-<protectionLevel>' and
645 // 'protection-<protectionLevel>-cascade'.
646 $protectionIndicatorId = 'protection-' . $protectionLevel . ( $isCascadeProtected ? '-cascade' : '' );
647
648 $protectionMsg = $outputPage->msg(
649 $protectionMsgKey,
650 // Messages: restriction-level-sysop, restriction-level-autoconfirmed
651 $outputPage->msg( "restriction-level-$protectionLevel" ),
652 $formattedProtectionExpiry
653 )->text();
654
655 // Use a trick similar to the one used in Action::addHelpLink() to allow wikis
656 // to customize where the help link points to.
657 $protectionHelpLink = $outputPage->msg( $protectionIndicatorId . '-helppage' );
658 if ( $protectionHelpLink->isDisabled() ) {
659 $protectionHelpLink = 'https://mediawiki.org/wiki/Special:MyLanguage/Help:Protection';
660 } else {
661 $protectionHelpLink = Skin::makeInternalOrExternalUrl( $protectionHelpLink->text() );
662 }
663
664 $outputPage->setIndicators( [
665 $protectionIndicatorId => Html::rawElement( 'a', [
666 'class' => 'mw-protection-indicator-icon--lock',
667 'title' => $protectionMsg,
668 'href' => $protectionHelpLink
669 ],
670 // Screen reader-only text describing the same thing as
671 // was mentioned in the title attribute.
672 Html::element( 'span', [], $protectionMsg ) )
673 ] );
674
675 $outputPage->addModuleStyles( 'mediawiki.protectionIndicators.styles' );
676 }
677
690 private function generateContentOutput(
691 Authority $performer,
692 ParserOptions $parserOptions,
693 int $oldid,
694 OutputPage $outputPage,
695 array $textOptions
696 ): bool {
697 # Should the parser cache be used?
698 $useParserCache = true;
699 $pOutput = null;
700 $parserOutputAccess = MediaWikiServices::getInstance()->getParserOutputAccess();
701
702 // NOTE: $outputDone and $useParserCache may be changed by the hook
703 $this->getHookRunner()->onArticleViewHeader( $this, $outputDone, $useParserCache );
704 if ( $outputDone ) {
705 if ( $outputDone instanceof ParserOutput ) {
706 $pOutput = $outputDone;
707 }
708
709 if ( $pOutput ) {
710 $this->doOutputMetaData( $pOutput, $outputPage );
711 }
712 return true;
713 }
714
715 // Early abort if the page doesn't exist
716 if ( !$this->mPage->exists() ) {
717 wfDebug( __METHOD__ . ": showing missing article" );
718 $this->showMissingArticle();
719 $this->mPage->doViewUpdates( $performer );
720 return false; // skip all further output to OutputPage
721 }
722
723 // Augment the parser options
724 $skin = $outputPage->getSkin();
725 $skinOptions = $skin->getOptions();
726 $textOptions += [
727 // T371022, T410923
728 'allowClone' => $this->getContext()->getConfig()->get( MainConfigNames::CloneArticleParserOutput ),
729 'skin' => $skin,
730 'injectTOC' => $skinOptions['toc'],
731 ];
732 foreach ( $textOptions as $key => $value ) {
733 // allowClone will disappear and should not impact cache
734 // userLang is a duplicate of userlang and should be reconciled with it
735 if ( $key === 'allowClone' || $key === 'userLang' ) {
736 continue;
737 }
738 if ( $key === 'enableSectionEditLinks' ) {
739 if ( $value === false ) {
740 wfDeprecated( __METHOD__ . " with deprecated textOption $key set to false", "1.46" );
741 $parserOptions->setSuppressSectionEditLinks();
742 }
743 continue;
744 }
745 if ( !in_array( $key, ParserOptions::$postprocOptions, true ) ) {
746 wfDeprecated( __METHOD__ . " with unknown textOption $key", "1.46" );
747 } else {
748 $parserOptions->setOption( $key, $value );
749 }
750 }
751 if ( $this->usePostProcessingCache( $parserOptions ) ) {
752 $parserOptions->enablePostproc();
753 }
754
755 // Try the latest parser cache
756 // NOTE: try latest-revision cache first to avoid loading revision.
757 if ( $useParserCache && !$oldid ) {
758 $pOutput = $parserOutputAccess->getCachedParserOutput(
759 $this->getPage(),
760 $parserOptions,
761 null,
762 [
763 // we already checked
764 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK => true,
765 ],
766 );
767
768 if ( $pOutput ) {
769 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
770 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $skin );
771 }
772 $this->doOutputFromPostProcessedParserCache( $pOutput, $outputPage );
773 $this->doOutputMetaData( $pOutput, $outputPage );
774 return true;
775 }
776 }
777
778 $rev = $this->fetchRevisionRecord();
779 if ( !$this->fetchResult->isOK() ) {
780 $this->showViewError( Status::wrap( $this->fetchResult )->getWikiText(
781 false, false, $this->getContext()->getLanguage()
782 ) );
783 return true;
784 }
785
786 # Are we looking at an old revision
787 if ( $oldid ) {
788 $this->setOldSubtitle( $oldid );
789
790 if ( !$this->showDeletedRevisionHeader() ) {
791 wfDebug( __METHOD__ . ": cannot view deleted revision" );
792 return false; // skip all further output to OutputPage
793 }
794
795 // Try the old revision parser cache
796 // NOTE: Repeating cache check for old revision to avoid fetching $rev
797 // before it's absolutely necessary.
798 if ( $useParserCache ) {
799 $pOutput = $parserOutputAccess->getCachedParserOutput(
800 $this->getPage(),
801 $parserOptions,
802 $rev,
803 [
804 // we already checked in fetchRevisionRecord
805 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK => true,
806 ],
807 );
808
809 if ( $pOutput ) {
810 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
811 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $skin );
812 }
813 $this->doOutputFromPostProcessedParserCache( $pOutput, $outputPage );
814 $this->doOutputMetaData( $pOutput, $outputPage );
815 return true;
816 }
817 }
818 }
819
820 # Ensure that UI elements requiring revision ID have
821 # the correct version information. (This may be overwritten after creation of ParserOutput)
822 $outputPage->setRevisionId( $this->getRevIdFetched() );
823 $outputPage->setRevisionIsCurrent( $rev->isCurrent() );
824 # Preload timestamp to avoid a DB hit
825 $outputPage->getMetadata()->setRevisionTimestamp( $rev->getTimestamp() );
826
827 # Pages containing custom CSS or JavaScript get special treatment
828 if ( $this->getTitle()->isSiteConfigPage() || $this->getTitle()->isUserConfigPage() ) {
829 $dir = $this->getContext()->getLanguage()->getDir();
830 $lang = $this->getContext()->getLanguage()->getHtmlCode();
831
832 $outputPage->wrapWikiMsg(
833 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
834 'clearyourcache'
835 );
836 $outputPage->addModuleStyles( 'mediawiki.action.styles' );
837 } elseif ( !$this->getHookRunner()->onArticleRevisionViewCustom(
838 $rev,
839 $this->getTitle(),
840 $oldid,
841 $outputPage )
842 ) {
843 // NOTE: sync with hooks called in DifferenceEngine::renderNewRevision()
844 // Allow extensions do their own custom view for certain pages
845 $this->doOutputMetaData( $pOutput, $outputPage );
846 return true;
847 }
848
849 # Run the parse, protected by a pool counter
850 wfDebug( __METHOD__ . ": doing uncached parse" );
851
852 $opt = [];
853
854 // we already checked the cache in case 2, don't check again; but if we're using postproc,
855 // we still want to check if we have a main parser cache entry.
856 if ( $this->usePostProcessingCache( $parserOptions ) ) {
857 $opt[ ParserOutputAccess::OPT_NO_POSTPROC_CACHE ] = true;
858 } else {
859 $opt[ ParserOutputAccess::OPT_NO_CHECK_CACHE ] = true;
860 }
861
862 // we already checked in fetchRevisionRecord()
863 $opt[ ParserOutputAccess::OPT_NO_AUDIENCE_CHECK ] = true;
864
865 // enable stampede protection
866 $opt[ ParserOutputAccess::OPT_POOL_COUNTER ]
867 = ParserOutputAccess::POOL_COUNTER_ARTICLE_VIEW;
868
869 // allow stale cached content to be served
870 $opt[ ParserOutputAccess::OPT_POOL_COUNTER_FALLBACK ] = true;
871
872 // Attempt to trigger WikiPage::triggerOpportunisticLinksUpdate
873 // Ideally this should not be the responsibility of the ParserCache to control this.
874 // See https://phabricator.wikimedia.org/T329842#8816557 for more context.
875 $opt[ ParserOutputAccess::OPT_LINKS_UPDATE ] = true;
876
877 if ( !$rev->getId() || !$useParserCache ) {
878 // fake revision or uncacheable options
879 $opt[ ParserOutputAccess::OPT_NO_CACHE ] = true;
880 }
881
882 $renderStatus = $parserOutputAccess->getParserOutput(
883 $this->getPage(),
884 $parserOptions,
885 $rev,
886 $opt
887 );
888
889 // T327164: If parsoid cache warming is enabled, we want to ensure that the page
890 // the user is currently looking at has a cached parsoid rendering, in case they
891 // open visual editor. The cache entry would typically be missing if it has expired
892 // from the cache or it was invalidated by RefreshLinksJob. When "traditional"
893 // parser output has been invalidated by RefreshLinksJob, we will render it on
894 // the fly when a user requests the page, and thereby populate the cache again,
895 // per the code above.
896 // The code below is intended to do the same for parsoid output, but asynchronously
897 // in a job, so the user does not have to wait.
898 // Note that we get here if the traditional parser output was missing from the cache.
899 // We do not check if the parsoid output is present in the cache, because that check
900 // takes time. The assumption is that if we have traditional parser output
901 // cached, we probably also have parsoid output cached.
902 // So we leave it to ParsoidCachePrewarmJob to determine whether or not parsing is
903 // needed.
904 if ( $oldid === 0 || $oldid === $this->getPage()->getLatest() ) {
905 $parsoidCacheWarmingEnabled = $this->getContext()->getConfig()
906 ->get( MainConfigNames::ParsoidCacheConfig )['WarmParsoidParserCache'];
907
908 if ( $parsoidCacheWarmingEnabled ) {
909 $parsoidJobSpec = ParsoidCachePrewarmJob::newSpec(
910 $rev->getId(),
911 $this->getPage()->toPageRecord(),
912 [ 'causeAction' => 'view' ]
913 );
914 $this->jobQueueGroup->lazyPush( $parsoidJobSpec );
915 }
916 }
917
918 $this->doOutputFromRenderStatus(
919 $renderStatus,
920 $outputPage,
921 $parserOptions,
922 $textOptions,
923 );
924
925 if ( !$renderStatus->isOK() ) {
926 return true;
927 }
928
929 $pOutput = $renderStatus->getValue();
930 $this->doOutputMetaData( $pOutput, $outputPage );
931 return true;
932 }
933
934 private function doOutputMetaData( ?ParserOutput $pOutput, OutputPage $outputPage ) {
935 # Adjust title for main page & pages with displaytitle
936 if ( $pOutput ) {
937 $this->adjustDisplayTitle( $pOutput );
938
939 // It would be nice to automatically set this during the first call
940 // to OutputPage::addParserOutputMetadata, but we can't because doing
941 // so would break non-pageview actions where OutputPage::getContLangForJS
942 // has different requirements.
943 $pageLang = $pOutput->getLanguage();
944 if ( $pageLang ) {
945 $outputPage->setContentLangForJS( $pageLang );
946 }
947 }
948
949 # Check for any __NOINDEX__ tags on the page using $pOutput
950 $policy = $this->getRobotPolicy( 'view', $pOutput ?: null );
951 $outputPage->getMetadata()->setIndexPolicy( $policy['index'] );
952 $outputPage->setFollowPolicy( $policy['follow'] ); // FIXME: test this
953
954 $this->mParserOutput = $pOutput;
955 }
956
957 private function postProcessOutput(
958 ParserOutput $pOutput, ParserOptions $parserOptions, array $textOptions, Skin $skin
959 ): ParserOutput {
960 $skinOptions = $skin->getOptions();
961 $textOptions += [
962 // T371022, T410923
963 'allowClone' => $this->getContext()->getConfig()->get( MainConfigNames::CloneArticleParserOutput ),
964 'skin' => $skin,
965 'injectTOC' => $skinOptions['toc'],
966 ];
967 $pipeline = MediaWikiServices::getInstance()->getDefaultOutputPipeline();
968 $pOutput = $pipeline->run( $pOutput, $parserOptions, $textOptions );
969 return $pOutput;
970 }
971
972 private function doOutputFromPostProcessedParserCache(
973 ParserOutput $pOutput,
974 OutputPage $outputPage,
975 ) {
976 # Ensure that UI elements requiring revision ID have
977 # the correct version information.
978 $oldid = $pOutput->getCacheRevisionId() ?? $this->getRevIdFetched();
979 $outputPage->setRevisionId( $oldid );
980 $outputPage->setRevisionIsCurrent( $oldid === $this->mPage->getLatest() );
981
982 $outputPage->addPostProcessedParserOutput( $pOutput );
983
984 if ( $pOutput->getRedirectHeader() !== null ) {
985 $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
986 $this->getContext()->msg( 'redirectpagesub' )->parse() . "</span>" );
987 }
988
989 # Preload timestamp to avoid a DB hit
990 $cachedTimestamp = $pOutput->getRevisionTimestamp();
991 if ( $cachedTimestamp !== null ) {
992 $outputPage->getMetadata()->setRevisionTimestamp( $cachedTimestamp );
993 $this->mPage->setTimestamp( $cachedTimestamp );
994 }
995 }
996
997 private function doOutputFromRenderStatus(
998 StatusValue $renderStatus,
999 OutputPage $outputPage,
1000 ParserOptions $parserOptions,
1001 array $textOptions,
1002 ) {
1003 $context = $this->getContext();
1004 if ( !$renderStatus->isOK() ) {
1005 $this->showViewError( Status::wrap( $renderStatus )->getWikiText(
1006 false, 'view-pool-error', $context->getLanguage()
1007 ) );
1008 return;
1009 }
1010
1011 $pOutput = $renderStatus->getValue();
1012
1013 // Cache stale ParserOutput object with a short expiry
1014 if ( $renderStatus->hasMessage( 'view-pool-dirty-output' ) ) {
1015 $outputPage->lowerCdnMaxage( $context->getConfig()->get( MainConfigNames::CdnMaxageStale ) );
1016 $outputPage->setLastModified( $pOutput->getCacheTime() );
1017 $staleReason = $renderStatus->hasMessage( 'view-pool-contention' )
1018 ? $context->msg( 'view-pool-contention' )->escaped()
1019 : $context->msg( 'view-pool-timeout' )->escaped();
1020 $outputPage->addHTML( "<!-- parser cache is expired, " .
1021 "sending anyway due to $staleReason-->\n" );
1022
1023 // Ensure OutputPage knowns the id from the dirty cache, but keep the current flag (T341013)
1024 $cachedId = $pOutput->getCacheRevisionId();
1025 if ( $cachedId !== null ) {
1026 $outputPage->setRevisionId( $cachedId );
1027 $outputPage->getMetadata()->setRevisionTimestamp( $pOutput->getRevisionTimestamp() );
1028 }
1029 }
1030
1031 // TODO this will probably need to be conditional on cache access and/or hoisted one level above but for
1032 // now let's keep things in the same place and avoid editing StatusValues.
1033 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
1034 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $outputPage->getSkin() );
1035 }
1036
1037 $outputPage->addPostProcessedParserOutput( $pOutput );
1038
1039 if ( $pOutput->getRedirectHeader() !== null ) {
1040 $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
1041 $context->msg( 'redirectpagesub' )->parse() . "</span>" );
1042 }
1043 }
1044
1048 public function adjustDisplayTitle( ParserOutput $pOutput ) {
1049 $out = $this->getContext()->getOutput();
1050
1051 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
1052 $titleText = $pOutput->getTitleText();
1053 if ( $titleText !== '' ) {
1054 # XXX T36514 / T314399 / T306440: we should have a language here
1055 # and split the namespace
1056 $out->setPageTitle( $titleText );
1057 $out->setDisplayTitle( $titleText );
1058 }
1059 }
1060
1065 protected function showDiffPage() {
1066 $context = $this->getContext();
1067 $outputPage = $context->getOutput();
1068 $outputPage->addBodyClasses( 'mw-article-diff' );
1069 $request = $context->getRequest();
1070 $diff = $request->getVal( 'diff' );
1071 $rcid = $request->getInt( 'rcid' );
1072 $purge = $request->getRawVal( 'action' ) === 'purge';
1073 $unhide = $request->getInt( 'unhide' ) === 1;
1074 $oldid = $this->getOldID();
1075
1076 $rev = $this->fetchRevisionRecord();
1077
1078 if ( !$rev ) {
1079 // T213621: $rev maybe null due to either lack of permission to view the
1080 // revision or actually not existing. So let's try loading it from the id
1081 $rev = $this->revisionStore->getRevisionById( $oldid );
1082 }
1083
1084 $services = MediaWikiServices::getInstance();
1085
1086 if ( $rev ) {
1087 $contentHandler = $services
1088 ->getContentHandlerFactory()
1089 ->getContentHandler(
1090 $rev->getMainContentModel()
1091 );
1092
1093 $de = $contentHandler->createDifferenceEngine(
1094 $context,
1095 $oldid,
1096 $diff,
1097 $rcid,
1098 $purge,
1099 $unhide
1100 );
1101 } else {
1102 // We don't have a content handler, so use the default difference engine
1103 // (this will fail eventually, but letting it get this far avoids the need
1104 // to duplicate the logic for printing the failure message)
1105 $de = new DifferenceEngine(
1106 $context,
1107 $oldid,
1108 $diff,
1109 $rcid,
1110 $purge,
1111 $unhide
1112 );
1113 }
1114
1115 $diffType = $request->getVal( 'diff-type' );
1116
1117 if ( $diffType === null ) {
1118 $diffType = $this->userOptionsLookup
1119 ->getOption( $context->getUser(), 'diff-type' );
1120 } else {
1121 $de->setExtraQueryParams( [ 'diff-type' => $diffType ] );
1122 }
1123
1124 $de->setSlotDiffOptions( [
1125 'diff-type' => $diffType,
1126 'expand-url' => $this->viewIsRenderAction,
1127 'inline-toggle' => true,
1128 ] );
1129 $de->showDiffPage( $this->isDiffOnlyView() );
1130
1131 // Run view updates for the newer revision being diffed (and shown
1132 // below the diff if not diffOnly).
1133 $this->mPage->doViewUpdates( $context->getAuthority(), $de->getNewRevision() );
1134
1135 // Add link to help page; see T321569
1136 $context->getOutput()->addHelpLink( 'Help:Diff' );
1137 }
1138
1139 protected function isDiffOnlyView(): bool {
1140 return $this->getContext()->getRequest()->getBool(
1141 'diffonly',
1142 $this->userOptionsLookup->getBoolOption( $this->getContext()->getUser(), 'diffonly' )
1143 );
1144 }
1145
1153 public function getRobotPolicy( $action, ?ParserOutput $pOutput = null ) {
1154 $context = $this->getContext();
1155 $mainConfig = $context->getConfig();
1156 $articleRobotPolicies = $mainConfig->get( MainConfigNames::ArticleRobotPolicies );
1157 $namespaceRobotPolicies = $mainConfig->get( MainConfigNames::NamespaceRobotPolicies );
1158 $defaultRobotPolicy = $mainConfig->get( MainConfigNames::DefaultRobotPolicy );
1159 $title = $this->getTitle();
1160 $ns = $title->getNamespace();
1161
1162 # Don't index user and user talk pages for blocked users (T13443)
1163 if ( $ns === NS_USER || $ns === NS_USER_TALK ) {
1164 $specificTarget = null;
1165 $vagueTarget = null;
1166 $titleText = $title->getText();
1167 if ( IPUtils::isValid( $titleText ) ) {
1168 $vagueTarget = $titleText;
1169 } else {
1170 $specificTarget = $title->getRootText();
1171 }
1172 $block = $this->blockStore->newFromTarget(
1173 $specificTarget, $vagueTarget, false, DatabaseBlockStore::AUTO_NONE );
1174 if ( $block instanceof DatabaseBlock ) {
1175 return [
1176 'index' => 'noindex',
1177 'follow' => 'nofollow'
1178 ];
1179 }
1180 }
1181
1182 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
1183 # Non-articles (special pages etc), and old revisions
1184 return [
1185 'index' => 'noindex',
1186 'follow' => 'nofollow'
1187 ];
1188 } elseif ( $context->getOutput()->isPrintable() ) {
1189 # Discourage indexing of printable versions, but encourage following
1190 return [
1191 'index' => 'noindex',
1192 'follow' => 'follow'
1193 ];
1194 } elseif ( $context->getRequest()->getInt( 'curid' ) ) {
1195 # For ?curid=x urls, disallow indexing
1196 return [
1197 'index' => 'noindex',
1198 'follow' => 'follow'
1199 ];
1200 }
1201
1202 # Otherwise, construct the policy based on the various config variables.
1203 $policy = self::formatRobotPolicy( $defaultRobotPolicy );
1204
1205 if ( isset( $namespaceRobotPolicies[$ns] ) ) {
1206 # Honour customised robot policies for this namespace
1207 $policy = array_merge(
1208 $policy,
1209 self::formatRobotPolicy( $namespaceRobotPolicies[$ns] )
1210 );
1211 }
1212 if ( $title->canUseNoindex() && $pOutput && $pOutput->getIndexPolicy() ) {
1213 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
1214 # a final check that we have really got the parser output.
1215 $policy['index'] = $pOutput->getIndexPolicy();
1216 }
1217
1218 if ( isset( $articleRobotPolicies[$title->getPrefixedText()] ) ) {
1219 # (T16900) site config can override user-defined __INDEX__ or __NOINDEX__
1220 $policy = array_merge(
1221 $policy,
1222 self::formatRobotPolicy( $articleRobotPolicies[$title->getPrefixedText()] )
1223 );
1224 }
1225
1226 return $policy;
1227 }
1228
1236 public static function formatRobotPolicy( $policy ) {
1237 if ( is_array( $policy ) ) {
1238 return $policy;
1239 } elseif ( !$policy ) {
1240 return [];
1241 }
1242
1243 $arr = [];
1244 foreach ( explode( ',', $policy ) as $var ) {
1245 $var = trim( $var );
1246 if ( $var === 'index' || $var === 'noindex' ) {
1247 $arr['index'] = $var;
1248 } elseif ( $var === 'follow' || $var === 'nofollow' ) {
1249 $arr['follow'] = $var;
1250 }
1251 }
1252
1253 return $arr;
1254 }
1255
1263 public function showRedirectedFromHeader() {
1264 $context = $this->getContext();
1265 $redirectSources = $context->getConfig()->get( MainConfigNames::RedirectSources );
1266 $outputPage = $context->getOutput();
1267 $request = $context->getRequest();
1268 $rdfrom = $request->getVal( 'rdfrom' );
1269
1270 // Construct a URL for the current page view, but with the target title
1271 $query = $request->getQueryValues();
1272 unset( $query['rdfrom'] );
1273 unset( $query['title'] );
1274 if ( $this->getTitle()->isRedirect() ) {
1275 // Prevent double redirects
1276 $query['redirect'] = 'no';
1277 }
1278 $redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
1279
1280 if ( $this->mRedirectedFrom ) {
1281 // This is an internally redirected page view.
1282 // We'll need a backlink to the source page for navigation.
1283 if ( $this->getHookRunner()->onArticleViewRedirect( $this ) ) {
1284 $redir = $this->linkRenderer->makeKnownLink(
1285 $this->mRedirectedFrom,
1286 null,
1287 [],
1288 [ 'redirect' => 'no' ]
1289 );
1290
1291 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
1292 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
1293 . "</span>" );
1294
1295 // Add the script to update the displayed URL and
1296 // set the fragment if one was specified in the redirect
1297 $outputPage->addJsConfigVars( [
1298 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1299 ] );
1300 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1301
1302 // Add a <link rel="canonical"> tag
1303 $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
1304
1305 // Tell the output object that the user arrived at this article through a redirect
1306 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
1307
1308 return true;
1309 }
1310 } elseif ( $rdfrom ) {
1311 // This is an externally redirected view, from some other wiki.
1312 // If it was reported from a trusted site, supply a backlink.
1313 if ( $redirectSources && preg_match( $redirectSources, $rdfrom ) ) {
1314 $redir = $this->linkRenderer->makeExternalLink( $rdfrom, $rdfrom, $this->getTitle() );
1315 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
1316 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
1317 . "</span>" );
1318
1319 // Add the script to update the displayed URL
1320 $outputPage->addJsConfigVars( [
1321 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1322 ] );
1323 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1324
1325 return true;
1326 }
1327 }
1328
1329 return false;
1330 }
1331
1341 public function showNamespaceHeader() {
1342 if (
1343 !$this->getTitle()->isTalkPage() &&
1344 $this->getTitle()->exists() &&
1345 !$this->getContext()->msg( 'subjectpageheader' )->isDisabled()
1346 ) {
1347 $this->getContext()->getOutput()->wrapWikiMsg(
1348 "<div class=\"mw-subjectpageheader\">\n$1\n</div>",
1349 [ 'subjectpageheader' ]
1350 );
1351 }
1352
1353 if (
1354 $this->getTitle()->isTalkPage() &&
1355 !$this->getContext()->msg( 'talkpageheader' )->isDisabled()
1356 ) {
1357 $this->getContext()->getOutput()->wrapWikiMsg(
1358 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1359 [ 'talkpageheader' ]
1360 );
1361 }
1362 }
1363
1367 public function showViewFooter() {
1368 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1369 if ( $this->getTitle()->getNamespace() === NS_USER_TALK
1370 && IPUtils::isValid( $this->getTitle()->getText() )
1371 ) {
1372 $this->getContext()->getOutput()->addWikiMsg( 'anontalkpagetext' );
1373 }
1374
1375 // Show a footer allowing the user to patrol the shown revision or page if possible
1376 $patrolFooterShown = $this->showPatrolFooter();
1377
1378 $this->getHookRunner()->onArticleViewFooter( $this, $patrolFooterShown );
1379 }
1380
1391 public function showPatrolFooter() {
1392 $context = $this->getContext();
1393 $mainConfig = $context->getConfig();
1394 $useNPPatrol = $mainConfig->get( MainConfigNames::UseNPPatrol );
1395 $useRCPatrol = $mainConfig->get( MainConfigNames::UseRCPatrol );
1396 $useFilePatrol = $mainConfig->get( MainConfigNames::UseFilePatrol );
1397 $fileMigrationStage = $mainConfig->get( MainConfigNames::FileSchemaMigrationStage );
1398 // Allow hooks to decide whether to not output this at all
1399 if ( !$this->getHookRunner()->onArticleShowPatrolFooter( $this ) ) {
1400 return false;
1401 }
1402
1403 $outputPage = $context->getOutput();
1404 $user = $context->getUser();
1405 $title = $this->getTitle();
1406 $rc = false;
1407
1408 if ( !$context->getAuthority()->probablyCan( 'patrol', $title )
1409 || !( $useRCPatrol || $useNPPatrol
1410 || ( $useFilePatrol && $title->inNamespace( NS_FILE ) ) )
1411 ) {
1412 // Patrolling is disabled or the user isn't allowed to
1413 return false;
1414 }
1415
1416 if ( $this->mRevisionRecord
1417 && !RecentChange::isInRCLifespan( $this->mRevisionRecord->getTimestamp(), 21600 )
1418 ) {
1419 // The latest revision is already older than what could be in the RC table
1420 // 6h tolerance because the RC might not be cleaned out regularly
1421 return false;
1422 }
1423
1424 // Check for cached results
1425 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1426 $key = $cache->makeKey( 'unpatrollable-page', $title->getArticleID() );
1427 if ( $cache->get( $key ) ) {
1428 return false;
1429 }
1430
1431 $dbr = $this->dbProvider->getReplicaDatabase();
1432 $oldestRevisionRow = $dbr->newSelectQueryBuilder()
1433 ->select( [ 'rev_id', 'rev_timestamp' ] )
1434 ->from( 'revision' )
1435 ->where( [ 'rev_page' => $title->getArticleID() ] )
1436 ->orderBy( [ 'rev_timestamp', 'rev_id' ] )
1437 ->caller( __METHOD__ )->fetchRow();
1438 $oldestRevisionTimestamp = $oldestRevisionRow ? $oldestRevisionRow->rev_timestamp : false;
1439
1440 // New page patrol: Get the timestamp of the oldest revision which
1441 // the revision table holds for the given page. Then we look
1442 // whether it's within the RC lifespan and if it is, we try
1443 // to get the recentchanges row belonging to that entry.
1444 $recentPageCreation = false;
1445 if ( $oldestRevisionTimestamp
1446 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1447 ) {
1448 // 6h tolerance because the RC might not be cleaned out regularly
1449 $recentPageCreation = true;
1450 $rc = $this->recentChangeLookup->getRecentChangeByConds(
1451 [
1452 'rc_this_oldid' => intval( $oldestRevisionRow->rev_id ),
1453 // Avoid selecting a categorization entry
1454 'rc_source' => RecentChange::SRC_NEW,
1455 ],
1456 __METHOD__
1457 );
1458 if ( $rc ) {
1459 // Use generic patrol message for new pages
1460 $markPatrolledMsg = $context->msg( 'markaspatrolledtext' );
1461 }
1462 }
1463
1464 // File patrol: Get the timestamp of the latest upload for this page,
1465 // check whether it is within the RC lifespan and if it is, we try
1466 // to get the recentchanges row belonging to that entry
1467 // (with rc_source = SRC_LOG, rc_log_type = upload).
1468 $recentFileUpload = false;
1469 if ( ( !$rc || $rc->getAttribute( 'rc_patrolled' ) ) && $useFilePatrol
1470 && $title->getNamespace() === NS_FILE ) {
1471 // Retrieve timestamp from the current file (latest upload)
1472 if ( $fileMigrationStage & SCHEMA_COMPAT_READ_OLD ) {
1473 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1474 ->select( 'img_timestamp' )
1475 ->from( 'image' )
1476 ->where( [ 'img_name' => $title->getDBkey() ] )
1477 ->caller( __METHOD__ )->fetchField();
1478 } else {
1479 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1480 ->select( 'fr_timestamp' )
1481 ->from( 'file' )
1482 ->join( 'filerevision', null, 'file_latest = fr_id' )
1483 ->where( [ 'file_name' => $title->getDBkey() ] )
1484 ->caller( __METHOD__ )->fetchField();
1485 }
1486
1487 if ( $newestUploadTimestamp
1488 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1489 ) {
1490 // 6h tolerance because the RC might not be cleaned out regularly
1491 $recentFileUpload = true;
1492 $rc = $this->recentChangeLookup->getRecentChangeByConds(
1493 [
1494 'rc_source' => RecentChange::SRC_LOG,
1495 'rc_log_type' => 'upload',
1496 'rc_timestamp' => $newestUploadTimestamp,
1497 'rc_namespace' => NS_FILE,
1498 'rc_cur_id' => $title->getArticleID()
1499 ],
1500 __METHOD__
1501 );
1502 if ( $rc ) {
1503 // Use patrol message specific to files
1504 $markPatrolledMsg = $context->msg( 'markaspatrolledtext-file' );
1505 }
1506 }
1507 }
1508
1509 if ( !$recentPageCreation && !$recentFileUpload ) {
1510 // Page creation and latest upload (for files) is too old to be in RC
1511
1512 // We definitely can't patrol so cache the information
1513 // When a new file version is uploaded, the cache is cleared
1514 $cache->set( $key, '1' );
1515
1516 return false;
1517 }
1518
1519 if ( !$rc ) {
1520 // Don't cache: This can be hit if the page gets accessed very fast after
1521 // its creation / latest upload or in case we have high replica DB lag. In case
1522 // the revision is too old, we will already return above.
1523 return false;
1524 }
1525
1526 if ( $rc->getAttribute( 'rc_patrolled' ) ) {
1527 // Patrolled RC entry around
1528
1529 // Cache the information we gathered above in case we can't patrol
1530 // Don't cache in case we can patrol as this could change
1531 $cache->set( $key, '1' );
1532
1533 return false;
1534 }
1535
1536 if ( $rc->getPerformerIdentity()->equals( $user ) ) {
1537 // Don't show a patrol link for own creations/uploads. If the user could
1538 // patrol them, they already would be patrolled
1539 return false;
1540 }
1541
1542 $outputPage->getMetadata()->setPreventClickjacking( true );
1543 $outputPage->addModules( 'mediawiki.misc-authed-curate' );
1544
1545 $link = $this->linkRenderer->makeKnownLink(
1546 $title,
1547 new HtmlArmor( '<button class="cdx-button cdx-button--action-progressive">'
1548 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable $markPatrolledMsg is always set
1549 . $markPatrolledMsg->escaped() . '</button>' ),
1550 [],
1551 [
1552 'action' => 'markpatrolled',
1553 'rcid' => $rc->getAttribute( 'rc_id' ),
1554 ]
1555 );
1556
1557 $outputPage->addModuleStyles( 'mediawiki.action.styles' );
1558 $outputPage->addHTML( "<div class='patrollink' data-mw-interface>$link</div>" );
1559
1560 return true;
1561 }
1562
1569 public static function purgePatrolFooterCache( $articleID ) {
1570 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1571 $cache->delete( $cache->makeKey( 'unpatrollable-page', $articleID ) );
1572 }
1573
1578 public function showMissingArticle() {
1579 $context = $this->getContext();
1580 $send404Code = $context->getConfig()->get( MainConfigNames::Send404Code );
1581
1582 $outputPage = $context->getOutput();
1583 // Whether the page is a root user page of an existing user (but not a subpage)
1584 $validUserPage = false;
1585
1586 $title = $this->getTitle();
1587
1588 $services = MediaWikiServices::getInstance();
1589
1590 $contextUser = $context->getUser();
1591
1592 # Indicate to client-side JS (Visual Editor in particular) whether
1593 # Parsoid would be used to render this article if created
1594 if ( $this->getParserOptions()->getUseParsoid() ) {
1595 $outputPage->addJsConfigVars(
1596 'wgParsoidHtmlVersion',
1597 Parsoid::defaultHTMLVersion()
1598 );
1599 }
1600
1601 # Show info in user (talk) namespace. Does the user exist? Are they blocked?
1602 if ( $title->getNamespace() === NS_USER
1603 || $title->getNamespace() === NS_USER_TALK
1604 ) {
1605 $rootPart = $title->getRootText();
1606 $userFactory = $services->getUserFactory();
1607 $user = $userFactory->newFromNameOrIp( $rootPart );
1608
1609 if ( $user && $user->isRegistered() && $user->isHidden() &&
1610 !$context->getAuthority()->isAllowed( 'hideuser' )
1611 ) {
1612 // T120883 if the user is hidden and the viewer cannot see hidden
1613 // users, pretend like it does not exist at all.
1614 $user = false;
1615 }
1616
1617 if ( !( $user && $user->isRegistered() ) && !$this->userNameUtils->isIP( $rootPart ) ) {
1618 $this->addMessageBoxStyles( $outputPage );
1619 // User does not exist
1620 $outputPage->addHTML( Html::warningBox(
1621 $context->msg( 'userpage-userdoesnotexist-view', wfEscapeWikiText( $rootPart ) )->parse(),
1622 'mw-userpage-userdoesnotexist'
1623 ) );
1624
1625 // Show renameuser log extract
1626 LogEventsList::showLogExtract(
1627 $outputPage,
1628 'renameuser',
1629 Title::makeTitleSafe( NS_USER, $rootPart ),
1630 '',
1631 [
1632 'lim' => 10,
1633 'showIfEmpty' => false,
1634 'msgKey' => [ 'renameuser-renamed-notice', $title->getBaseText() ]
1635 ]
1636 );
1637 } else {
1638 $validUserPage = !$title->isSubpage();
1639
1640 $blockLogBox = LogEventsList::getBlockLogWarningBox(
1641 $this->blockStore,
1642 $services->getNamespaceInfo(),
1643 $this->getContext(),
1644 $this->linkRenderer,
1645 $user,
1646 $title
1647 );
1648 if ( $blockLogBox !== null ) {
1649 $outputPage->addHTML( $blockLogBox );
1650 }
1651 }
1652 }
1653
1654 $this->getHookRunner()->onShowMissingArticle( $this );
1655
1656 # Show delete and move logs if there were any such events.
1657 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1658 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1659 $dbCache = MediaWikiServices::getInstance()->getMainObjectStash();
1660 $key = $dbCache->makeKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
1661 $isRegistered = $contextUser->isRegistered();
1662 $sessionExists = $context->getRequest()->getSession()->isPersistent();
1663
1664 if ( $isRegistered || $dbCache->get( $key ) || $sessionExists ) {
1665 $logTypes = [ 'delete', 'move', 'protect', 'merge' ];
1666
1667 $dbr = $this->dbProvider->getReplicaDatabase();
1668
1669 $conds = [ $dbr->expr( 'log_action', '!=', 'revision' ) ];
1670 // Give extensions a chance to hide their (unrelated) log entries
1671 $this->getHookRunner()->onArticle__MissingArticleConditions( $conds, $logTypes );
1672 LogEventsList::showLogExtract(
1673 $outputPage,
1674 $logTypes,
1675 $title,
1676 '',
1677 [
1678 'lim' => 10,
1679 'conds' => $conds,
1680 'showIfEmpty' => false,
1681 'msgKey' => [ $isRegistered || $sessionExists
1682 ? 'moveddeleted-notice'
1683 : 'moveddeleted-notice-recent'
1684 ]
1685 ]
1686 );
1687 }
1688
1689 if ( !$this->mPage->hasViewableContent() && $send404Code && !$validUserPage ) {
1690 // If there's no backing content, send a 404 Not Found
1691 // for better machine handling of broken links.
1692 $context->getRequest()->response()->statusHeader( 404 );
1693 }
1694
1695 // Also apply the robot policy for nonexisting pages (even if a 404 was used)
1696 $policy = $this->getRobotPolicy( 'view' );
1697 $outputPage->getMetadata()->setIndexPolicy( $policy['index'] );
1698 $outputPage->setFollowPolicy( $policy['follow'] );
1699
1700 $hookResult = $this->getHookRunner()->onBeforeDisplayNoArticleText( $this );
1701
1702 if ( !$hookResult ) {
1703 return;
1704 }
1705
1706 # Show error message
1707 $oldid = $this->getOldID();
1708 if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
1709 $text = $this->getTitle()->getDefaultMessageText() ?? '';
1710 $outputPage->addWikiTextAsContent( $text );
1711 } else {
1712 if ( $oldid ) {
1713 $text = $this->getMissingRevisionMsg( $oldid )->plain();
1714 } elseif ( $context->getAuthority()->probablyCan( 'edit', $title ) ) {
1715 $message = $isRegistered ? 'noarticletext' : 'noarticletextanon';
1716 $text = $context->msg( $message )->plain();
1717 } else {
1718 $text = $context->msg( 'noarticletext-nopermission' )->plain();
1719 }
1720
1721 $dir = $context->getLanguage()->getDir();
1722 $lang = $context->getLanguage()->getHtmlCode();
1723 $outputPage->addWikiTextAsInterface( Html::openElement( 'div', [
1724 'class' => "noarticletext mw-content-$dir",
1725 'dir' => $dir,
1726 'lang' => $lang,
1727 ] ) . "\n$text\n</div>" );
1728 }
1729 }
1730
1735 private function showViewError( string $errortext ) {
1736 $outputPage = $this->getContext()->getOutput();
1737 $outputPage->setPageTitleMsg( $this->getContext()->msg( 'errorpagetitle' ) );
1738 $outputPage->disableClientCache();
1739 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1740 $outputPage->clearHTML();
1741 $this->addMessageBoxStyles( $outputPage );
1742 $outputPage->addHTML( Html::errorBox( $outputPage->parseAsContent( $errortext ) ) );
1743 }
1744
1751 public function showDeletedRevisionHeader() {
1752 if ( !$this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
1753 // Not deleted
1754 return true;
1755 }
1756 $outputPage = $this->getContext()->getOutput();
1757 // Used in wikilinks, should not contain whitespaces
1758 $titleText = $this->getTitle()->getPrefixedURL();
1759 $this->addMessageBoxStyles( $outputPage );
1760 // If the user is not allowed to see it...
1761 if ( !$this->mRevisionRecord->userCan(
1762 RevisionRecord::DELETED_TEXT,
1763 $this->getContext()->getAuthority()
1764 ) ) {
1765 $outputPage->addHTML(
1766 Html::warningBox(
1767 $outputPage->msg( 'rev-deleted-text-permission', $titleText )->parse(),
1768 'plainlinks'
1769 )
1770 );
1771
1772 return false;
1773 // If the user needs to confirm that they want to see it...
1774 } elseif ( $this->getContext()->getRequest()->getInt( 'unhide' ) !== 1 ) {
1775 # Give explanation and add a link to view the revision...
1776 $oldid = intval( $this->getOldID() );
1777 $link = $this->getTitle()->getFullURL( "oldid={$oldid}&unhide=1" );
1778 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ?
1779 'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
1780 $outputPage->addHTML(
1781 Html::warningBox(
1782 $outputPage->msg( $msg, $link )->parse(),
1783 'plainlinks'
1784 )
1785 );
1786
1787 return false;
1788 // We are allowed to see...
1789 } else {
1790 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED )
1791 ? [ 'rev-suppressed-text-view', $titleText ]
1792 : [ 'rev-deleted-text-view', $titleText ];
1793 $outputPage->addHTML(
1794 Html::warningBox(
1795 $outputPage->msg( $msg[0], $msg[1] )->parse(),
1796 'plainlinks'
1797 )
1798 );
1799
1800 return true;
1801 }
1802 }
1803
1804 private function addMessageBoxStyles( OutputPage $outputPage ) {
1805 $outputPage->addModuleStyles( [
1806 'mediawiki.codex.messagebox.styles',
1807 ] );
1808 }
1809
1818 public function setOldSubtitle( $oldid = 0 ) {
1819 if ( !$this->getHookRunner()->onDisplayOldSubtitle( $this, $oldid ) ) {
1820 return;
1821 }
1822
1823 $context = $this->getContext();
1824 $unhide = $context->getRequest()->getInt( 'unhide' ) === 1;
1825
1826 # Cascade unhide param in links for easy deletion browsing
1827 $extraParams = [];
1828 if ( $unhide ) {
1829 $extraParams['unhide'] = 1;
1830 }
1831
1832 if ( $this->mRevisionRecord && $this->mRevisionRecord->getId() === $oldid ) {
1833 $revisionRecord = $this->mRevisionRecord;
1834 } else {
1835 $revisionRecord = $this->revisionStore->getRevisionById( $oldid );
1836 }
1837 if ( !$revisionRecord ) {
1838 throw new LogicException( 'There should be a revision record at this point.' );
1839 }
1840
1841 $timestamp = $revisionRecord->getTimestamp();
1842
1843 $current = ( $oldid == $this->mPage->getLatest() );
1844 $language = $context->getLanguage();
1845 $user = $context->getUser();
1846
1847 $td = $language->userTimeAndDate( $timestamp, $user );
1848 $tddate = $language->userDate( $timestamp, $user );
1849 $tdtime = $language->userTime( $timestamp, $user );
1850
1851 # Show user links if allowed to see them. If hidden, then show them only if requested...
1852 $userlinks = Linker::revUserTools( $revisionRecord, !$unhide );
1853
1854 $infomsg = $current && !$context->msg( 'revision-info-current' )->isDisabled()
1855 ? 'revision-info-current'
1856 : 'revision-info';
1857
1858 $outputPage = $context->getOutput();
1859 $outputPage->addModuleStyles( [
1860 'mediawiki.action.styles',
1861 'mediawiki.interface.helpers.styles'
1862 ] );
1863
1864 $revisionUser = $revisionRecord->getUser();
1865 $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
1866 $context->msg( $infomsg, $td )
1867 ->rawParams( $userlinks )
1868 ->params(
1869 $revisionRecord->getId(),
1870 $tddate,
1871 $tdtime,
1872 $revisionUser ? $revisionUser->getName() : ''
1873 )
1874 ->rawParams( $this->commentFormatter->formatRevision(
1875 $revisionRecord,
1876 $user,
1877 true,
1878 !$unhide
1879 ) )
1880 ->parse() .
1881 "</div>";
1882
1883 $lnk = $current
1884 ? $context->msg( 'currentrevisionlink' )->escaped()
1885 : $this->linkRenderer->makeKnownLink(
1886 $this->getTitle(),
1887 $context->msg( 'currentrevisionlink' )->text(),
1888 [],
1889 $extraParams
1890 );
1891 $curdiff = $current
1892 ? $context->msg( 'diff' )->escaped()
1893 : $this->linkRenderer->makeKnownLink(
1894 $this->getTitle(),
1895 $context->msg( 'diff' )->text(),
1896 [],
1897 [
1898 'diff' => 'cur',
1899 'oldid' => $oldid
1900 ] + $extraParams
1901 );
1902 $prevExist = (bool)$this->revisionStore->getPreviousRevision( $revisionRecord );
1903 $prevlink = $prevExist
1904 ? $this->linkRenderer->makeKnownLink(
1905 $this->getTitle(),
1906 $context->msg( 'previousrevision' )->text(),
1907 [],
1908 [
1909 'direction' => 'prev',
1910 'oldid' => $oldid
1911 ] + $extraParams
1912 )
1913 : $context->msg( 'previousrevision' )->escaped();
1914 $prevdiff = $prevExist
1915 ? $this->linkRenderer->makeKnownLink(
1916 $this->getTitle(),
1917 $context->msg( 'diff' )->text(),
1918 [],
1919 [
1920 'diff' => 'prev',
1921 'oldid' => $oldid
1922 ] + $extraParams
1923 )
1924 : $context->msg( 'diff' )->escaped();
1925 $nextlink = $current
1926 ? $context->msg( 'nextrevision' )->escaped()
1927 : $this->linkRenderer->makeKnownLink(
1928 $this->getTitle(),
1929 $context->msg( 'nextrevision' )->text(),
1930 [],
1931 [
1932 'direction' => 'next',
1933 'oldid' => $oldid
1934 ] + $extraParams
1935 );
1936 $nextdiff = $current
1937 ? $context->msg( 'diff' )->escaped()
1938 : $this->linkRenderer->makeKnownLink(
1939 $this->getTitle(),
1940 $context->msg( 'diff' )->text(),
1941 [],
1942 [
1943 'diff' => 'next',
1944 'oldid' => $oldid
1945 ] + $extraParams
1946 );
1947
1948 $cdel = Linker::getRevDeleteLink(
1949 $context->getAuthority(),
1950 $revisionRecord,
1951 $this->getTitle()
1952 );
1953 if ( $cdel !== '' ) {
1954 $cdel .= ' ';
1955 }
1956
1957 // the outer div is need for styling the revision info and nav in MobileFrontend
1958 $this->addMessageBoxStyles( $outputPage );
1959 $outputPage->addSubtitle(
1960 Html::warningBox(
1961 $revisionInfo .
1962 "<div id=\"mw-revision-nav\">" . $cdel .
1963 $context->msg( 'revision-nav' )->rawParams(
1964 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1965 )->escaped() . "</div>",
1966 'mw-revision'
1967 )
1968 );
1969 }
1970
1979 public function addHelpLink( $to, $overrideBaseUrl = false ) {
1980 $out = $this->getContext()->getOutput();
1981 $msg = $out->msg( 'namespace-' . $this->getTitle()->getNamespace() . '-helppage' );
1982
1983 if ( !$msg->isDisabled() ) {
1984 $title = Title::newFromText( $msg->plain() );
1985 if ( $title instanceof Title ) {
1986 $out->addHelpLink( $title->getLocalURL(), true );
1987 }
1988 } else {
1989 $out->addHelpLink( $to, $overrideBaseUrl );
1990 }
1991 }
1992
1996 public function render() {
1997 $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
1998 $this->getContext()->getOutput()->setArticleBodyOnly( true );
1999 // We later set suppress section edit links based on this; also used by ImagePage
2000 $this->viewIsRenderAction = true;
2001 $this->view();
2002 }
2003
2007 public function protect() {
2008 $form = new ProtectionForm( $this );
2009 $form->execute();
2010 }
2011
2015 public function unprotect() {
2016 $this->protect();
2017 }
2018
2019 /* Caching functions */
2020
2028 protected function tryFileCache() {
2029 static $called = false;
2030
2031 if ( $called ) {
2032 wfDebug( "Article::tryFileCache(): called twice!?" );
2033 return false;
2034 }
2035
2036 $called = true;
2037 if ( $this->isFileCacheable() ) {
2038 $cache = new HTMLFileCache( $this->getTitle(), 'view' );
2039 if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
2040 wfDebug( "Article::tryFileCache(): about to load file" );
2041 $cache->loadFromFileCache( $this->getContext() );
2042 return true;
2043 } else {
2044 wfDebug( "Article::tryFileCache(): starting buffer" );
2045 ob_start( $cache->saveToFileCache( ... ) );
2046 }
2047 } else {
2048 wfDebug( "Article::tryFileCache(): not cacheable" );
2049 }
2050
2051 return false;
2052 }
2053
2059 public function isFileCacheable( $mode = HTMLFileCache::MODE_NORMAL ) {
2060 $cacheable = false;
2061
2062 if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
2063 $cacheable = $this->mPage->getId()
2064 && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
2065 // Extension may have reason to disable file caching on some pages.
2066 if ( $cacheable ) {
2067 $cacheable = $this->getHookRunner()->onIsFileCacheable( $this ) ?? false;
2068 }
2069 }
2070
2071 return $cacheable;
2072 }
2073
2087 public function getParserOutput( $oldid = null, ?UserIdentity $user = null, array $options = [] ) {
2088 $parserOptions = $this->getParserOptions( $oldid, $user );
2089 return $this->mPage->getParserOutput( $parserOptions, $oldid, options: $options );
2090 }
2091
2096 public function getParserOptions( ?int $oldid = null, ?UserIdentity $user = null ) {
2097 $parserOptions =
2098 $this->mPage->makeParserOptions( $user ?? $this->getContext() );
2099 $parserOptions->setRenderReason( $oldid ? 'page_view_oldid' : 'page_view' );
2100 # Allow extensions to vary parser options used for article rendering
2101 $services = MediaWikiServices::getInstance();
2102 ( new HookRunner( $services->getHookContainer() ) )
2103 ->onArticleParserOptions( $this, $parserOptions );
2104
2105 return $parserOptions;
2106 }
2107
2114 public function setContext( $context ) {
2115 $this->mContext = $context;
2116 }
2117
2124 public function getContext(): IContextSource {
2125 if ( $this->mContext instanceof IContextSource ) {
2126 return $this->mContext;
2127 } else {
2128 wfDebug( __METHOD__ . " called and \$mContext is null. " .
2129 "Return RequestContext::getMain()" );
2130 return RequestContext::getMain();
2131 }
2132 }
2133
2139 public function getActionOverrides() {
2140 return $this->mPage->getActionOverrides();
2141 }
2142
2143 private function getMissingRevisionMsg( int $oldid ): Message {
2144 // T251066: Try loading the revision from the archive table.
2145 // Show link to view it if it exists and the user has permission to view it.
2146 // (Ignore the given title, if any; look it up from the revision instead.)
2147 $context = $this->getContext();
2148 $revRecord = $this->archivedRevisionLookup->getArchivedRevisionRecord( null, $oldid );
2149 if (
2150 $revRecord &&
2151 $revRecord->userCan(
2152 RevisionRecord::DELETED_TEXT,
2153 $context->getAuthority()
2154 ) &&
2155 $context->getAuthority()->isAllowedAny( 'deletedtext', 'undelete' )
2156 ) {
2157 // You can see deleted content. So we know exactly what page is it on
2158 // and can render the message in that context regardless of what
2159 // title (if any) is given in URL params
2160 return $context->msg(
2161 'missing-revision-permission',
2162 $oldid,
2163 $revRecord->getTimestamp(),
2164 Title::newFromPageIdentity( $revRecord->getPage() )->getPrefixedURL()
2165 )->page( $revRecord->getPage() );
2166 }
2167
2168 if ( $context->getRequest()->getCheck( 'title' ) ) {
2169 // If you specify a title then link to the deletion log for that title
2170 return $context->msg( 'missing-revision', $oldid );
2171 } else {
2172 // Don't show the deletion log for the main page if you don't specify a title
2173 return $context->msg( 'missing-revision-nolog', $oldid );
2174 }
2175 }
2176
2177 private function usePostProcessingCache( ParserOptions $poptions ): bool {
2178 if ( $poptions->getUseParsoid() ) {
2179 return $this->parsoidPostprocCacheAvailable;
2180 }
2181 return $this->legacyPostprocCacheAvailable && $this->useLegacyPostprocCache;
2182 }
2183
2189 public function setUseLegacyPostprocCache( bool $val = true ): void {
2190 $this->useLegacyPostprocCache = $val;
2191 }
2192}
2193
2195class_alias( Article::class, 'Article' );
const NS_USER
Definition Defines.php:53
const NS_FILE
Definition Defines.php:57
const NS_MEDIAWIKI
Definition Defines.php:59
const SCHEMA_COMPAT_READ_OLD
Definition Defines.php:294
const NS_MEDIA
Definition Defines.php:39
const NS_USER_TALK
Definition Defines.php:54
const NS_CATEGORY
Definition Defines.php:65
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Page view caching in the file system.
This is the main service interface for converting single-line comments from various DB comment fields...
Group all the pieces relevant to the context of a request into one instance.
makeTitle( $linkId)
Convert a link ID to a Title.to override Title
DifferenceEngine is responsible for rendering the difference between two revisions as HTML.
The HTML user interface for page editing.
Definition EditPage.php:130
Show an error when a user tries to do something they do not have the necessary permissions for.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
This class is a collection of static functions that serve two purposes:
Definition Html.php:44
Handle enqueueing of background jobs.
Class that generates HTML for internal links.
Some internal bits split of from Skin.php.
Definition Linker.php:47
A class containing constants representing the names of configuration variables.
const UsePostprocCacheParsoid
Name constant for the UsePostprocCacheParsoid setting, for use with Config::get()
const UsePostprocCacheLegacy
Name constant for the UsePostprocCacheLegacy setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
This is one of the Core classes and should be read at least once by any new developers.
addSubtitle( $str)
Add $str to the subtitle.
addModuleStyles( $modules)
Load the styles of one or more style-only ResourceLoader modules on this page.
Legacy class representing an editable page and handling UI for some page actions.
Definition Article.php:66
render()
Handle action=render.
Definition Article.php:1996
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
Definition Article.php:1236
static purgePatrolFooterCache( $articleID)
Purge the cache used to check if it is worth showing the patrol footer For example,...
Definition Article.php:1569
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:219
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, such as [[MediaWiki:Subjectpageheader...
Definition Article.php:1341
showViewFooter()
Show the footer section of an ordinary page view.
Definition Article.php:1367
IConnectionProvider $dbProvider
Definition Article.php:122
int null $mOldId
The oldid of the article that was requested to be shown, 0 for the latest revision.
Definition Article.php:85
showPatrolFooter()
If patrol is possible, output a patrol UI box.
Definition Article.php:1391
setOldSubtitle( $oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Definition Article.php:1818
Title null $mRedirectedFrom
Title from which we were redirected here, if any.
Definition Article.php:88
setContext( $context)
Sets the context this Article is executed in.
Definition Article.php:2114
bool $viewIsRenderAction
Whether render() was called.
Definition Article.php:111
getRedirectedFrom()
Get the page this view was redirected from.
Definition Article.php:230
showProtectionIndicator()
Show a lock icon above the article body if the page is protected.
Definition Article.php:595
view()
This is the default action of the index.php entry point: just view the page of the given title.
Definition Article.php:451
getRevIdFetched()
Use this to fetch the rev ID used on page views.
Definition Article.php:437
getParserOutput( $oldid=null, ?UserIdentity $user=null, array $options=[])
Lightweight method to get the parser output for a page, checking the parser cache and so on.
Definition Article.php:2087
string false $mRedirectUrl
URL to redirect to or false if none.
Definition Article.php:91
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
Definition Article.php:418
getParserOptions(?int $oldid=null, ?UserIdentity $user=null)
Get parser options suitable for rendering the primary article wikitext.
Definition Article.php:2096
static newFromID( $id)
Constructor from a page id.
Definition Article.php:180
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
Definition Article.php:2028
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
Definition Article.php:1263
getPage()
Get the WikiPage object of this instance.
Definition Article.php:257
protect()
action=protect handler
Definition Article.php:2007
ParserOutput null false $mParserOutput
The ParserOutput generated for viewing the page, initialized by view().
Definition Article.php:104
fetchRevisionRecord()
Fetches the revision to work on.
Definition Article.php:360
DatabaseBlockStore $blockStore
Definition Article.php:123
newPage(Title $title)
Definition Article.php:172
RestrictionStore $restrictionStore
Definition Article.php:124
LinkRenderer $linkRenderer
Definition Article.php:113
setUseLegacyPostprocCache(bool $val=true)
By default, we do not use the postprocessing cache for legacy parses; however, we want to be able to ...
Definition Article.php:2189
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
Definition Article.php:1751
getTitle()
Get the title object of the article.
Definition Article.php:247
showDiffPage()
Show a diff page according to current request variables.
Definition Article.php:1065
getActionOverrides()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2139
WikiPage $mPage
The WikiPage object of this instance.
Definition Article.php:79
isFileCacheable( $mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
Definition Article.php:2059
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
Definition Article.php:238
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
Definition Article.php:1048
showMissingArticle()
Show the error text for a missing article.
Definition Article.php:1578
getRobotPolicy( $action, ?ParserOutput $pOutput=null)
Get the robot policy to be used for the current view.
Definition Article.php:1153
unprotect()
action=unprotect handler (alias)
Definition Article.php:2015
getContext()
Gets the context this Article is executed in.
Definition Article.php:2124
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition Article.php:1979
__construct(Title $title, $oldId=null)
Definition Article.php:142
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
Definition Article.php:292
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:191
Special handling for category description pages.
Rendering of file description pages.
Definition ImagePage.php:34
Handles the page protection UI and backend.
Service for creating WikiPage objects.
Base representation for an editable wiki page.
Definition WikiPage.php:83
getTitle()
Get the title object of the article.
Definition WikiPage.php:251
Set options of the Parser.
ParserOutput is a rendering of a Content object or a message.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:138
A StatusValue for permission errors.
Utility class for creating and reading rows in the recentchanges table.
Exception raised when the text of a revision is permanently missing or corrupt.
Page revision base class.
Service for looking up page revisions.
The base class for all skins.
Definition Skin.php:53
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Represents a title within MediaWiki.
Definition Title.php:69
Provides access to user options.
UserNameUtils service.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
hasMessage(string $message)
Returns true if the specified message is present as a warning or error.
isOK()
Returns whether the operation completed.
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:18
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchstarPopover' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\RecentChanges\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
Interface for objects which can provide a MediaWiki context on request.
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
Definition Page.php:18
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
Interface for objects representing user identity.
Provide primary and replica IDatabase connections.
msg( $key,... $params)