MediaWiki master
Article.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Page;
8
9use LogicException;
19use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
51use Wikimedia\IPUtils;
52use Wikimedia\NonSerializable\NonSerializableTrait;
54
64class Article implements Page {
65 use ProtectedHookAccessorTrait;
66 use NonSerializableTrait;
67
73 protected $mContext;
74
76 protected $mPage;
77
82 public $mOldId;
83
85 public $mRedirectedFrom = null;
86
88 public $mRedirectUrl = false;
89
94 private $fetchResult = null;
95
101 public $mParserOutput = null;
102
108 protected $viewIsRenderAction = false;
109
111 private RevisionStore $revisionStore;
112 private UserNameUtils $userNameUtils;
113 private UserOptionsLookup $userOptionsLookup;
114 private CommentFormatter $commentFormatter;
115 private WikiPageFactory $wikiPageFactory;
116 private JobQueueGroup $jobQueueGroup;
117 private ArchivedRevisionLookup $archivedRevisionLookup;
118 private RecentChangeLookup $recentChangeLookup;
122 private bool $useLegacyPostprocCache;
123
130 private $mRevisionRecord = null;
131
132 private bool $parsoidPostprocCacheAvailable;
133 private bool $legacyPostprocCacheAvailable;
134
139 public function __construct( Title $title, $oldId = null ) {
140 $this->mOldId = $oldId;
141 $this->mPage = $this->newPage( $title );
142
143 $services = MediaWikiServices::getInstance();
144 $this->linkRenderer = $services->getLinkRenderer();
145 $this->revisionStore = $services->getRevisionStore();
146 $this->userNameUtils = $services->getUserNameUtils();
147 $this->userOptionsLookup = $services->getUserOptionsLookup();
148 $this->commentFormatter = $services->getCommentFormatter();
149 $this->wikiPageFactory = $services->getWikiPageFactory();
150 $this->jobQueueGroup = $services->getJobQueueGroup();
151 $this->archivedRevisionLookup = $services->getArchivedRevisionLookup();
152 $this->recentChangeLookup = $services->getRecentChangeLookup();
153 $this->dbProvider = $services->getConnectionProvider();
154 $this->blockStore = $services->getDatabaseBlockStore();
155 $this->restrictionStore = $services->getRestrictionStore();
156 $this->parsoidPostprocCacheAvailable =
158 // TODO remove when the config has been switched to UsePostprocCacheParsoid
160 $this->legacyPostprocCacheAvailable =
162 $this->useLegacyPostprocCache = false;
163 }
164
169 protected function newPage( Title $title ) {
170 return new WikiPage( $title );
171 }
172
177 public static function newFromID( $id ): ?static {
178 $t = Title::newFromID( $id );
179 return $t === null ? null : new static( $t );
180 }
181
188 public static function newFromTitle( $title, IContextSource $context ): static {
189 if ( $title->getNamespace() === NS_MEDIA ) {
190 // XXX: This should not be here, but where should it go?
191 $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
192 }
193
194 $page = null;
195 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
196 // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
197 ->onArticleFromTitle( $title, $page, $context );
198
199 $page ??= match ( $title->getNamespace() ) {
200 NS_FILE => new ImagePage( $title ),
201 NS_CATEGORY => new CategoryPage( $title ),
202 default => new Article( $title )
203 };
204 $page->setContext( $context );
205
206 return $page;
207 }
208
216 public static function newFromWikiPage( WikiPage $page, IContextSource $context ) {
217 $article = self::newFromTitle( $page->getTitle(), $context );
218 $article->mPage = $page; // override to keep process cached vars
219 return $article;
220 }
221
227 public function getRedirectedFrom() {
228 return $this->mRedirectedFrom;
229 }
230
235 public function setRedirectedFrom( Title $from ) {
236 $this->mRedirectedFrom = $from;
237 }
238
244 public function getTitle() {
245 return $this->mPage->getTitle();
246 }
247
254 public function getPage() {
255 return $this->mPage;
256 }
257
258 public function clear() {
259 $this->mRedirectedFrom = null; # Title object if set
260 $this->mRedirectUrl = false;
261 $this->mRevisionRecord = null;
262 $this->fetchResult = null;
263
264 // TODO hard-deprecate direct access to public fields
265
266 $this->mPage->clear();
267 }
268
276 public function getOldID() {
277 if ( $this->mOldId === null ) {
278 $this->mOldId = $this->getOldIDFromRequest();
279 }
280
281 return $this->mOldId;
282 }
283
289 public function getOldIDFromRequest() {
290 $this->mRedirectUrl = false;
291
292 $request = $this->getContext()->getRequest();
293 $oldid = $request->getIntOrNull( 'oldid' );
294
295 if ( $oldid === null ) {
296 return 0;
297 }
298
299 if ( $oldid !== 0 ) {
300 # Load the given revision and check whether the page is another one.
301 # In that case, update this instance to reflect the change.
302 if ( $oldid === $this->mPage->getLatest() ) {
303 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
304 } else {
305 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
306 if ( $this->mRevisionRecord !== null ) {
307 $revPageId = $this->mRevisionRecord->getPageId();
308 // Revision title doesn't match the page title given?
309 if ( $this->mPage->getId() !== $revPageId ) {
310 $this->mPage = $this->wikiPageFactory->newFromID( $revPageId );
311 }
312 }
313 }
314 }
315
316 $oldRev = $this->mRevisionRecord;
317 if ( $request->getRawVal( 'direction' ) === 'next' ) {
318 $nextid = 0;
319 if ( $oldRev ) {
320 $nextRev = $this->revisionStore->getNextRevision( $oldRev );
321 if ( $nextRev ) {
322 $nextid = $nextRev->getId();
323 }
324 }
325 if ( $nextid ) {
326 $oldid = $nextid;
327 $this->mRevisionRecord = null;
328 } else {
329 $this->mRedirectUrl = $this->getTitle()->getFullURL( 'redirect=no' );
330 }
331 } elseif ( $request->getRawVal( 'direction' ) === 'prev' ) {
332 $previd = 0;
333 if ( $oldRev ) {
334 $prevRev = $this->revisionStore->getPreviousRevision( $oldRev );
335 if ( $prevRev ) {
336 $previd = $prevRev->getId();
337 }
338 }
339 if ( $previd ) {
340 $oldid = $previd;
341 $this->mRevisionRecord = null;
342 }
343 }
344
345 return $oldid;
346 }
347
357 public function fetchRevisionRecord() {
358 if ( $this->fetchResult ) {
359 return $this->mRevisionRecord;
360 }
361
362 $oldid = $this->getOldID();
363
364 // $this->mRevisionRecord might already be fetched by getOldIDFromRequest()
365 if ( !$this->mRevisionRecord ) {
366 if ( !$oldid ) {
367 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
368
369 if ( !$this->mRevisionRecord ) {
370 wfDebug( __METHOD__ . " failed to find page data for title " .
371 $this->getTitle()->getPrefixedText() );
372
373 // Output for this case is done by showMissingArticle().
374 $this->fetchResult = Status::newFatal( 'noarticletext' );
375 return null;
376 }
377 } else {
378 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
379
380 if ( !$this->mRevisionRecord ) {
381 wfDebug( __METHOD__ . " failed to load revision, rev_id $oldid" );
382
383 $this->fetchResult = Status::newFatal( $this->getMissingRevisionMsg( $oldid ) );
384 return null;
385 }
386 }
387 }
388
389 if ( !$this->mRevisionRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getContext()->getAuthority() ) ) {
390 wfDebug( __METHOD__ . " failed to retrieve content of revision " . $this->mRevisionRecord->getId() );
391
392 // Output for this case is done by showDeletedRevisionHeader().
393 // title used in wikilinks, should not contain whitespaces
394 $this->fetchResult = new Status;
395 $title = $this->getTitle()->getPrefixedDBkey();
396
397 if ( $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
398 $this->fetchResult->fatal( 'rev-suppressed-text' );
399 } else {
400 $this->fetchResult->fatal( 'rev-deleted-text-permission', $title );
401 }
402
403 return null;
404 }
405
406 $this->fetchResult = Status::newGood( $this->mRevisionRecord );
407 return $this->mRevisionRecord;
408 }
409
415 public function isCurrent() {
416 # If no oldid, this is the current version.
417 if ( $this->getOldID() == 0 ) {
418 return true;
419 }
420
421 return $this->mPage->exists() &&
422 $this->mRevisionRecord &&
423 $this->mRevisionRecord->isCurrent();
424 }
425
434 public function getRevIdFetched() {
435 if ( $this->fetchResult && $this->fetchResult->isOK() ) {
437 $rev = $this->fetchResult->getValue();
438 return $rev->getId();
439 } else {
440 return $this->mPage->getLatest();
441 }
442 }
443
448 public function view() {
449 $context = $this->getContext();
450 $useFileCache = $context->getConfig()->get( MainConfigNames::UseFileCache );
451
452 # Get variables from query string
453 # As side effect this will load the revision and update the title
454 # in a revision ID is passed in the request, so this should remain
455 # the first call of this method even if $oldid is used way below.
456 $oldid = $this->getOldID();
457
458 $authority = $context->getAuthority();
459 # Another check in case getOldID() is altering the title
460 $permissionStatus = PermissionStatus::newEmpty();
461 if ( !$authority
462 ->authorizeRead( 'read', $this->getTitle(), $permissionStatus )
463 ) {
464 wfDebug( __METHOD__ . ": denied on secondary read check" );
465 throw new PermissionsError( 'read', $permissionStatus );
466 }
467
468 $outputPage = $context->getOutput();
469 # getOldID() may as well want us to redirect somewhere else
470 if ( $this->mRedirectUrl ) {
471 $outputPage->redirect( $this->mRedirectUrl );
472 wfDebug( __METHOD__ . ": redirecting due to oldid" );
473
474 return;
475 }
476
477 # If we got diff in the query, we want to see a diff page instead of the article.
478 if ( $context->getRequest()->getCheck( 'diff' ) ) {
479 wfDebug( __METHOD__ . ": showing diff page" );
480 $this->showDiffPage();
481
482 return;
483 }
484
485 $this->showProtectionIndicator();
486
487 # Set page title (may be overridden from ParserOutput if title conversion is enabled or DISPLAYTITLE is used)
488 $outputPage->setPageTitle( Parser::formatPageTitle(
489 str_replace( '_', ' ', $this->getTitle()->getNsText() ),
490 ':',
491 $this->getTitle()->getText(),
492 $this->getTitle()->getPageLanguage()
493 ) );
494
495 $outputPage->setArticleFlag( true );
496 # Allow frames by default
497 $outputPage->getMetadata()->setPreventClickjacking( false );
498
499 $parserOptions = $this->getParserOptions();
500
501 $poOptions = [];
502 # Allow extensions to vary parser options used for article rendering
503 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
504 ->onArticleParserOptions( $this, $parserOptions );
505 # Render printable version, use printable version cache
506 if ( $outputPage->isPrintable() ) {
507 $parserOptions->setIsPrintable( true );
508 $parserOptions->setSuppressSectionEditLinks();
509 $this->addMessageBoxStyles( $outputPage );
510 $outputPage->prependHTML(
511 Html::warningBox(
512 $outputPage->msg( 'printableversion-deprecated-warning' )->escaped()
513 )
514 );
515 } elseif ( $this->viewIsRenderAction || !$this->isCurrent() ||
516 !$authority->probablyCan( 'edit', $this->getTitle() )
517 ) {
518 $parserOptions->setSuppressSectionEditLinks();
519 }
520
521 # Try client and file cache
522 if ( $oldid === 0 && $this->mPage->checkTouched() ) {
523 # Try to stream the output from file cache
524 if ( $useFileCache && $this->tryFileCache() ) {
525 wfDebug( __METHOD__ . ": done file cache" );
526 # tell wgOut that output is taken care of
527 $outputPage->disable();
528 $this->mPage->doViewUpdates( $authority, $oldid );
529
530 return;
531 }
532 }
533
534 $this->showRedirectedFromHeader();
535 $this->showNamespaceHeader();
536
537 if ( $this->viewIsRenderAction ) {
538 $poOptions += [ 'absoluteURLs' => true ];
539 }
540 $poOptions += [ 'includeDebugInfo' => true ];
541
542 try {
543 $continue =
544 $this->generateContentOutput( $authority, $parserOptions, $oldid, $outputPage, $poOptions );
545 } catch ( BadRevisionException ) {
546 $continue = false;
547 $this->showViewError( wfMessage( 'badrevision' )->text() );
548 }
549
550 if ( !$continue ) {
551 return;
552 }
553
554 # For the main page, overwrite the <title> element with the con-
555 # tents of 'pagetitle-view-mainpage' instead of the default (if
556 # that's not empty).
557 # This message always exists because it is in the i18n files
558 if ( $this->getTitle()->isMainPage() ) {
559 $msg = $context->msg( 'pagetitle-view-mainpage' )->inContentLanguage();
560 if ( !$msg->isDisabled() ) {
561 $outputPage->setHTMLTitle( $msg->text() );
562 }
563 }
564
565 // Enable 1-day CDN cache on this response
566 //
567 // To reduce impact of lost or delayed HTTP purges, the adaptive TTL will
568 // raise the TTL for pages not recently edited, upto $wgCdnMaxAge.
569 // This could use getTouched(), but that could be scary for major template edits.
570 $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), 86_400 );
571
572 $this->showViewFooter();
573 $this->mPage->doViewUpdates( $authority, $oldid, $this->fetchRevisionRecord() );
574
575 # Load the postEdit module if the user just saved this revision
576 # See also EditPage::setPostEditCookie
577 $request = $context->getRequest();
578 $cookieKey = EditPage::POST_EDIT_COOKIE_KEY_PREFIX . $this->getRevIdFetched();
579 $postEdit = $request->getCookie( $cookieKey );
580 if ( $postEdit ) {
581 # Clear the cookie. This also prevents caching of the response.
582 $request->response()->clearCookie( $cookieKey );
583 $outputPage->addJsConfigVars( 'wgPostEdit', $postEdit );
584 $outputPage->addModules( 'mediawiki.action.view.postEdit' ); // FIXME: test this
585 if ( $this->getContext()->getConfig()->get( MainConfigNames::EnableEditRecovery )
586 && $this->userOptionsLookup->getOption( $this->getContext()->getUser(), 'editrecovery' )
587 ) {
588 $outputPage->addModules( 'mediawiki.editRecovery.postEdit' );
589 }
590 }
591 }
592
596 public function showProtectionIndicator(): void {
597 $title = $this->getTitle();
598 $context = $this->getContext();
599 $outputPage = $context->getOutput();
600
601 $protectionIndicatorsAreEnabled = $context->getConfig()
602 ->get( MainConfigNames::EnableProtectionIndicators );
603
604 if ( !$protectionIndicatorsAreEnabled || $title->isMainPage() ) {
605 return;
606 }
607
608 $protection = $this->restrictionStore->getRestrictions( $title, 'edit' );
609
610 $cascadeProtection = $this->restrictionStore->getCascadeProtectionSources( $title )[1];
611
612 $isCascadeProtected = array_key_exists( 'edit', $cascadeProtection );
613
614 if ( !$protection && !$isCascadeProtected ) {
615 return;
616 }
617
618 if ( $isCascadeProtected ) {
619 // Cascade-protected pages are protected at the sysop level. So it
620 // should not matter if we take the protection level of the first
621 // or last page that is being cascaded to the current page.
622 $protectionLevel = $cascadeProtection['edit'][0];
623 } else {
624 $protectionLevel = $protection[0];
625 }
626
627 // Protection levels are stored in the database as plain text, but
628 // they are expected to be valid protection levels. So we should be able to
629 // safely use them. However phan thinks this could be a XSS problem so we
630 // are being paranoid and escaping them once more.
631 $protectionLevel = htmlspecialchars( $protectionLevel );
632
633 $protectionExpiry = $this->restrictionStore->getRestrictionExpiry( $title, 'edit' );
634 $formattedProtectionExpiry = $context->getLanguage()
635 ->formatExpiry( $protectionExpiry ?? '' );
636
637 $protectionMsgKey = 'protection-indicator-title';
638 if ( $protectionExpiry === 'infinity' || !$protectionExpiry ) {
639 $protectionMsgKey = 'protection-indicator-title-infinity';
640 }
641
642 // Potential values: 'protection-sysop', 'protection-autoconfirmed',
643 // 'protection-sysop-cascade' etc.
644 // If the wiki has more protection levels, the additional ids that get
645 // added take the form 'protection-<protectionLevel>' and
646 // 'protection-<protectionLevel>-cascade'.
647 $protectionIndicatorId = 'protection-' . $protectionLevel . ( $isCascadeProtected ? '-cascade' : '' );
648
649 $protectionMsg = $outputPage->msg(
650 $protectionMsgKey,
651 // Messages: restriction-level-sysop, restriction-level-autoconfirmed
652 $outputPage->msg( "restriction-level-$protectionLevel" ),
653 $formattedProtectionExpiry
654 )->text();
655
656 // Use a trick similar to the one used in Action::addHelpLink() to allow wikis
657 // to customize where the help link points to.
658 $protectionHelpLink = $outputPage->msg( $protectionIndicatorId . '-helppage' );
659 if ( $protectionHelpLink->isDisabled() ) {
660 $protectionHelpLink = 'https://mediawiki.org/wiki/Special:MyLanguage/Help:Protection';
661 } else {
662 $protectionHelpLink = $protectionHelpLink->text();
663 }
664
665 $outputPage->setIndicators( [
666 $protectionIndicatorId => Html::rawElement( 'a', [
667 'class' => 'mw-protection-indicator-icon--lock',
668 'title' => $protectionMsg,
669 'href' => $protectionHelpLink
670 ],
671 // Screen reader-only text describing the same thing as
672 // was mentioned in the title attribute.
673 Html::element( 'span', [], $protectionMsg ) )
674 ] );
675
676 $outputPage->addModuleStyles( 'mediawiki.protectionIndicators.styles' );
677 }
678
691 private function generateContentOutput(
692 Authority $performer,
693 ParserOptions $parserOptions,
694 int $oldid,
695 OutputPage $outputPage,
696 array $textOptions
697 ): bool {
698 # Should the parser cache be used?
699 $useParserCache = true;
700 $pOutput = null;
701 $parserOutputAccess = MediaWikiServices::getInstance()->getParserOutputAccess();
702
703 // NOTE: $outputDone and $useParserCache may be changed by the hook
704 $this->getHookRunner()->onArticleViewHeader( $this, $outputDone, $useParserCache );
705 if ( $outputDone ) {
706 if ( $outputDone instanceof ParserOutput ) {
707 $pOutput = $outputDone;
708 }
709
710 if ( $pOutput ) {
711 $this->doOutputMetaData( $pOutput, $outputPage );
712 }
713 return true;
714 }
715
716 // Early abort if the page doesn't exist
717 if ( !$this->mPage->exists() ) {
718 wfDebug( __METHOD__ . ": showing missing article" );
719 $this->showMissingArticle();
720 $this->mPage->doViewUpdates( $performer );
721 return false; // skip all further output to OutputPage
722 }
723
724 // Augment the parser options
725 $skin = $outputPage->getSkin();
726 $skinOptions = $skin->getOptions();
727 $textOptions += [
728 // T371022, T410923
729 'allowClone' => $this->getContext()->getConfig()->get( MainConfigNames::CloneArticleParserOutput ),
730 'skin' => $skin,
731 'injectTOC' => $skinOptions['toc'],
732 ];
733 foreach ( $textOptions as $key => $value ) {
734 // allowClone will disappear and should not impact cache
735 // userLang is a duplicate of userlang and should be reconciled with it
736 if ( $key === 'allowClone' || $key === 'userLang' ) {
737 continue;
738 }
739 if ( $key === 'enableSectionEditLinks' ) {
740 if ( $value === false ) {
741 wfDeprecated( __METHOD__ . " with deprecated textOption $key set to false", "1.46" );
742 $parserOptions->setSuppressSectionEditLinks();
743 }
744 continue;
745 }
746 if ( !in_array( $key, ParserOptions::$postprocOptions, true ) ) {
747 wfDeprecated( __METHOD__ . " with unknown textOption $key", "1.46" );
748 } else {
749 $parserOptions->setOption( $key, $value );
750 }
751 }
752 if ( $this->usePostProcessingCache( $parserOptions ) ) {
753 $parserOptions->enablePostproc();
754 }
755
756 // Try the latest parser cache
757 // NOTE: try latest-revision cache first to avoid loading revision.
758 if ( $useParserCache && !$oldid ) {
759 $pOutput = $parserOutputAccess->getCachedParserOutput(
760 $this->getPage(),
761 $parserOptions,
762 null,
763 [
764 // we already checked
765 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK => true,
766 ],
767 );
768
769 if ( $pOutput ) {
770 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
771 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $skin );
772 }
773 $this->doOutputFromPostProcessedParserCache( $pOutput, $outputPage );
774 $this->doOutputMetaData( $pOutput, $outputPage );
775 return true;
776 }
777 }
778
779 $rev = $this->fetchRevisionRecord();
780 if ( !$this->fetchResult->isOK() ) {
781 $this->showViewError( $this->fetchResult->getWikiText(
782 false, false, $this->getContext()->getLanguage()
783 ) );
784 return true;
785 }
786
787 # Are we looking at an old revision
788 if ( $oldid ) {
789 $this->setOldSubtitle( $oldid );
790
791 if ( !$this->showDeletedRevisionHeader() ) {
792 wfDebug( __METHOD__ . ": cannot view deleted revision" );
793 return false; // skip all further output to OutputPage
794 }
795
796 // Try the old revision parser cache
797 // NOTE: Repeating cache check for old revision to avoid fetching $rev
798 // before it's absolutely necessary.
799 if ( $useParserCache ) {
800 $pOutput = $parserOutputAccess->getCachedParserOutput(
801 $this->getPage(),
802 $parserOptions,
803 $rev,
804 [
805 // we already checked in fetchRevisionRecord
806 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK => true,
807 ],
808 );
809
810 if ( $pOutput ) {
811 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
812 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $skin );
813 }
814 $this->doOutputFromPostProcessedParserCache( $pOutput, $outputPage );
815 $this->doOutputMetaData( $pOutput, $outputPage );
816 return true;
817 }
818 }
819 }
820
821 # Ensure that UI elements requiring revision ID have
822 # the correct version information. (This may be overwritten after creation of ParserOutput)
823 $outputPage->setRevisionId( $this->getRevIdFetched() );
824 $outputPage->setRevisionIsCurrent( $rev->isCurrent() );
825 # Preload timestamp to avoid a DB hit
826 $outputPage->getMetadata()->setRevisionTimestamp( $rev->getTimestamp() );
827
828 # Pages containing custom CSS or JavaScript get special treatment
829 if ( $this->getTitle()->isSiteConfigPage() || $this->getTitle()->isUserConfigPage() ) {
830 $dir = $this->getContext()->getLanguage()->getDir();
831 $lang = $this->getContext()->getLanguage()->getHtmlCode();
832
833 $outputPage->wrapWikiMsg(
834 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
835 'clearyourcache'
836 );
837 $outputPage->addModuleStyles( 'mediawiki.action.styles' );
838 } elseif ( !$this->getHookRunner()->onArticleRevisionViewCustom(
839 $rev,
840 $this->getTitle(),
841 $oldid,
842 $outputPage )
843 ) {
844 // NOTE: sync with hooks called in DifferenceEngine::renderNewRevision()
845 // Allow extensions do their own custom view for certain pages
846 $this->doOutputMetaData( $pOutput, $outputPage );
847 return true;
848 }
849
850 # Run the parse, protected by a pool counter
851 wfDebug( __METHOD__ . ": doing uncached parse" );
852
853 $opt = [];
854
855 // we already checked the cache in case 2, don't check again; but if we're using postproc,
856 // we still want to check if we have a main parser cache entry.
857 if ( $this->usePostProcessingCache( $parserOptions ) ) {
858 $opt[ ParserOutputAccess::OPT_NO_POSTPROC_CACHE ] = true;
859 } else {
860 $opt[ ParserOutputAccess::OPT_NO_CHECK_CACHE ] = true;
861 }
862
863 // we already checked in fetchRevisionRecord()
864 $opt[ ParserOutputAccess::OPT_NO_AUDIENCE_CHECK ] = true;
865
866 // enable stampede protection
867 $opt[ ParserOutputAccess::OPT_POOL_COUNTER ]
868 = ParserOutputAccess::POOL_COUNTER_ARTICLE_VIEW;
869
870 // allow stale cached content to be served
871 $opt[ ParserOutputAccess::OPT_POOL_COUNTER_FALLBACK ] = true;
872
873 // Attempt to trigger WikiPage::triggerOpportunisticLinksUpdate
874 // Ideally this should not be the responsibility of the ParserCache to control this.
875 // See https://phabricator.wikimedia.org/T329842#8816557 for more context.
876 $opt[ ParserOutputAccess::OPT_LINKS_UPDATE ] = true;
877
878 if ( !$rev->getId() || !$useParserCache ) {
879 // fake revision or uncacheable options
880 $opt[ ParserOutputAccess::OPT_NO_CACHE ] = true;
881 }
882
883 $renderStatus = $parserOutputAccess->getParserOutput(
884 $this->getPage(),
885 $parserOptions,
886 $rev,
887 $opt
888 );
889
890 // T327164: If parsoid cache warming is enabled, we want to ensure that the page
891 // the user is currently looking at has a cached parsoid rendering, in case they
892 // open visual editor. The cache entry would typically be missing if it has expired
893 // from the cache or it was invalidated by RefreshLinksJob. When "traditional"
894 // parser output has been invalidated by RefreshLinksJob, we will render it on
895 // the fly when a user requests the page, and thereby populate the cache again,
896 // per the code above.
897 // The code below is intended to do the same for parsoid output, but asynchronously
898 // in a job, so the user does not have to wait.
899 // Note that we get here if the traditional parser output was missing from the cache.
900 // We do not check if the parsoid output is present in the cache, because that check
901 // takes time. The assumption is that if we have traditional parser output
902 // cached, we probably also have parsoid output cached.
903 // So we leave it to ParsoidCachePrewarmJob to determine whether or not parsing is
904 // needed.
905 if ( $oldid === 0 || $oldid === $this->getPage()->getLatest() ) {
906 $parsoidCacheWarmingEnabled = $this->getContext()->getConfig()
907 ->get( MainConfigNames::ParsoidCacheConfig )['WarmParsoidParserCache'];
908
909 if ( $parsoidCacheWarmingEnabled ) {
910 $parsoidJobSpec = ParsoidCachePrewarmJob::newSpec(
911 $rev->getId(),
912 $this->getPage()->toPageRecord(),
913 [ 'causeAction' => 'view' ]
914 );
915 $this->jobQueueGroup->lazyPush( $parsoidJobSpec );
916 }
917 }
918
919 $this->doOutputFromRenderStatus(
920 $rev,
921 $renderStatus,
922 $outputPage,
923 $parserOptions,
924 $textOptions,
925 );
926
927 if ( !$renderStatus->isOK() ) {
928 return true;
929 }
930
931 $pOutput = $renderStatus->getValue();
932 $this->doOutputMetaData( $pOutput, $outputPage );
933 return true;
934 }
935
936 private function doOutputMetaData( ?ParserOutput $pOutput, OutputPage $outputPage ) {
937 # Adjust title for main page & pages with displaytitle
938 if ( $pOutput ) {
939 $this->adjustDisplayTitle( $pOutput );
940
941 // It would be nice to automatically set this during the first call
942 // to OutputPage::addParserOutputMetadata, but we can't because doing
943 // so would break non-pageview actions where OutputPage::getContLangForJS
944 // has different requirements.
945 $pageLang = $pOutput->getLanguage();
946 if ( $pageLang ) {
947 $outputPage->setContentLangForJS( $pageLang );
948 }
949 }
950
951 # Check for any __NOINDEX__ tags on the page using $pOutput
952 $policy = $this->getRobotPolicy( 'view', $pOutput ?: null );
953 $outputPage->getMetadata()->setIndexPolicy( $policy['index'] );
954 $outputPage->setFollowPolicy( $policy['follow'] ); // FIXME: test this
955
956 $this->mParserOutput = $pOutput;
957 }
958
959 private function postProcessOutput(
960 ParserOutput $pOutput, ParserOptions $parserOptions, array $textOptions, Skin $skin
961 ): ParserOutput {
962 $skinOptions = $skin->getOptions();
963 $textOptions += [
964 // T371022, T410923
965 'allowClone' => $this->getContext()->getConfig()->get( MainConfigNames::CloneArticleParserOutput ),
966 'skin' => $skin,
967 'injectTOC' => $skinOptions['toc'],
968 ];
969 $pipeline = MediaWikiServices::getInstance()->getDefaultOutputPipeline();
970 $pOutput = $pipeline->run( $pOutput, $parserOptions, $textOptions );
971 return $pOutput;
972 }
973
974 private function doOutputFromPostProcessedParserCache(
975 ParserOutput $pOutput,
976 OutputPage $outputPage,
977 ) {
978 # Ensure that UI elements requiring revision ID have
979 # the correct version information.
980 $oldid = $pOutput->getCacheRevisionId() ?? $this->getRevIdFetched();
981 $outputPage->setRevisionId( $oldid );
982 $outputPage->setRevisionIsCurrent( $oldid === $this->mPage->getLatest() );
983
984 $outputPage->addPostProcessedParserOutput( $pOutput );
985
986 # Preload timestamp to avoid a DB hit
987 $cachedTimestamp = $pOutput->getRevisionTimestamp();
988 if ( $cachedTimestamp !== null ) {
989 $outputPage->getMetadata()->setRevisionTimestamp( $cachedTimestamp );
990 $this->mPage->setTimestamp( $cachedTimestamp );
991 }
992 }
993
994 private function doOutputFromRenderStatus(
995 RevisionRecord $rev,
996 Status $renderStatus,
997 OutputPage $outputPage,
998 ParserOptions $parserOptions,
999 array $textOptions,
1000 ) {
1001 $context = $this->getContext();
1002 if ( !$renderStatus->isOK() ) {
1003 $this->showViewError( $renderStatus->getWikiText(
1004 false, 'view-pool-error', $context->getLanguage()
1005 ) );
1006 return;
1007 }
1008
1009 $pOutput = $renderStatus->getValue();
1010
1011 // Cache stale ParserOutput object with a short expiry
1012 if ( $renderStatus->hasMessage( 'view-pool-dirty-output' ) ) {
1013 $outputPage->lowerCdnMaxage( $context->getConfig()->get( MainConfigNames::CdnMaxageStale ) );
1014 $outputPage->setLastModified( $pOutput->getCacheTime() );
1015 $staleReason = $renderStatus->hasMessage( 'view-pool-contention' )
1016 ? $context->msg( 'view-pool-contention' )->escaped()
1017 : $context->msg( 'view-pool-timeout' )->escaped();
1018 $outputPage->addHTML( "<!-- parser cache is expired, " .
1019 "sending anyway due to $staleReason-->\n" );
1020
1021 // Ensure OutputPage knowns the id from the dirty cache, but keep the current flag (T341013)
1022 $cachedId = $pOutput->getCacheRevisionId();
1023 if ( $cachedId !== null ) {
1024 $outputPage->setRevisionId( $cachedId );
1025 $outputPage->getMetadata()->setRevisionTimestamp( $pOutput->getRevisionTimestamp() );
1026 }
1027 }
1028
1029 // TODO this will probably need to be conditional on cache access and/or hoisted one level above but for
1030 // now let's keep things in the same place and avoid editing StatusValues.
1031 if ( !$this->usePostProcessingCache( $parserOptions ) ) {
1032 $pOutput = $this->postProcessOutput( $pOutput, $parserOptions, $textOptions, $outputPage->getSkin() );
1033 }
1034
1035 $outputPage->addPostProcessedParserOutput( $pOutput );
1036
1037 if ( $this->getRevisionRedirectTarget( $rev ) ) {
1038 $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
1039 $context->msg( 'redirectpagesub' )->parse() . "</span>" );
1040 }
1041 }
1042
1047 private function getRevisionRedirectTarget( RevisionRecord $revision ) {
1048 // TODO: find a *good* place for the code that determines the redirect target for
1049 // a given revision!
1050 // NOTE: Use main slot content. Compare code in DerivedPageDataUpdater::revisionIsRedirect.
1051 $content = $revision->getContent( SlotRecord::MAIN );
1052 return $content ? $content->getRedirectTarget() : null;
1053 }
1054
1058 public function adjustDisplayTitle( ParserOutput $pOutput ) {
1059 $out = $this->getContext()->getOutput();
1060
1061 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
1062 $titleText = $pOutput->getTitleText();
1063 if ( $titleText !== '' ) {
1064 # XXX T36514 / T314399 / T306440: we should have a language here
1065 # and split the namespace
1066 $out->setPageTitle( $titleText );
1067 $out->setDisplayTitle( $titleText );
1068 }
1069 }
1070
1075 protected function showDiffPage() {
1076 $context = $this->getContext();
1077 $outputPage = $context->getOutput();
1078 $outputPage->addBodyClasses( 'mw-article-diff' );
1079 $request = $context->getRequest();
1080 $diff = $request->getVal( 'diff' );
1081 $rcid = $request->getInt( 'rcid' );
1082 $purge = $request->getRawVal( 'action' ) === 'purge';
1083 $unhide = $request->getInt( 'unhide' ) === 1;
1084 $oldid = $this->getOldID();
1085
1086 $rev = $this->fetchRevisionRecord();
1087
1088 if ( !$rev ) {
1089 // T213621: $rev maybe null due to either lack of permission to view the
1090 // revision or actually not existing. So let's try loading it from the id
1091 $rev = $this->revisionStore->getRevisionById( $oldid );
1092 if ( $rev ) {
1093 // Revision exists but $user lacks permission to diff it.
1094 // Do nothing here.
1095 // The $rev will later be used to create standard diff elements however.
1096 } else {
1097 $outputPage->setPageTitleMsg( $context->msg( 'errorpagetitle' ) );
1098 $msg = $context->msg( 'difference-missing-revision' )
1099 ->params( $oldid )
1100 ->numParams( 1 )
1101 ->parseAsBlock();
1102 $outputPage->addHTML( $msg );
1103 return;
1104 }
1105 }
1106
1107 $services = MediaWikiServices::getInstance();
1108
1109 $contentHandler = $services
1110 ->getContentHandlerFactory()
1111 ->getContentHandler(
1112 $rev->getMainContentModel()
1113 );
1114 $de = $contentHandler->createDifferenceEngine(
1115 $context,
1116 $oldid,
1117 $diff,
1118 $rcid,
1119 $purge,
1120 $unhide
1121 );
1122
1123 $diffType = $request->getVal( 'diff-type' );
1124
1125 if ( $diffType === null ) {
1126 $diffType = $this->userOptionsLookup
1127 ->getOption( $context->getUser(), 'diff-type' );
1128 } else {
1129 $de->setExtraQueryParams( [ 'diff-type' => $diffType ] );
1130 }
1131
1132 $de->setSlotDiffOptions( [
1133 'diff-type' => $diffType,
1134 'expand-url' => $this->viewIsRenderAction,
1135 'inline-toggle' => true,
1136 ] );
1137 $de->showDiffPage( $this->isDiffOnlyView() );
1138
1139 // Run view updates for the newer revision being diffed (and shown
1140 // below the diff if not diffOnly).
1141 [ , $new ] = $de->mapDiffPrevNext( $oldid, $diff );
1142 // New can be false, convert it to 0 - this conveniently means the latest revision
1143 $this->mPage->doViewUpdates( $context->getAuthority(), (int)$new );
1144
1145 // Add link to help page; see T321569
1146 $context->getOutput()->addHelpLink( 'Help:Diff' );
1147 }
1148
1149 protected function isDiffOnlyView(): bool {
1150 return $this->getContext()->getRequest()->getBool(
1151 'diffonly',
1152 $this->userOptionsLookup->getBoolOption( $this->getContext()->getUser(), 'diffonly' )
1153 );
1154 }
1155
1163 public function getRobotPolicy( $action, ?ParserOutput $pOutput = null ) {
1164 $context = $this->getContext();
1165 $mainConfig = $context->getConfig();
1166 $articleRobotPolicies = $mainConfig->get( MainConfigNames::ArticleRobotPolicies );
1167 $namespaceRobotPolicies = $mainConfig->get( MainConfigNames::NamespaceRobotPolicies );
1168 $defaultRobotPolicy = $mainConfig->get( MainConfigNames::DefaultRobotPolicy );
1169 $title = $this->getTitle();
1170 $ns = $title->getNamespace();
1171
1172 # Don't index user and user talk pages for blocked users (T13443)
1173 if ( $ns === NS_USER || $ns === NS_USER_TALK ) {
1174 $specificTarget = null;
1175 $vagueTarget = null;
1176 $titleText = $title->getText();
1177 if ( IPUtils::isValid( $titleText ) ) {
1178 $vagueTarget = $titleText;
1179 } else {
1180 $specificTarget = $title->getRootText();
1181 }
1182 $block = $this->blockStore->newFromTarget(
1183 $specificTarget, $vagueTarget, false, DatabaseBlockStore::AUTO_NONE );
1184 if ( $block instanceof DatabaseBlock ) {
1185 return [
1186 'index' => 'noindex',
1187 'follow' => 'nofollow'
1188 ];
1189 }
1190 }
1191
1192 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
1193 # Non-articles (special pages etc), and old revisions
1194 return [
1195 'index' => 'noindex',
1196 'follow' => 'nofollow'
1197 ];
1198 } elseif ( $context->getOutput()->isPrintable() ) {
1199 # Discourage indexing of printable versions, but encourage following
1200 return [
1201 'index' => 'noindex',
1202 'follow' => 'follow'
1203 ];
1204 } elseif ( $context->getRequest()->getInt( 'curid' ) ) {
1205 # For ?curid=x urls, disallow indexing
1206 return [
1207 'index' => 'noindex',
1208 'follow' => 'follow'
1209 ];
1210 }
1211
1212 # Otherwise, construct the policy based on the various config variables.
1213 $policy = self::formatRobotPolicy( $defaultRobotPolicy );
1214
1215 if ( isset( $namespaceRobotPolicies[$ns] ) ) {
1216 # Honour customised robot policies for this namespace
1217 $policy = array_merge(
1218 $policy,
1219 self::formatRobotPolicy( $namespaceRobotPolicies[$ns] )
1220 );
1221 }
1222 if ( $title->canUseNoindex() && $pOutput && $pOutput->getIndexPolicy() ) {
1223 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
1224 # a final check that we have really got the parser output.
1225 $policy['index'] = $pOutput->getIndexPolicy();
1226 }
1227
1228 if ( isset( $articleRobotPolicies[$title->getPrefixedText()] ) ) {
1229 # (T16900) site config can override user-defined __INDEX__ or __NOINDEX__
1230 $policy = array_merge(
1231 $policy,
1232 self::formatRobotPolicy( $articleRobotPolicies[$title->getPrefixedText()] )
1233 );
1234 }
1235
1236 return $policy;
1237 }
1238
1246 public static function formatRobotPolicy( $policy ) {
1247 if ( is_array( $policy ) ) {
1248 return $policy;
1249 } elseif ( !$policy ) {
1250 return [];
1251 }
1252
1253 $arr = [];
1254 foreach ( explode( ',', $policy ) as $var ) {
1255 $var = trim( $var );
1256 if ( $var === 'index' || $var === 'noindex' ) {
1257 $arr['index'] = $var;
1258 } elseif ( $var === 'follow' || $var === 'nofollow' ) {
1259 $arr['follow'] = $var;
1260 }
1261 }
1262
1263 return $arr;
1264 }
1265
1273 public function showRedirectedFromHeader() {
1274 $context = $this->getContext();
1275 $redirectSources = $context->getConfig()->get( MainConfigNames::RedirectSources );
1276 $outputPage = $context->getOutput();
1277 $request = $context->getRequest();
1278 $rdfrom = $request->getVal( 'rdfrom' );
1279
1280 // Construct a URL for the current page view, but with the target title
1281 $query = $request->getQueryValues();
1282 unset( $query['rdfrom'] );
1283 unset( $query['title'] );
1284 if ( $this->getTitle()->isRedirect() ) {
1285 // Prevent double redirects
1286 $query['redirect'] = 'no';
1287 }
1288 $redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
1289
1290 if ( $this->mRedirectedFrom ) {
1291 // This is an internally redirected page view.
1292 // We'll need a backlink to the source page for navigation.
1293 if ( $this->getHookRunner()->onArticleViewRedirect( $this ) ) {
1294 $redir = $this->linkRenderer->makeKnownLink(
1295 $this->mRedirectedFrom,
1296 null,
1297 [],
1298 [ 'redirect' => 'no' ]
1299 );
1300
1301 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
1302 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
1303 . "</span>" );
1304
1305 // Add the script to update the displayed URL and
1306 // set the fragment if one was specified in the redirect
1307 $outputPage->addJsConfigVars( [
1308 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1309 ] );
1310 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1311
1312 // Add a <link rel="canonical"> tag
1313 $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
1314
1315 // Tell the output object that the user arrived at this article through a redirect
1316 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
1317
1318 return true;
1319 }
1320 } elseif ( $rdfrom ) {
1321 // This is an externally redirected view, from some other wiki.
1322 // If it was reported from a trusted site, supply a backlink.
1323 if ( $redirectSources && preg_match( $redirectSources, $rdfrom ) ) {
1324 $redir = $this->linkRenderer->makeExternalLink( $rdfrom, $rdfrom, $this->getTitle() );
1325 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
1326 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
1327 . "</span>" );
1328
1329 // Add the script to update the displayed URL
1330 $outputPage->addJsConfigVars( [
1331 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1332 ] );
1333 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1334
1335 return true;
1336 }
1337 }
1338
1339 return false;
1340 }
1341
1351 public function showNamespaceHeader() {
1352 if (
1353 !$this->getTitle()->isTalkPage() &&
1354 $this->getTitle()->exists() &&
1355 !$this->getContext()->msg( 'subjectpageheader' )->isDisabled()
1356 ) {
1357 $this->getContext()->getOutput()->wrapWikiMsg(
1358 "<div class=\"mw-subjectpageheader\">\n$1\n</div>",
1359 [ 'subjectpageheader' ]
1360 );
1361 }
1362
1363 if (
1364 $this->getTitle()->isTalkPage() &&
1365 !$this->getContext()->msg( 'talkpageheader' )->isDisabled()
1366 ) {
1367 $this->getContext()->getOutput()->wrapWikiMsg(
1368 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1369 [ 'talkpageheader' ]
1370 );
1371 }
1372 }
1373
1377 public function showViewFooter() {
1378 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1379 if ( $this->getTitle()->getNamespace() === NS_USER_TALK
1380 && IPUtils::isValid( $this->getTitle()->getText() )
1381 ) {
1382 $this->getContext()->getOutput()->addWikiMsg( 'anontalkpagetext' );
1383 }
1384
1385 // Show a footer allowing the user to patrol the shown revision or page if possible
1386 $patrolFooterShown = $this->showPatrolFooter();
1387
1388 $this->getHookRunner()->onArticleViewFooter( $this, $patrolFooterShown );
1389 }
1390
1401 public function showPatrolFooter() {
1402 $context = $this->getContext();
1403 $mainConfig = $context->getConfig();
1404 $useNPPatrol = $mainConfig->get( MainConfigNames::UseNPPatrol );
1405 $useRCPatrol = $mainConfig->get( MainConfigNames::UseRCPatrol );
1406 $useFilePatrol = $mainConfig->get( MainConfigNames::UseFilePatrol );
1407 $fileMigrationStage = $mainConfig->get( MainConfigNames::FileSchemaMigrationStage );
1408 // Allow hooks to decide whether to not output this at all
1409 if ( !$this->getHookRunner()->onArticleShowPatrolFooter( $this ) ) {
1410 return false;
1411 }
1412
1413 $outputPage = $context->getOutput();
1414 $user = $context->getUser();
1415 $title = $this->getTitle();
1416 $rc = false;
1417
1418 if ( !$context->getAuthority()->probablyCan( 'patrol', $title )
1419 || !( $useRCPatrol || $useNPPatrol
1420 || ( $useFilePatrol && $title->inNamespace( NS_FILE ) ) )
1421 ) {
1422 // Patrolling is disabled or the user isn't allowed to
1423 return false;
1424 }
1425
1426 if ( $this->mRevisionRecord
1427 && !RecentChange::isInRCLifespan( $this->mRevisionRecord->getTimestamp(), 21600 )
1428 ) {
1429 // The current revision is already older than what could be in the RC table
1430 // 6h tolerance because the RC might not be cleaned out regularly
1431 return false;
1432 }
1433
1434 // Check for cached results
1435 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1436 $key = $cache->makeKey( 'unpatrollable-page', $title->getArticleID() );
1437 if ( $cache->get( $key ) ) {
1438 return false;
1439 }
1440
1441 $dbr = $this->dbProvider->getReplicaDatabase();
1442 $oldestRevisionRow = $dbr->newSelectQueryBuilder()
1443 ->select( [ 'rev_id', 'rev_timestamp' ] )
1444 ->from( 'revision' )
1445 ->where( [ 'rev_page' => $title->getArticleID() ] )
1446 ->orderBy( [ 'rev_timestamp', 'rev_id' ] )
1447 ->caller( __METHOD__ )->fetchRow();
1448 $oldestRevisionTimestamp = $oldestRevisionRow ? $oldestRevisionRow->rev_timestamp : false;
1449
1450 // New page patrol: Get the timestamp of the oldest revision which
1451 // the revision table holds for the given page. Then we look
1452 // whether it's within the RC lifespan and if it is, we try
1453 // to get the recentchanges row belonging to that entry.
1454 $recentPageCreation = false;
1455 if ( $oldestRevisionTimestamp
1456 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1457 ) {
1458 // 6h tolerance because the RC might not be cleaned out regularly
1459 $recentPageCreation = true;
1460 $rc = $this->recentChangeLookup->getRecentChangeByConds(
1461 [
1462 'rc_this_oldid' => intval( $oldestRevisionRow->rev_id ),
1463 // Avoid selecting a categorization entry
1464 'rc_source' => RecentChange::SRC_NEW,
1465 ],
1466 __METHOD__
1467 );
1468 if ( $rc ) {
1469 // Use generic patrol message for new pages
1470 $markPatrolledMsg = $context->msg( 'markaspatrolledtext' );
1471 }
1472 }
1473
1474 // File patrol: Get the timestamp of the latest upload for this page,
1475 // check whether it is within the RC lifespan and if it is, we try
1476 // to get the recentchanges row belonging to that entry
1477 // (with rc_source = SRC_LOG, rc_log_type = upload).
1478 $recentFileUpload = false;
1479 if ( ( !$rc || $rc->getAttribute( 'rc_patrolled' ) ) && $useFilePatrol
1480 && $title->getNamespace() === NS_FILE ) {
1481 // Retrieve timestamp from the current file (latest upload)
1482 if ( $fileMigrationStage & SCHEMA_COMPAT_READ_OLD ) {
1483 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1484 ->select( 'img_timestamp' )
1485 ->from( 'image' )
1486 ->where( [ 'img_name' => $title->getDBkey() ] )
1487 ->caller( __METHOD__ )->fetchField();
1488 } else {
1489 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1490 ->select( 'fr_timestamp' )
1491 ->from( 'file' )
1492 ->join( 'filerevision', null, 'file_latest = fr_id' )
1493 ->where( [ 'file_name' => $title->getDBkey() ] )
1494 ->caller( __METHOD__ )->fetchField();
1495 }
1496
1497 if ( $newestUploadTimestamp
1498 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1499 ) {
1500 // 6h tolerance because the RC might not be cleaned out regularly
1501 $recentFileUpload = true;
1502 $rc = $this->recentChangeLookup->getRecentChangeByConds(
1503 [
1504 'rc_source' => RecentChange::SRC_LOG,
1505 'rc_log_type' => 'upload',
1506 'rc_timestamp' => $newestUploadTimestamp,
1507 'rc_namespace' => NS_FILE,
1508 'rc_cur_id' => $title->getArticleID()
1509 ],
1510 __METHOD__
1511 );
1512 if ( $rc ) {
1513 // Use patrol message specific to files
1514 $markPatrolledMsg = $context->msg( 'markaspatrolledtext-file' );
1515 }
1516 }
1517 }
1518
1519 if ( !$recentPageCreation && !$recentFileUpload ) {
1520 // Page creation and latest upload (for files) is too old to be in RC
1521
1522 // We definitely can't patrol so cache the information
1523 // When a new file version is uploaded, the cache is cleared
1524 $cache->set( $key, '1' );
1525
1526 return false;
1527 }
1528
1529 if ( !$rc ) {
1530 // Don't cache: This can be hit if the page gets accessed very fast after
1531 // its creation / latest upload or in case we have high replica DB lag. In case
1532 // the revision is too old, we will already return above.
1533 return false;
1534 }
1535
1536 if ( $rc->getAttribute( 'rc_patrolled' ) ) {
1537 // Patrolled RC entry around
1538
1539 // Cache the information we gathered above in case we can't patrol
1540 // Don't cache in case we can patrol as this could change
1541 $cache->set( $key, '1' );
1542
1543 return false;
1544 }
1545
1546 if ( $rc->getPerformerIdentity()->equals( $user ) ) {
1547 // Don't show a patrol link for own creations/uploads. If the user could
1548 // patrol them, they already would be patrolled
1549 return false;
1550 }
1551
1552 $outputPage->getMetadata()->setPreventClickjacking( true );
1553 $outputPage->addModules( 'mediawiki.misc-authed-curate' );
1554
1555 $link = $this->linkRenderer->makeKnownLink(
1556 $title,
1557 new HtmlArmor( '<button class="cdx-button cdx-button--action-progressive">'
1558 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable $markPatrolledMsg is always set
1559 . $markPatrolledMsg->escaped() . '</button>' ),
1560 [],
1561 [
1562 'action' => 'markpatrolled',
1563 'rcid' => $rc->getAttribute( 'rc_id' ),
1564 ]
1565 );
1566
1567 $outputPage->addModuleStyles( 'mediawiki.action.styles' );
1568 $outputPage->addHTML( "<div class='patrollink' data-mw-interface>$link</div>" );
1569
1570 return true;
1571 }
1572
1579 public static function purgePatrolFooterCache( $articleID ) {
1580 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1581 $cache->delete( $cache->makeKey( 'unpatrollable-page', $articleID ) );
1582 }
1583
1588 public function showMissingArticle() {
1589 $context = $this->getContext();
1590 $send404Code = $context->getConfig()->get( MainConfigNames::Send404Code );
1591
1592 $outputPage = $context->getOutput();
1593 // Whether the page is a root user page of an existing user (but not a subpage)
1594 $validUserPage = false;
1595
1596 $title = $this->getTitle();
1597
1598 $services = MediaWikiServices::getInstance();
1599
1600 $contextUser = $context->getUser();
1601
1602 # Show info in user (talk) namespace. Does the user exist? Are they blocked?
1603 if ( $title->getNamespace() === NS_USER
1604 || $title->getNamespace() === NS_USER_TALK
1605 ) {
1606 $rootPart = $title->getRootText();
1607 $userFactory = $services->getUserFactory();
1608 $user = $userFactory->newFromNameOrIp( $rootPart );
1609
1610 if ( $user && $user->isRegistered() && $user->isHidden() &&
1611 !$context->getAuthority()->isAllowed( 'hideuser' )
1612 ) {
1613 // T120883 if the user is hidden and the viewer cannot see hidden
1614 // users, pretend like it does not exist at all.
1615 $user = false;
1616 }
1617
1618 if ( !( $user && $user->isRegistered() ) && !$this->userNameUtils->isIP( $rootPart ) ) {
1619 $this->addMessageBoxStyles( $outputPage );
1620 // User does not exist
1621 $outputPage->addHTML( Html::warningBox(
1622 $context->msg( 'userpage-userdoesnotexist-view', wfEscapeWikiText( $rootPart ) )->parse(),
1623 'mw-userpage-userdoesnotexist'
1624 ) );
1625
1626 // Show renameuser log extract
1627 LogEventsList::showLogExtract(
1628 $outputPage,
1629 'renameuser',
1630 Title::makeTitleSafe( NS_USER, $rootPart ),
1631 '',
1632 [
1633 'lim' => 10,
1634 'showIfEmpty' => false,
1635 'msgKey' => [ 'renameuser-renamed-notice', $title->getBaseText() ]
1636 ]
1637 );
1638 } else {
1639 $validUserPage = !$title->isSubpage();
1640
1641 $blockLogBox = LogEventsList::getBlockLogWarningBox(
1642 $this->blockStore,
1643 $services->getNamespaceInfo(),
1644 $this->getContext(),
1645 $this->linkRenderer,
1646 $user,
1647 $title
1648 );
1649 if ( $blockLogBox !== null ) {
1650 $outputPage->addHTML( $blockLogBox );
1651 }
1652 }
1653 }
1654
1655 $this->getHookRunner()->onShowMissingArticle( $this );
1656
1657 # Show delete and move logs if there were any such events.
1658 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1659 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1660 $dbCache = MediaWikiServices::getInstance()->getMainObjectStash();
1661 $key = $dbCache->makeKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
1662 $isRegistered = $contextUser->isRegistered();
1663 $sessionExists = $context->getRequest()->getSession()->isPersistent();
1664
1665 if ( $isRegistered || $dbCache->get( $key ) || $sessionExists ) {
1666 $logTypes = [ 'delete', 'move', 'protect', 'merge' ];
1667
1668 $dbr = $this->dbProvider->getReplicaDatabase();
1669
1670 $conds = [ $dbr->expr( 'log_action', '!=', 'revision' ) ];
1671 // Give extensions a chance to hide their (unrelated) log entries
1672 $this->getHookRunner()->onArticle__MissingArticleConditions( $conds, $logTypes );
1673 LogEventsList::showLogExtract(
1674 $outputPage,
1675 $logTypes,
1676 $title,
1677 '',
1678 [
1679 'lim' => 10,
1680 'conds' => $conds,
1681 'showIfEmpty' => false,
1682 'msgKey' => [ $isRegistered || $sessionExists
1683 ? 'moveddeleted-notice'
1684 : 'moveddeleted-notice-recent'
1685 ]
1686 ]
1687 );
1688 }
1689
1690 if ( !$this->mPage->hasViewableContent() && $send404Code && !$validUserPage ) {
1691 // If there's no backing content, send a 404 Not Found
1692 // for better machine handling of broken links.
1693 $context->getRequest()->response()->statusHeader( 404 );
1694 }
1695
1696 // Also apply the robot policy for nonexisting pages (even if a 404 was used)
1697 $policy = $this->getRobotPolicy( 'view' );
1698 $outputPage->getMetadata()->setIndexPolicy( $policy['index'] );
1699 $outputPage->setFollowPolicy( $policy['follow'] );
1700
1701 $hookResult = $this->getHookRunner()->onBeforeDisplayNoArticleText( $this );
1702
1703 if ( !$hookResult ) {
1704 return;
1705 }
1706
1707 # Show error message
1708 $oldid = $this->getOldID();
1709 if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
1710 $text = $this->getTitle()->getDefaultMessageText() ?? '';
1711 $outputPage->addWikiTextAsContent( $text );
1712 } else {
1713 if ( $oldid ) {
1714 $text = $this->getMissingRevisionMsg( $oldid )->plain();
1715 } elseif ( $context->getAuthority()->probablyCan( 'edit', $title ) ) {
1716 $message = $isRegistered ? 'noarticletext' : 'noarticletextanon';
1717 $text = $context->msg( $message )->plain();
1718 } else {
1719 $text = $context->msg( 'noarticletext-nopermission' )->plain();
1720 }
1721
1722 $dir = $context->getLanguage()->getDir();
1723 $lang = $context->getLanguage()->getHtmlCode();
1724 $outputPage->addWikiTextAsInterface( Html::openElement( 'div', [
1725 'class' => "noarticletext mw-content-$dir",
1726 'dir' => $dir,
1727 'lang' => $lang,
1728 ] ) . "\n$text\n</div>" );
1729 }
1730 }
1731
1736 private function showViewError( string $errortext ) {
1737 $outputPage = $this->getContext()->getOutput();
1738 $outputPage->setPageTitleMsg( $this->getContext()->msg( 'errorpagetitle' ) );
1739 $outputPage->disableClientCache();
1740 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1741 $outputPage->clearHTML();
1742 $this->addMessageBoxStyles( $outputPage );
1743 $outputPage->addHTML( Html::errorBox( $outputPage->parseAsContent( $errortext ) ) );
1744 }
1745
1752 public function showDeletedRevisionHeader() {
1753 if ( !$this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
1754 // Not deleted
1755 return true;
1756 }
1757 $outputPage = $this->getContext()->getOutput();
1758 // Used in wikilinks, should not contain whitespaces
1759 $titleText = $this->getTitle()->getPrefixedURL();
1760 $this->addMessageBoxStyles( $outputPage );
1761 // If the user is not allowed to see it...
1762 if ( !$this->mRevisionRecord->userCan(
1763 RevisionRecord::DELETED_TEXT,
1764 $this->getContext()->getAuthority()
1765 ) ) {
1766 $outputPage->addHTML(
1767 Html::warningBox(
1768 $outputPage->msg( 'rev-deleted-text-permission', $titleText )->parse(),
1769 'plainlinks'
1770 )
1771 );
1772
1773 return false;
1774 // If the user needs to confirm that they want to see it...
1775 } elseif ( $this->getContext()->getRequest()->getInt( 'unhide' ) !== 1 ) {
1776 # Give explanation and add a link to view the revision...
1777 $oldid = intval( $this->getOldID() );
1778 $link = $this->getTitle()->getFullURL( "oldid={$oldid}&unhide=1" );
1779 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ?
1780 'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
1781 $outputPage->addHTML(
1782 Html::warningBox(
1783 $outputPage->msg( $msg, $link )->parse(),
1784 'plainlinks'
1785 )
1786 );
1787
1788 return false;
1789 // We are allowed to see...
1790 } else {
1791 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED )
1792 ? [ 'rev-suppressed-text-view', $titleText ]
1793 : [ 'rev-deleted-text-view', $titleText ];
1794 $outputPage->addHTML(
1795 Html::warningBox(
1796 $outputPage->msg( $msg[0], $msg[1] )->parse(),
1797 'plainlinks'
1798 )
1799 );
1800
1801 return true;
1802 }
1803 }
1804
1805 private function addMessageBoxStyles( OutputPage $outputPage ) {
1806 $outputPage->addModuleStyles( [
1807 'mediawiki.codex.messagebox.styles',
1808 ] );
1809 }
1810
1819 public function setOldSubtitle( $oldid = 0 ) {
1820 if ( !$this->getHookRunner()->onDisplayOldSubtitle( $this, $oldid ) ) {
1821 return;
1822 }
1823
1824 $context = $this->getContext();
1825 $unhide = $context->getRequest()->getInt( 'unhide' ) === 1;
1826
1827 # Cascade unhide param in links for easy deletion browsing
1828 $extraParams = [];
1829 if ( $unhide ) {
1830 $extraParams['unhide'] = 1;
1831 }
1832
1833 if ( $this->mRevisionRecord && $this->mRevisionRecord->getId() === $oldid ) {
1834 $revisionRecord = $this->mRevisionRecord;
1835 } else {
1836 $revisionRecord = $this->revisionStore->getRevisionById( $oldid );
1837 }
1838 if ( !$revisionRecord ) {
1839 throw new LogicException( 'There should be a revision record at this point.' );
1840 }
1841
1842 $timestamp = $revisionRecord->getTimestamp();
1843
1844 $current = ( $oldid == $this->mPage->getLatest() );
1845 $language = $context->getLanguage();
1846 $user = $context->getUser();
1847
1848 $td = $language->userTimeAndDate( $timestamp, $user );
1849 $tddate = $language->userDate( $timestamp, $user );
1850 $tdtime = $language->userTime( $timestamp, $user );
1851
1852 # Show user links if allowed to see them. If hidden, then show them only if requested...
1853 $userlinks = Linker::revUserTools( $revisionRecord, !$unhide );
1854
1855 $infomsg = $current && !$context->msg( 'revision-info-current' )->isDisabled()
1856 ? 'revision-info-current'
1857 : 'revision-info';
1858
1859 $outputPage = $context->getOutput();
1860 $outputPage->addModuleStyles( [
1861 'mediawiki.action.styles',
1862 'mediawiki.interface.helpers.styles'
1863 ] );
1864
1865 $revisionUser = $revisionRecord->getUser();
1866 $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
1867 $context->msg( $infomsg, $td )
1868 ->rawParams( $userlinks )
1869 ->params(
1870 $revisionRecord->getId(),
1871 $tddate,
1872 $tdtime,
1873 $revisionUser ? $revisionUser->getName() : ''
1874 )
1875 ->rawParams( $this->commentFormatter->formatRevision(
1876 $revisionRecord,
1877 $user,
1878 true,
1879 !$unhide
1880 ) )
1881 ->parse() .
1882 "</div>";
1883
1884 $lnk = $current
1885 ? $context->msg( 'currentrevisionlink' )->escaped()
1886 : $this->linkRenderer->makeKnownLink(
1887 $this->getTitle(),
1888 $context->msg( 'currentrevisionlink' )->text(),
1889 [],
1890 $extraParams
1891 );
1892 $curdiff = $current
1893 ? $context->msg( 'diff' )->escaped()
1894 : $this->linkRenderer->makeKnownLink(
1895 $this->getTitle(),
1896 $context->msg( 'diff' )->text(),
1897 [],
1898 [
1899 'diff' => 'cur',
1900 'oldid' => $oldid
1901 ] + $extraParams
1902 );
1903 $prevExist = (bool)$this->revisionStore->getPreviousRevision( $revisionRecord );
1904 $prevlink = $prevExist
1905 ? $this->linkRenderer->makeKnownLink(
1906 $this->getTitle(),
1907 $context->msg( 'previousrevision' )->text(),
1908 [],
1909 [
1910 'direction' => 'prev',
1911 'oldid' => $oldid
1912 ] + $extraParams
1913 )
1914 : $context->msg( 'previousrevision' )->escaped();
1915 $prevdiff = $prevExist
1916 ? $this->linkRenderer->makeKnownLink(
1917 $this->getTitle(),
1918 $context->msg( 'diff' )->text(),
1919 [],
1920 [
1921 'diff' => 'prev',
1922 'oldid' => $oldid
1923 ] + $extraParams
1924 )
1925 : $context->msg( 'diff' )->escaped();
1926 $nextlink = $current
1927 ? $context->msg( 'nextrevision' )->escaped()
1928 : $this->linkRenderer->makeKnownLink(
1929 $this->getTitle(),
1930 $context->msg( 'nextrevision' )->text(),
1931 [],
1932 [
1933 'direction' => 'next',
1934 'oldid' => $oldid
1935 ] + $extraParams
1936 );
1937 $nextdiff = $current
1938 ? $context->msg( 'diff' )->escaped()
1939 : $this->linkRenderer->makeKnownLink(
1940 $this->getTitle(),
1941 $context->msg( 'diff' )->text(),
1942 [],
1943 [
1944 'diff' => 'next',
1945 'oldid' => $oldid
1946 ] + $extraParams
1947 );
1948
1949 $cdel = Linker::getRevDeleteLink(
1950 $context->getAuthority(),
1951 $revisionRecord,
1952 $this->getTitle()
1953 );
1954 if ( $cdel !== '' ) {
1955 $cdel .= ' ';
1956 }
1957
1958 // the outer div is need for styling the revision info and nav in MobileFrontend
1959 $this->addMessageBoxStyles( $outputPage );
1960 $outputPage->addSubtitle(
1961 Html::warningBox(
1962 $revisionInfo .
1963 "<div id=\"mw-revision-nav\">" . $cdel .
1964 $context->msg( 'revision-nav' )->rawParams(
1965 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1966 )->escaped() . "</div>",
1967 'mw-revision'
1968 )
1969 );
1970 }
1971
1985 public static function getRedirectHeaderHtml( Language $lang, Title $target, $forceKnown = false ) {
1986 wfDeprecated( __METHOD__, '1.41' );
1987 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1988 return $linkRenderer->makeRedirectHeader( $lang, $target, $forceKnown );
1989 }
1990
1999 public function addHelpLink( $to, $overrideBaseUrl = false ) {
2000 $out = $this->getContext()->getOutput();
2001 $msg = $out->msg( 'namespace-' . $this->getTitle()->getNamespace() . '-helppage' );
2002
2003 if ( !$msg->isDisabled() ) {
2004 $title = Title::newFromText( $msg->plain() );
2005 if ( $title instanceof Title ) {
2006 $out->addHelpLink( $title->getLocalURL(), true );
2007 }
2008 } else {
2009 $out->addHelpLink( $to, $overrideBaseUrl );
2010 }
2011 }
2012
2016 public function render() {
2017 $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
2018 $this->getContext()->getOutput()->setArticleBodyOnly( true );
2019 // We later set suppress section edit links based on this; also used by ImagePage
2020 $this->viewIsRenderAction = true;
2021 $this->view();
2022 }
2023
2027 public function protect() {
2028 $form = new ProtectionForm( $this );
2029 $form->execute();
2030 }
2031
2035 public function unprotect() {
2036 $this->protect();
2037 }
2038
2039 /* Caching functions */
2040
2048 protected function tryFileCache() {
2049 static $called = false;
2050
2051 if ( $called ) {
2052 wfDebug( "Article::tryFileCache(): called twice!?" );
2053 return false;
2054 }
2055
2056 $called = true;
2057 if ( $this->isFileCacheable() ) {
2058 $cache = new HTMLFileCache( $this->getTitle(), 'view' );
2059 if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
2060 wfDebug( "Article::tryFileCache(): about to load file" );
2061 $cache->loadFromFileCache( $this->getContext() );
2062 return true;
2063 } else {
2064 wfDebug( "Article::tryFileCache(): starting buffer" );
2065 ob_start( $cache->saveToFileCache( ... ) );
2066 }
2067 } else {
2068 wfDebug( "Article::tryFileCache(): not cacheable" );
2069 }
2070
2071 return false;
2072 }
2073
2079 public function isFileCacheable( $mode = HTMLFileCache::MODE_NORMAL ) {
2080 $cacheable = false;
2081
2082 if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
2083 $cacheable = $this->mPage->getId()
2084 && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
2085 // Extension may have reason to disable file caching on some pages.
2086 if ( $cacheable ) {
2087 $cacheable = $this->getHookRunner()->onIsFileCacheable( $this ) ?? false;
2088 }
2089 }
2090
2091 return $cacheable;
2092 }
2093
2105 public function getParserOutput( $oldid = null, ?UserIdentity $user = null ) {
2106 if ( $user === null ) {
2107 $parserOptions = $this->getParserOptions();
2108 } else {
2109 $parserOptions = $this->mPage->makeParserOptions( $user );
2110 $parserOptions->setRenderReason( $this->getOldID() ? 'page_view_oldid' : 'page_view' );
2111 }
2112
2113 return $this->mPage->getParserOutput( $parserOptions, $oldid );
2114 }
2115
2120 public function getParserOptions() {
2121 $parserOptions = $this->mPage->makeParserOptions( $this->getContext() );
2122 $parserOptions->setRenderReason( $this->getOldID() ? 'page_view_oldid' : 'page_view' );
2123 return $parserOptions;
2124 }
2125
2132 public function setContext( $context ) {
2133 $this->mContext = $context;
2134 }
2135
2142 public function getContext(): IContextSource {
2143 if ( $this->mContext instanceof IContextSource ) {
2144 return $this->mContext;
2145 } else {
2146 wfDebug( __METHOD__ . " called and \$mContext is null. " .
2147 "Return RequestContext::getMain()" );
2148 return RequestContext::getMain();
2149 }
2150 }
2151
2157 public function getActionOverrides() {
2158 return $this->mPage->getActionOverrides();
2159 }
2160
2161 private function getMissingRevisionMsg( int $oldid ): Message {
2162 // T251066: Try loading the revision from the archive table.
2163 // Show link to view it if it exists and the user has permission to view it.
2164 // (Ignore the given title, if any; look it up from the revision instead.)
2165 $context = $this->getContext();
2166 $revRecord = $this->archivedRevisionLookup->getArchivedRevisionRecord( null, $oldid );
2167 if (
2168 $revRecord &&
2169 $revRecord->userCan(
2170 RevisionRecord::DELETED_TEXT,
2171 $context->getAuthority()
2172 ) &&
2173 $context->getAuthority()->isAllowedAny( 'deletedtext', 'undelete' )
2174 ) {
2175 return $context->msg(
2176 'missing-revision-permission',
2177 $oldid,
2178 $revRecord->getTimestamp(),
2179 Title::newFromPageIdentity( $revRecord->getPage() )->getPrefixedURL()
2180 );
2181 }
2182 return $context->msg( 'missing-revision', $oldid );
2183 }
2184
2185 private function usePostProcessingCache( ParserOptions $poptions ): bool {
2186 if ( $poptions->getUseParsoid() ) {
2187 return $this->parsoidPostprocCacheAvailable;
2188 }
2189 return $this->legacyPostprocCacheAvailable && $this->useLegacyPostprocCache;
2190 }
2191
2197 public function setUseLegacyPostprocCache( bool $val = true ): void {
2198 $this->useLegacyPostprocCache = $val;
2199 }
2200}
2201
2203class_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
The HTML user interface for page editing.
Definition EditPage.php:135
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:43
Handle enqueueing of background jobs.
Base class for language-specific code.
Definition Language.php:68
Class that generates HTML for internal links.
makeRedirectHeader(Language $lang, Title $target, bool $forceKnown=false, bool $addLinkTag=false)
Return the HTML for the top of a redirect page.
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 UsePostprocCache
Name constant for the UsePostprocCache 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:64
render()
Handle action=render.
Definition Article.php:2016
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
Definition Article.php:1246
static purgePatrolFooterCache( $articleID)
Purge the cache used to check if it is worth showing the patrol footer For example,...
Definition Article.php:1579
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:216
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, such as [[MediaWiki:Subjectpageheader...
Definition Article.php:1351
showViewFooter()
Show the footer section of an ordinary page view.
Definition Article.php:1377
IConnectionProvider $dbProvider
Definition Article.php:119
int null $mOldId
The oldid of the article that was requested to be shown, 0 for the current revision.
Definition Article.php:82
showPatrolFooter()
If patrol is possible, output a patrol UI box.
Definition Article.php:1401
setOldSubtitle( $oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Definition Article.php:1819
Title null $mRedirectedFrom
Title from which we were redirected here, if any.
Definition Article.php:85
setContext( $context)
Sets the context this Article is executed in.
Definition Article.php:2132
getParserOutput( $oldid=null, ?UserIdentity $user=null)
Lightweight method to get the parser output for a page, checking the parser cache and so on.
Definition Article.php:2105
bool $viewIsRenderAction
Whether render() was called.
Definition Article.php:108
getRedirectedFrom()
Get the page this view was redirected from.
Definition Article.php:227
showProtectionIndicator()
Show a lock icon above the article body if the page is protected.
Definition Article.php:596
view()
This is the default action of the index.php entry point: just view the page of the given title.
Definition Article.php:448
getRevIdFetched()
Use this to fetch the rev ID used on page views.
Definition Article.php:434
string false $mRedirectUrl
URL to redirect to or false if none.
Definition Article.php:88
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
Definition Article.php:415
static newFromID( $id)
Constructor from a page id.
Definition Article.php:177
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
Definition Article.php:2048
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
Definition Article.php:1273
getPage()
Get the WikiPage object of this instance.
Definition Article.php:254
protect()
action=protect handler
Definition Article.php:2027
ParserOutput null false $mParserOutput
The ParserOutput generated for viewing the page, initialized by view().
Definition Article.php:101
fetchRevisionRecord()
Fetches the revision to work on.
Definition Article.php:357
DatabaseBlockStore $blockStore
Definition Article.php:120
newPage(Title $title)
Definition Article.php:169
IContextSource null $mContext
The context this Article is executed in.
Definition Article.php:73
RestrictionStore $restrictionStore
Definition Article.php:121
LinkRenderer $linkRenderer
Definition Article.php:110
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:2197
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
Definition Article.php:1752
getTitle()
Get the title object of the article.
Definition Article.php:244
showDiffPage()
Show a diff page according to current request variables.
Definition Article.php:1075
getActionOverrides()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2157
WikiPage $mPage
The WikiPage object of this instance.
Definition Article.php:76
isFileCacheable( $mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
Definition Article.php:2079
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
Definition Article.php:235
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
Definition Article.php:1058
showMissingArticle()
Show the error text for a missing article.
Definition Article.php:1588
getRobotPolicy( $action, ?ParserOutput $pOutput=null)
Get the robot policy to be used for the current view.
Definition Article.php:1163
unprotect()
action=unprotect handler (alias)
Definition Article.php:2035
getContext()
Gets the context this Article is executed in.
Definition Article.php:2142
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition Article.php:1999
__construct(Title $title, $oldId=null)
Definition Article.php:139
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
Definition Article.php:289
static getRedirectHeaderHtml(Language $lang, Title $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition Article.php:1985
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
Definition Article.php:2120
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:188
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:82
getTitle()
Get the title object of the article.
Definition WikiPage.php:250
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:135
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.
Value object representing a content slot associated with a page revision.
The base class for all skins.
Definition Skin.php:52
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.
fatal( $message,... $parameters)
Add an error and set OK to false, indicating that the operation as a whole was fatal.
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, 250, 300,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> 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, 'UserEmailConfirmationUseHTML'=> false, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, '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, 'ImageLinksSchemaMigrationStage'=> 769, '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,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, '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, ], '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, 'UseLegacyMediaStyles' => 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, ], ], '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, ], '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, '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, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => 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, '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, '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, '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, '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, '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, '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' => [ ], 'RCEngines' => [ 'redis' => 'MediaWiki\\RCFeed\\RedisPubSubFeedEngine', 'udp' => 'MediaWiki\\RCFeed\\UDPRCFeedEngine', ], '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, ], '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, '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\\JobQueue\\Jobs\\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', '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, '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, 'UsePostprocCache' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => false, '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', ], 'ThumbnailStepsRatio' => [ 'number', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'UserEmailConfirmationUseHTML' => 'boolean', 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ImageLinksSchemaMigrationStage' => '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', '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', ], 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ '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', 'RCEngines' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => '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', ], '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', 'UsePostprocCache' => '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', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], 'required' => [ 'url', ], ], ], '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.