MediaWiki master
Title.php
Go to the documentation of this file.
1<?php
11namespace MediaWiki\Title;
12
13use InvalidArgumentException;
14use MediaWiki\Cache\LinkCache;
16use MediaWiki\DAO\WikiAwareEntityTrait;
47use RuntimeException;
48use stdClass;
49use Stringable;
50use Wikimedia\Assert\Assert;
51use Wikimedia\Assert\PreconditionException;
53use Wikimedia\Parsoid\Core\LinkTarget as ParsoidLinkTarget;
54use Wikimedia\Parsoid\Core\LinkTargetTrait;
59use Wikimedia\Timestamp\TimestampFormat as TS;
60
69class Title implements Stringable, LinkTarget, PageIdentity {
70 use WikiAwareEntityTrait;
71 use LinkTargetTrait;
72
74 private static $titleCache = null;
75
80 private static ?Title $cachedMainPage = null;
81
87 private const CACHE_MAX = 1000;
88
96 public const NEW_CLONE = 'clone';
97
99 private $mTextform = '';
100
102 private $mUrlform = '';
103
105 private $mDbkeyform = '';
106
108 private $mNamespace = NS_MAIN;
109
111 private $mInterwiki = '';
112
114 private $mLocalInterwiki = false;
115
117 private $mFragment = '';
118
119 /***************************************************************************/
120 // region Private member variables
128 public $mArticleID = -1;
129
131 protected $mLatestID = false;
132
137 private $mContentModel = false;
138
143 private $mForcedContentModel = false;
144
146 private $mEstimateRevisions;
147
156 public $prefixedText = null;
157
163 private const DEFAULT_NAMESPACE = NS_MAIN;
164
166 protected $mLength = -1;
167
169 public $mRedirect = null;
170
172 private $mHasSubpages;
173
175 private $mPageLanguage;
176
180 private $mDbPageLanguage = false;
181
183 private $mTitleValue = null;
184
186 private $mIsBigDeletion = null;
187
189 private $mIsValid = null;
190
192 private $mInstanceCacheKey = null;
193
194 // endregion -- end of private member variables
196 /***************************************************************************/
197
203 private function getLanguageConverter( $language ): ILanguageConverter {
204 return MediaWikiServices::getInstance()->getLanguageConverterFactory()
205 ->getLanguageConverter( $language );
206 }
207
211 private function getPageLanguageConverter(): ILanguageConverter {
212 return $this->getLanguageConverter( $this->getPageLanguage() );
213 }
214
218 private function getDbProvider(): IConnectionProvider {
219 return MediaWikiServices::getInstance()->getConnectionProvider();
220 }
221
230 private static function getTitleFormatter() {
231 return MediaWikiServices::getInstance()->getTitleFormatter();
232 }
233
242 private static function getInterwikiLookup() {
243 return MediaWikiServices::getInstance()->getInterwikiLookup();
244 }
245
246 private function __construct() {
247 }
248
257 public static function newFromDBkey( $key ) {
258 $t = new self();
259
260 try {
261 $t->secureAndSplit( $key );
262 return $t;
263 } catch ( MalformedTitleException ) {
264 return null;
265 }
266 }
267
279 public static function newFromLinkTarget( ParsoidLinkTarget $linkTarget, $forceClone = '' ) {
280 if ( $linkTarget instanceof Title ) {
281 // Special case if it's already a Title object
282 if ( $forceClone === self::NEW_CLONE ) {
283 return clone $linkTarget;
284 } else {
285 return $linkTarget;
286 }
287 }
288 return self::makeTitle(
289 $linkTarget->getNamespace(),
290 $linkTarget->getText(),
291 $linkTarget->getFragment(),
292 $linkTarget->getInterwiki()
293 );
294 }
295
303 public static function castFromLinkTarget( ?ParsoidLinkTarget $linkTarget ) {
304 if ( !$linkTarget ) {
305 return null;
306 }
307 return self::newFromLinkTarget( $linkTarget );
308 }
309
318 public static function newFromPageIdentity( PageIdentity $pageIdentity ): Title {
319 return self::newFromPageReference( $pageIdentity );
320 }
321
329 public static function castFromPageIdentity( ?PageIdentity $pageIdentity ): ?Title {
330 return self::castFromPageReference( $pageIdentity );
331 }
332
341 public static function newFromPageReference( PageReference $pageReference ): Title {
342 if ( $pageReference instanceof Title ) {
343 return $pageReference;
344 }
345
346 $pageReference->assertWiki( self::LOCAL );
347 $title = self::makeTitle( $pageReference->getNamespace(), $pageReference->getDBkey() );
348
349 if ( $pageReference instanceof PageIdentity ) {
350 $title->mArticleID = $pageReference->getId();
351 }
352 return $title;
353 }
354
362 public static function castFromPageReference( ?PageReference $pageReference ): ?Title {
363 if ( !$pageReference ) {
364 return null;
365 }
366 return self::newFromPageReference( $pageReference );
367 }
368
388 public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
389 // DWIM: Integers can be passed in here when page titles are used as array keys.
390 if ( $text !== null && !is_string( $text ) && !is_int( $text ) ) {
391 throw new InvalidArgumentException( '$text must be a string.' );
392 }
393 if ( $text === null || $text === '' ) {
394 return null;
395 }
396
397 try {
398 return self::newFromTextThrow( (string)$text, (int)$defaultNamespace );
399 } catch ( MalformedTitleException ) {
400 return null;
401 }
402 }
403
423 public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
424 if ( is_object( $text ) ) {
425 throw new InvalidArgumentException( '$text must be a string, given an object' );
426 } elseif ( $text === null ) {
427 // Legacy code relies on MalformedTitleException being thrown in this case
428 // TODO: fix(happens when URL with no title in it is parsed).
429 throw new MalformedTitleException( 'title-invalid-empty' );
430 }
431
432 $titleCache = self::getTitleCache();
433
434 // Wiki pages often contain multiple links to the same page.
435 // Title normalization and parsing can become expensive on pages with many
436 // links, so we can save a little time by caching them.
437 if ( $defaultNamespace === NS_MAIN ) {
438 $t = $titleCache->get( $text );
439 if ( $t ) {
440 return $t;
441 }
442 }
443
444 // Convert things like &eacute; &#257; or &#x3017; into normalized (T16952) text
445 $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
446
447 $t = new Title();
448 $dbKeyForm = strtr( $filteredText, ' ', '_' );
449
450 $t->secureAndSplit( $dbKeyForm, (int)$defaultNamespace );
451 if ( $defaultNamespace === NS_MAIN ) {
452 $t->mInstanceCacheKey = $text;
453 $titleCache->set( $text, $t );
454 }
455 return $t;
456 }
457
462 private function uncache() {
463 if ( $this->mInstanceCacheKey !== null ) {
464 $titleCache = self::getTitleCache();
465 $titleCache->clear( $this->mInstanceCacheKey );
466 $this->mInstanceCacheKey = null;
467 }
468 }
469
485 public static function newFromURL( $url ) {
486 $t = new Title();
487
488 # For compatibility with old buggy URLs. "+" is usually not valid in titles,
489 # but some URLs used it as a space replacement and they still come
490 # from some external search tools.
491 if ( !str_contains( self::legalChars(), '+' ) ) {
492 $url = strtr( $url, '+', ' ' );
493 }
494
495 $dbKeyForm = strtr( $url, ' ', '_' );
496
497 try {
498 $t->secureAndSplit( $dbKeyForm );
499 return $t;
500 } catch ( MalformedTitleException ) {
501 return null;
502 }
503 }
504
508 private static function getTitleCache() {
509 if ( self::$titleCache === null ) {
510 self::$titleCache = new MapCacheLRU( self::CACHE_MAX );
511 }
512 return self::$titleCache;
513 }
514
522 public static function newFromID( $id, $flags = 0 ) {
523 $pageStore = MediaWikiServices::getInstance()->getPageStore();
524 $dbr = DBAccessObjectUtils::getDBFromRecency(
525 MediaWikiServices::getInstance()->getConnectionProvider(),
526 $flags
527 );
528 $row = $dbr->newSelectQueryBuilder()
529 ->select( $pageStore->getSelectFields() )
530 ->from( 'page' )
531 ->where( [ 'page_id' => $id ] )
532 ->recency( $flags )
533 ->caller( __METHOD__ )->fetchRow();
534 if ( $row !== false ) {
535 $title = self::newFromRow( $row );
536 } else {
537 $title = null;
538 }
539
540 return $title;
541 }
542
549 public static function newFromRow( $row ) {
550 $t = self::makeTitle( $row->page_namespace, $row->page_title );
551 $t->loadFromRow( $row );
552 return $t;
553 }
554
561 public function loadFromRow( $row ) {
562 if ( $row ) { // page found
563 if ( isset( $row->page_id ) ) {
564 $this->mArticleID = (int)$row->page_id;
565 }
566 if ( isset( $row->page_len ) ) {
567 $this->mLength = (int)$row->page_len;
568 }
569 if ( isset( $row->page_is_redirect ) ) {
570 $this->mRedirect = (bool)$row->page_is_redirect;
571 }
572 if ( isset( $row->page_latest ) ) {
573 $this->mLatestID = (int)$row->page_latest;
574 }
575 if ( isset( $row->page_content_model ) ) {
576 $this->lazyFillContentModel( $row->page_content_model );
577 } else {
578 $this->lazyFillContentModel( false ); // lazily-load getContentModel()
579 }
580 if ( isset( $row->page_lang ) ) {
581 $this->mDbPageLanguage = (string)$row->page_lang;
582 }
583 } else { // page not found
584 $this->mArticleID = 0;
585 $this->mLength = 0;
586 $this->mRedirect = false;
587 $this->mLatestID = 0;
588 $this->lazyFillContentModel( false ); // lazily-load getContentModel()
589 }
590 }
591
614 public static function makeTitle( $ns, $title, $fragment = '', $interwiki = '' ) {
615 $t = new Title();
616 $t->mInterwiki = $interwiki;
617 $t->mFragment = self::normalizeFragment( $fragment );
618 $t->mNamespace = $ns = (int)$ns;
619 $t->mDbkeyform = strtr( $title, ' ', '_' );
620 $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
621 $t->mUrlform = wfUrlencode( $t->mDbkeyform );
622 $t->mTextform = strtr( $title, '_', ' ' );
623 return $t;
624 }
625
640 public static function makeTitleSafe( $ns, $title, $fragment = '', $interwiki = '' ) {
641 // NOTE: ideally, this would just call makeTitle() and then isValid(),
642 // but presently, that means more overhead on a potential performance hotspot.
643
644 if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->exists( $ns ) ) {
645 return null;
646 }
647
648 $t = new Title();
649 $dbKeyForm = self::makeName( $ns, $title, $fragment, $interwiki, true );
650
651 try {
652 $t->secureAndSplit( $dbKeyForm );
653 return $t;
654 } catch ( MalformedTitleException ) {
655 return null;
656 }
657 }
658
676 public static function newMainPage( ?MessageLocalizer $localizer = null ) {
677 static $recursionGuard = false;
678
679 $title = null;
680
681 if ( !$recursionGuard ) {
682 $msg = $localizer ? $localizer->msg( 'mainpage' ) : wfMessage( 'mainpage' );
683
684 $recursionGuard = true;
685 $title = self::newFromText( $msg->inContentLanguage()->text() );
686 $recursionGuard = false;
687 }
688
689 // Every page renders at least one link to the Main Page (e.g. sidebar).
690 // Don't produce fatal errors that would make the wiki inaccessible, and hard to fix the
691 // invalid message.
692 //
693 // Fallback scenarios:
694 // * Recursion guard
695 // If the message contains a bare local interwiki (T297571), then
696 // Title::newFromText via TitleParser::splitTitleString can get back here.
697 // * Invalid title
698 // If the 'mainpage' message contains something that is invalid, Title::newFromText
699 // will return null.
700
701 return $title ?? self::makeTitle( NS_MAIN, 'Main Page' );
702 }
703
709 public static function legalChars() {
710 global $wgLegalTitleChars;
711 return $wgLegalTitleChars;
712 }
713
723 public static function convertByteClassToUnicodeClass( $byteClass ) {
724 $length = strlen( $byteClass );
725 // Input token queue
726 $x0 = $x1 = $x2 = '';
727 // Decoded queue
728 $d0 = $d1 = '';
729 // Decoded integer codepoints
730 $ord0 = $ord1 = $ord2 = 0;
731 // Re-encoded queue
732 $r0 = $r1 = $r2 = '';
733 // Output
734 $out = '';
735 // Flags
736 $allowUnicode = false;
737 for ( $pos = 0; $pos < $length; $pos++ ) {
738 // Shift the queues down
739 $x2 = $x1;
740 $x1 = $x0;
741 $d1 = $d0;
742 $ord2 = $ord1;
743 $ord1 = $ord0;
744 $r2 = $r1;
745 $r1 = $r0;
746 // Load the current input token and decoded values
747 $inChar = $byteClass[$pos];
748 if ( $inChar === '\\' ) {
749 if ( preg_match( '/x([0-9a-fA-F]{2})/A', $byteClass, $m, 0, $pos + 1 ) ) {
750 $x0 = $inChar . $m[0];
751 $d0 = chr( hexdec( $m[1] ) );
752 $pos += strlen( $m[0] );
753 } elseif ( preg_match( '/[0-7]{3}/A', $byteClass, $m, 0, $pos + 1 ) ) {
754 $x0 = $inChar . $m[0];
755 $d0 = chr( octdec( $m[0] ) );
756 $pos += strlen( $m[0] );
757 } elseif ( $pos + 1 >= $length ) {
758 $x0 = $d0 = '\\';
759 } else {
760 $d0 = $byteClass[$pos + 1];
761 $x0 = $inChar . $d0;
762 $pos++;
763 }
764 } else {
765 $x0 = $d0 = $inChar;
766 }
767 $ord0 = ord( $d0 );
768 // Load the current re-encoded value
769 if ( $ord0 < 32 || $ord0 == 0x7f ) {
770 $r0 = sprintf( '\x%02x', $ord0 );
771 } elseif ( $ord0 >= 0x80 ) {
772 // Allow unicode if a single high-bit character appears
773 $r0 = sprintf( '\x%02x', $ord0 );
774 $allowUnicode = true;
775 // @phan-suppress-next-line PhanParamSuspiciousOrder false positive
776 } elseif ( str_contains( '-\\[]^', $d0 ) ) {
777 $r0 = '\\' . $d0;
778 } else {
779 $r0 = $d0;
780 }
781 // Do the output
782 if ( $x0 !== '' && $x1 === '-' && $x2 !== '' ) {
783 // Range
784 if ( $ord2 > $ord0 ) {
785 // Empty range
786 } elseif ( $ord0 >= 0x80 ) {
787 // Unicode range
788 $allowUnicode = true;
789 if ( $ord2 < 0x80 ) {
790 // Keep the non-unicode section of the range
791 $out .= "$r2-\\x7F";
792 }
793 } else {
794 // Normal range
795 $out .= "$r2-$r0";
796 }
797 // Reset state to the initial value
798 // @phan-suppress-next-line PhanPluginRedundantAssignmentInLoop
799 $x0 = $x1 = $d0 = $d1 = $r0 = $r1 = '';
800 } elseif ( $ord2 < 0x80 ) {
801 // ASCII character
802 $out .= $r2;
803 }
804 }
805 // @phan-suppress-next-line PhanSuspiciousValueComparison
806 if ( $ord1 < 0x80 ) {
807 $out .= $r1;
808 }
809 if ( $ord0 < 0x80 ) {
810 $out .= $r0;
811 }
812 if ( $allowUnicode ) {
813 $out .= '\u0080-\uFFFF';
814 }
815 return $out;
816 }
817
829 public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
830 $canonicalNamespace = false
831 ) {
832 if ( $canonicalNamespace ) {
833 $namespace = MediaWikiServices::getInstance()->getNamespaceInfo()->
834 getCanonicalName( $ns );
835 } else {
836 $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
837 }
838 if ( $namespace === false ) {
839 // See T165149. Awkward, but better than erroneously linking to the main namespace.
840 $namespace = self::makeName( NS_SPECIAL, "Badtitle/NS$ns", '', '', $canonicalNamespace );
841 }
842 $name = $namespace === '' ? $title : "$namespace:$title";
843 if ( strval( $interwiki ) != '' ) {
844 $name = "$interwiki:$name";
845 }
846 if ( strval( $fragment ) != '' ) {
847 $name .= '#' . $fragment;
848 }
849 return $name;
850 }
851
860 public static function compare( $a, $b ) {
861 return $a->getNamespace() <=> $b->getNamespace()
862 ?: strcmp( $a->getDBkey(), $b->getDBkey() );
863 }
864
881 public function isValid() {
882 if ( $this->mIsValid !== null ) {
883 return $this->mIsValid;
884 }
885
886 try {
887 // Optimization: Avoid Title::getFullText because that involves GenderCache
888 // and (unbatched) database queries. For validation, canonical namespace suffices.
889 $text = self::makeName( $this->mNamespace, $this->mDbkeyform, $this->mFragment, $this->mInterwiki, true );
890 $titleParser = MediaWikiServices::getInstance()->getTitleParser();
891
892 $parts = $titleParser->splitTitleString( $text, $this->mNamespace );
893
894 // Check that nothing changed!
895 // This ensures that $text was already properly normalized.
896 if ( $parts['fragment'] !== $this->mFragment
897 || $parts['interwiki'] !== $this->mInterwiki
898 || $parts['local_interwiki'] !== $this->mLocalInterwiki
899 || $parts['namespace'] !== $this->mNamespace
900 || $parts['dbkey'] !== $this->mDbkeyform
901 ) {
902 $this->mIsValid = false;
903 return $this->mIsValid;
904 }
905 } catch ( MalformedTitleException ) {
906 $this->mIsValid = false;
907 return $this->mIsValid;
908 }
909
910 $this->mIsValid = true;
911 return $this->mIsValid;
912 }
913
921 public function isLocal() {
922 if ( $this->isExternal() ) {
923 $iw = self::getInterwikiLookup()->fetch( $this->mInterwiki );
924 if ( $iw ) {
925 return $iw->isLocal();
926 }
927 }
928 return true;
929 }
930
938 public function getInterwiki(): string {
939 return $this->mInterwiki;
940 }
941
947 public function wasLocalInterwiki() {
948 return $this->mLocalInterwiki;
949 }
950
957 public function isTrans() {
958 if ( !$this->isExternal() ) {
959 return false;
960 }
961
962 return self::getInterwikiLookup()->fetch( $this->mInterwiki )->isTranscludable();
963 }
964
970 public function getTransWikiID() {
971 if ( !$this->isExternal() ) {
972 return false;
973 }
974
975 return self::getInterwikiLookup()->fetch( $this->mInterwiki )->getWikiID();
976 }
977
987 public function getTitleValue() {
988 if ( $this->mTitleValue === null ) {
989 try {
990 $this->mTitleValue = new TitleValue(
991 $this->mNamespace,
992 $this->mDbkeyform,
993 $this->mFragment,
994 $this->mInterwiki
995 );
996 } catch ( InvalidArgumentException $ex ) {
997 wfDebug( __METHOD__ . ': Can\'t create a TitleValue for [[' .
998 $this->getPrefixedText() . ']]: ' . $ex->getMessage() );
999 }
1000 }
1001
1002 return $this->mTitleValue;
1003 }
1004
1010 public function getText(): string {
1011 return $this->mTextform;
1012 }
1013
1019 public function getPartialURL() {
1020 return $this->mUrlform;
1021 }
1022
1028 public function getDBkey(): string {
1029 return $this->mDbkeyform;
1030 }
1031
1037 public function getNamespace(): int {
1038 return $this->mNamespace;
1039 }
1040
1047 private function shouldReadLatest( int $flags ) {
1048 return ( $flags & ( IDBAccessObject::READ_LATEST ) ) > 0;
1049 }
1050
1059 public function getContentModel( $flags = 0 ) {
1060 if ( $this->mForcedContentModel ) {
1061 if ( !$this->mContentModel ) {
1062 throw new RuntimeException( 'Got out of sync; an empty model is being forced' );
1063 }
1064 // Content model is locked to the currently loaded one
1065 return $this->mContentModel;
1066 }
1067
1068 if ( $this->shouldReadLatest( $flags ) || !$this->mContentModel ) {
1069 $this->lazyFillContentModel( $this->getFieldFromPageStore( 'page_content_model', $flags ) );
1070 }
1071
1072 if ( !$this->mContentModel ) {
1073 $slotRoleregistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
1074 $mainSlotHandler = $slotRoleregistry->getRoleHandler( 'main' );
1075 $this->lazyFillContentModel( $mainSlotHandler->getDefaultModel( $this ) );
1076 }
1077
1078 return $this->mContentModel;
1079 }
1080
1087 public function hasContentModel( $id ) {
1088 return $this->getContentModel() == $id;
1089 }
1090
1107 public function setContentModel( $model ) {
1108 if ( (string)$model === '' ) {
1109 throw new InvalidArgumentException( "Missing CONTENT_MODEL_* constant" );
1110 }
1111
1112 $this->uncache();
1113 $this->mContentModel = $model;
1114 $this->mForcedContentModel = true;
1115 }
1116
1122 private function lazyFillContentModel( $model ) {
1123 if ( !$this->mForcedContentModel ) {
1124 $this->mContentModel = ( $model === false ) ? false : (string)$model;
1125 }
1126 }
1127
1133 public function getNsText() {
1134 if ( $this->isExternal() ) {
1135 // This probably shouldn't even happen, except for interwiki transclusion.
1136 // If possible, use the canonical name for the foreign namespace.
1137 if ( $this->mNamespace === NS_MAIN ) {
1138 // Optimisation
1139 return '';
1140 } else {
1141 $nsText = MediaWikiServices::getInstance()->getNamespaceInfo()->
1142 getCanonicalName( $this->mNamespace );
1143 if ( $nsText !== false ) {
1144 return $nsText;
1145 }
1146 }
1147 }
1148
1149 try {
1150 $formatter = self::getTitleFormatter();
1151 return $formatter->getNamespaceName( $this->mNamespace, $this->mDbkeyform );
1152 } catch ( InvalidArgumentException $ex ) {
1153 wfDebug( __METHOD__ . ': ' . $ex->getMessage() );
1154 return false;
1155 }
1156 }
1157
1163 public function getSubjectNsText() {
1164 $services = MediaWikiServices::getInstance();
1165 return $services->getContentLanguage()->
1166 getNsText( $services->getNamespaceInfo()->getSubject( $this->mNamespace ) );
1167 }
1168
1174 public function getTalkNsText() {
1175 $services = MediaWikiServices::getInstance();
1176 return $services->getContentLanguage()->
1177 getNsText( $services->getNamespaceInfo()->getTalk( $this->mNamespace ) );
1178 }
1179
1191 public function canHaveTalkPage() {
1192 return MediaWikiServices::getInstance()->getNamespaceInfo()->canHaveTalkPage( $this );
1193 }
1194
1205 public function canExist(): bool {
1206 // NOTE: Don't use getArticleID(), we don't want to
1207 // trigger a database query here. This check is supposed to
1208 // act as an optimization, not add extra cost.
1209 if ( $this->mArticleID > 0 ) {
1210 // It exists, so it can exist.
1211 return true;
1212 }
1213
1214 // NOTE: we call the relatively expensive isValid() method further down,
1215 // but we can bail out early if we already know the title is invalid.
1216 if ( $this->mIsValid === false ) {
1217 // It's invalid, so it can't exist.
1218 return false;
1219 }
1220
1221 if ( $this->getNamespace() < NS_MAIN ) {
1222 // It's a special page, so it can't exist in the database.
1223 return false;
1224 }
1225
1226 if ( $this->isExternal() ) {
1227 // If it's external, it's not local, so it can't exist.
1228 return false;
1229 }
1230
1231 if ( $this->getText() === '' ) {
1232 // The title has no text, so it can't exist in the database.
1233 // It's probably an on-page section link, like "#something".
1234 return false;
1235 }
1236
1237 // Double check that the title is valid.
1238 return $this->isValid();
1239 }
1240
1246 public function isSpecialPage() {
1247 return $this->mNamespace === NS_SPECIAL;
1248 }
1249
1256 public function isSpecial( $name ) {
1257 if ( $this->isSpecialPage() ) {
1258 [ $thisName, /* $subpage */ ] =
1259 MediaWikiServices::getInstance()->getSpecialPageFactory()->
1260 resolveAlias( $this->mDbkeyform );
1261 if ( $name == $thisName ) {
1262 return true;
1263 }
1264 }
1265 return false;
1266 }
1267
1274 public function fixSpecialName() {
1275 if ( $this->isSpecialPage() ) {
1276 $spFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
1277 [ $canonicalName, $par ] = $spFactory->resolveAlias( $this->mDbkeyform );
1278 if ( $canonicalName ) {
1279 $localName = $spFactory->getLocalNameFor( $canonicalName, $par );
1280 if ( $localName != $this->mDbkeyform ) {
1281 return self::makeTitle( NS_SPECIAL, $localName );
1282 }
1283 }
1284 }
1285 return $this;
1286 }
1287
1295 public function inNamespace( int $ns ): bool {
1296 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1297 equals( $this->mNamespace, $ns );
1298 }
1299
1307 public function inNamespaces( ...$namespaces ) {
1308 if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) {
1309 $namespaces = $namespaces[0];
1310 }
1311
1312 foreach ( $namespaces as $ns ) {
1313 if ( $this->inNamespace( $ns ) ) {
1314 return true;
1315 }
1316 }
1317
1318 return false;
1319 }
1320
1334 public function hasSubjectNamespace( $ns ) {
1335 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1336 subjectEquals( $this->mNamespace, $ns );
1337 }
1338
1346 public function isContentPage() {
1347 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1348 isContent( $this->mNamespace );
1349 }
1350
1357 public function isMovable() {
1358 $services = MediaWikiServices::getInstance();
1359 if (
1360 !$services->getNamespaceInfo()->
1361 isMovable( $this->mNamespace ) || $this->isExternal()
1362 ) {
1363 // Interwiki title or immovable namespace. Hooks don't get to override here
1364 return false;
1365 }
1366
1367 $result = true;
1368 ( new HookRunner( $services->getHookContainer() ) )->onTitleIsMovable( $this, $result );
1369 return $result;
1370 }
1371
1379 public function isMainPage() {
1380 self::$cachedMainPage ??= self::newMainPage();
1381 return $this->equals( self::$cachedMainPage );
1382 }
1383
1389 public function isSubpage() {
1390 return MediaWikiServices::getInstance()
1391 ->getNamespaceInfo()
1392 ->hasSubpages( $this->mNamespace )
1393 && str_contains( $this->getText(), '/' );
1394 }
1395
1401 public function isConversionTable() {
1402 // @todo ConversionTable should become a separate content model.
1403 // @todo And the prefix should be localized, too!
1404
1405 return $this->mNamespace === NS_MEDIAWIKI &&
1406 str_starts_with( $this->getText(), 'Conversiontable/' );
1407 }
1408
1414 public function isWikitextPage() {
1415 return $this->hasContentModel( CONTENT_MODEL_WIKITEXT );
1416 }
1417
1432 public function isSiteConfigPage() {
1433 return (
1434 $this->isSiteCssConfigPage()
1435 || $this->isSiteJsonConfigPage()
1436 || $this->isSiteJsConfigPage()
1437 );
1438 }
1439
1446 public function isUserConfigPage() {
1447 return (
1448 $this->isUserCssConfigPage()
1449 || $this->isUserJsonConfigPage()
1450 || $this->isUserJsConfigPage()
1451 );
1452 }
1453
1460 public function getSkinFromConfigSubpage() {
1461 $text = $this->getText();
1462 $lastSlashPos = $this->findSubpageDivider( $text, -1 );
1463 if ( $lastSlashPos === false ) {
1464 return '';
1465 }
1466
1467 $lastDot = strrpos( $text, '.', $lastSlashPos );
1468 if ( $lastDot === false ) {
1469 return '';
1470 }
1471
1472 return substr( $text, $lastSlashPos + 1, $lastDot - $lastSlashPos - 1 );
1473 }
1474
1481 public function isUserCssConfigPage() {
1482 return (
1483 $this->mNamespace === NS_USER
1484 && $this->isSubpage()
1485 && $this->hasContentModel( CONTENT_MODEL_CSS )
1486 );
1487 }
1488
1495 public function isUserJsonConfigPage() {
1496 return (
1497 $this->mNamespace === NS_USER
1498 && $this->isSubpage()
1499 && $this->hasContentModel( CONTENT_MODEL_JSON )
1500 );
1501 }
1502
1509 public function isUserJsConfigPage() {
1510 return (
1511 $this->mNamespace === NS_USER
1512 && $this->isSubpage()
1513 && ( $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ||
1514 $this->hasContentModel( CONTENT_MODEL_VUE )
1515 )
1516 );
1517 }
1518
1525 public function isSiteCssConfigPage() {
1526 return (
1527 $this->mNamespace === NS_MEDIAWIKI
1528 && (
1529 $this->hasContentModel( CONTENT_MODEL_CSS )
1530 // paranoia - a MediaWiki: namespace page with mismatching extension and content
1531 // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1532 || str_ends_with( $this->mDbkeyform, '.css' )
1533 )
1534 );
1535 }
1536
1543 public function isSiteJsonConfigPage() {
1544 return (
1545 $this->mNamespace === NS_MEDIAWIKI
1546 && (
1547 $this->hasContentModel( CONTENT_MODEL_JSON )
1548 // paranoia - a MediaWiki: namespace page with mismatching extension and content
1549 // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1550 || str_ends_with( $this->mDbkeyform, '.json' )
1551 )
1552 );
1553 }
1554
1561 public function isSiteJsConfigPage() {
1562 return (
1563 $this->mNamespace === NS_MEDIAWIKI
1564 && (
1565 (
1566 $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
1567 // paranoia - a MediaWiki: namespace page with mismatching extension and content
1568 // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1569 || str_ends_with( $this->mDbkeyform, '.js' )
1570 ) || (
1571 $this->hasContentModel( CONTENT_MODEL_VUE )
1572 || str_ends_with( $this->mDbkeyform, '.vue' )
1573 )
1574 )
1575 );
1576 }
1577
1584 public function isRawHtmlMessage() {
1585 global $wgRawHtmlMessages;
1586
1587 if ( !$this->inNamespace( NS_MEDIAWIKI ) ) {
1588 return false;
1589 }
1590 $message = lcfirst( $this->getRootTitle()->getDBkey() );
1591 return in_array( $message, $wgRawHtmlMessages, true );
1592 }
1593
1599 public function isTalkPage() {
1600 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1601 isTalk( $this->mNamespace );
1602 }
1603
1615 public function getTalkPage() {
1616 // NOTE: The equivalent code in NamespaceInfo is less lenient about producing invalid titles.
1617 // Instead of failing on invalid titles, let's just log the issue for now.
1618 // See the discussion on T227817.
1619
1620 // Is this the same title?
1621 $talkNS = MediaWikiServices::getInstance()->getNamespaceInfo()->getTalk( $this->mNamespace );
1622 if ( $this->mNamespace == $talkNS ) {
1623 return $this;
1624 }
1625
1626 $title = self::makeTitle( $talkNS, $this->mDbkeyform );
1627
1628 $this->warnIfPageCannotExist( $title, __METHOD__ );
1629
1630 return $title;
1631 // TODO: replace the above with the code below:
1632 // return self::castFromLinkTarget(
1633 // MediaWikiServices::getInstance()->getNamespaceInfo()->getTalkPage( $this ) );
1634 }
1635
1645 public function getTalkPageIfDefined() {
1646 if ( !$this->canHaveTalkPage() ) {
1647 return null;
1648 }
1649
1650 return $this->getTalkPage();
1651 }
1652
1660 public function getSubjectPage() {
1661 // Is this the same title?
1662 $subjectNS = MediaWikiServices::getInstance()->getNamespaceInfo()
1663 ->getSubject( $this->mNamespace );
1664 if ( $this->mNamespace == $subjectNS ) {
1665 return $this;
1666 }
1667 // NOTE: The equivalent code in NamespaceInfo is less lenient about producing invalid titles.
1668 // Instead of failing on invalid titles, let's just log the issue for now.
1669 // See the discussion on T227817.
1670 $title = self::makeTitle( $subjectNS, $this->mDbkeyform );
1671
1672 $this->warnIfPageCannotExist( $title, __METHOD__ );
1673
1674 return $title;
1675 // TODO: replace the above with the code below:
1676 // return self::castFromLinkTarget(
1677 // MediaWikiServices::getInstance()->getNamespaceInfo()->getSubjectPage( $this ) );
1678 }
1679
1686 private function warnIfPageCannotExist( Title $title, $method ) {
1687 if ( $this->getText() == '' ) {
1689 $method . ': called on empty title ' . $this->getFullText() . ', returning '
1690 . $title->getFullText()
1691 );
1692
1693 return true;
1694 }
1695
1696 if ( $this->getInterwiki() !== '' ) {
1698 $method . ': called on interwiki title ' . $this->getFullText() . ', returning '
1699 . $title->getFullText()
1700 );
1701
1702 return true;
1703 }
1704
1705 return false;
1706 }
1707
1717 public function getOtherPage() {
1718 // NOTE: Depend on the methods in this class instead of their equivalent in NamespaceInfo,
1719 // until their semantics has become exactly the same.
1720 // See the discussion on T227817.
1721 if ( $this->isSpecialPage() ) {
1722 throw new MWException( 'Special pages cannot have other pages' );
1723 }
1724 if ( $this->isTalkPage() ) {
1725 return $this->getSubjectPage();
1726 } else {
1727 if ( !$this->canHaveTalkPage() ) {
1728 throw new MWException( "{$this->getPrefixedText()} does not have an other page" );
1729 }
1730 return $this->getTalkPage();
1731 }
1732 // TODO: replace the above with the code below:
1733 // return self::castFromLinkTarget(
1734 // MediaWikiServices::getInstance()->getNamespaceInfo()->getAssociatedPage( $this ) );
1735 }
1736
1744 public function getFragment(): string {
1745 return $this->mFragment;
1746 }
1747
1753 public function getFragmentForURL() {
1754 if ( !$this->hasFragment() ) {
1755 return '';
1756 } elseif ( $this->isExternal() ) {
1757 // Note: If the interwiki is unknown, it's treated as a namespace on the local wiki,
1758 // so we treat it like a local interwiki.
1759 $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
1760 if ( $interwiki && !$interwiki->isLocal() ) {
1761 return '#' . Sanitizer::escapeIdForExternalInterwiki( $this->mFragment );
1762 }
1763 }
1764
1765 return '#' . Sanitizer::escapeIdForLink( $this->mFragment );
1766 }
1767
1778 public function setFragment( $fragment ) {
1779 $this->uncache();
1780 $this->mFragment = self::normalizeFragment( $fragment );
1781 }
1782
1790 public function createFragmentTarget( string $fragment ): self {
1791 return self::makeTitle(
1792 $this->mNamespace,
1793 $this->getText(),
1794 $fragment,
1795 $this->mInterwiki
1796 );
1797 }
1798
1805 private static function normalizeFragment( $fragment ) {
1806 if ( str_starts_with( $fragment, '#' ) ) {
1807 $fragment = substr( $fragment, 1 );
1808 }
1809 return strtr( $fragment, '_', ' ' );
1810 }
1811
1819 private function prefix( $name ) {
1820 $p = '';
1821 if ( $this->isExternal() ) {
1822 $p = $this->mInterwiki . ':';
1823 }
1824
1825 if ( $this->mNamespace != 0 ) {
1826 $nsText = $this->getNsText();
1827
1828 if ( $nsText === false ) {
1829 // See T165149. Awkward, but better than erroneously linking to the main namespace.
1830 $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
1831 getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
1832 }
1833
1834 $p .= $nsText . ':';
1835 }
1836 return $p . $name;
1837 }
1838
1845 public function getPrefixedDBkey() {
1846 $s = $this->prefix( $this->mDbkeyform );
1847 $s = strtr( $s, ' ', '_' );
1848 return $s;
1849 }
1850
1857 public function getPrefixedText() {
1858 if ( $this->prefixedText === null ) {
1859 $s = $this->prefix( $this->mTextform );
1860 $s = strtr( $s, '_', ' ' );
1861 $this->prefixedText = $s;
1862 }
1863 return $this->prefixedText;
1864 }
1865
1871 public function __toString(): string {
1872 return $this->getPrefixedText();
1873 }
1874
1881 public function getFullText() {
1882 $text = $this->getPrefixedText();
1883 if ( $this->hasFragment() ) {
1884 $text .= '#' . $this->mFragment;
1885 }
1886 return $text;
1887 }
1888
1903 private function findSubpageDivider( $text, $dir ) {
1904 if ( $dir > 0 ) {
1905 // Skip leading slashes, but keep the last one when there is nothing but slashes
1906 $bottom = strspn( $text, '/', 0, -1 );
1907 $idx = strpos( $text, '/', $bottom );
1908 } else {
1909 // Any slash from the end can be a divider, as subpage names can be empty
1910 $idx = strrpos( $text, '/' );
1911 }
1912
1913 // The first character can never be a divider, as that would result in an empty base
1914 return $idx === 0 ? false : $idx;
1915 }
1916
1921 private function hasSubpagesEnabled() {
1922 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1923 hasSubpages( $this->mNamespace );
1924 }
1925
1941 public function getRootText() {
1942 $text = $this->getText();
1943 if ( !$this->hasSubpagesEnabled() ) {
1944 return $text;
1945 }
1946
1947 $firstSlashPos = $this->findSubpageDivider( $text, +1 );
1948 // Don't discard the real title if there's no subpage involved
1949 if ( $firstSlashPos === false ) {
1950 return $text;
1951 }
1952
1953 return substr( $text, 0, $firstSlashPos );
1954 }
1955
1968 public function getRootTitle() {
1969 $title = self::makeTitleSafe( $this->mNamespace, $this->getRootText() );
1970
1971 if ( !$title ) {
1972 if ( !$this->isValid() ) {
1973 // If the title wasn't valid in the first place, we can't expect
1974 // to successfully parse it. T290194
1975 return $this;
1976 }
1977
1978 Assert::postcondition(
1979 $title !== null,
1980 'makeTitleSafe() should always return a Title for the text ' .
1981 'returned by getRootText().'
1982 );
1983 }
1984
1985 return $title;
1986 }
1987
2002 public function getBaseText() {
2003 $text = $this->getText();
2004 if ( !$this->hasSubpagesEnabled() ) {
2005 return $text;
2006 }
2007
2008 $lastSlashPos = $this->findSubpageDivider( $text, -1 );
2009 // Don't discard the real title if there's no subpage involved
2010 if ( $lastSlashPos === false ) {
2011 return $text;
2012 }
2013
2014 return substr( $text, 0, $lastSlashPos );
2015 }
2016
2029 public function getBaseTitle() {
2030 $title = self::makeTitleSafe( $this->mNamespace, $this->getBaseText() );
2031
2032 if ( !$title ) {
2033 if ( !$this->isValid() ) {
2034 // If the title wasn't valid in the first place, we can't expect
2035 // to successfully parse it. T290194
2036 return $this;
2037 }
2038
2039 Assert::postcondition(
2040 $title !== null,
2041 'makeTitleSafe() should always return a Title for the text ' .
2042 'returned by getBaseText().'
2043 );
2044 }
2045
2046 return $title;
2047 }
2048
2060 public function getSubpageText() {
2061 $text = $this->getText();
2062 if ( !$this->hasSubpagesEnabled() ) {
2063 return $text;
2064 }
2065
2066 $lastSlashPos = $this->findSubpageDivider( $text, -1 );
2067 if ( $lastSlashPos === false ) {
2068 // T256922 - Return the title text if no subpages
2069 return $text;
2070 }
2071 return substr( $text, $lastSlashPos + 1 );
2072 }
2073
2087 public function getSubpage( $text ) {
2088 return self::makeTitleSafe(
2089 $this->mNamespace,
2090 $this->getText() . '/' . $text,
2091 '',
2092 $this->mInterwiki
2093 );
2094 }
2095
2108 public function getFullSubpageText() {
2109 $text = $this->getText();
2110 $slashPos = strpos( $text, '/' );
2111
2112 if ( $slashPos === false ) {
2113 return '';
2114 }
2115
2116 return substr( $text, $slashPos + 1 );
2117 }
2118
2124 public function getSubpageUrlForm() {
2125 $text = $this->getSubpageText();
2126 $text = wfUrlencode( strtr( $text, ' ', '_' ) );
2127 return $text;
2128 }
2129
2135 public function getPrefixedURL() {
2136 $s = $this->prefix( $this->mDbkeyform );
2137 $s = wfUrlencode( strtr( $s, ' ', '_' ) );
2138 return $s;
2139 }
2140
2152 public function getFullURL( $query = '', $query2 = false, $proto = PROTO_RELATIVE ) {
2153 $services = MediaWikiServices::getInstance();
2154
2155 $query = is_array( $query ) ? wfArrayToCgi( $query ) : $query;
2156
2157 # Hand off all the decisions on urls to getLocalURL
2158 $url = $this->getLocalURL( $query );
2159
2160 # Expand the url to make it a full url. Note that getLocalURL has the
2161 # potential to output full urls for a variety of reasons, so we use
2162 # UrlUtils::expand() instead of simply prepending $wgServer
2163 $url = (string)$services->getUrlUtils()->expand( $url, $proto );
2164
2165 # Finally, add the fragment.
2166 $url .= $this->getFragmentForURL();
2167 ( new HookRunner( $services->getHookContainer() ) )->onGetFullURL( $this, $url, $query );
2168 return $url;
2169 }
2170
2187 public function getFullUrlForRedirect( $query = '', $proto = PROTO_CURRENT ) {
2188 $target = $this;
2189 if ( $this->isExternal() ) {
2190 $target = SpecialPage::getTitleFor(
2191 'GoToInterwiki',
2192 $this->getPrefixedDBkey()
2193 );
2194 }
2195 return $target->getFullURL( $query, false, $proto );
2196 }
2197
2215 public function getLocalURL( $query = '' ) {
2217
2218 $query = is_array( $query ) ? wfArrayToCgi( $query ) : $query;
2219
2220 $services = MediaWikiServices::getInstance();
2221 $hookRunner = new HookRunner( $services->getHookContainer() );
2222 $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
2223 if ( $interwiki ) {
2224 $namespace = $this->getNsText();
2225 if ( $namespace != '' ) {
2226 # Can this actually happen? Interwikis shouldn't be parsed.
2227 # Yes! It can in interwiki transclusion. But... it probably shouldn't.
2228 $namespace .= ':';
2229 }
2230 $url = $interwiki->getURL( $namespace . $this->mDbkeyform );
2231 $url = wfAppendQuery( $url, $query );
2232 } else {
2233 $dbkey = wfUrlencode( $this->getPrefixedDBkey() );
2234 if ( $query == '' ) {
2235 if ( $wgMainPageIsDomainRoot && $this->isMainPage() ) {
2236 $url = '/';
2237 } else {
2238 $url = str_replace( '$1', $dbkey, $wgArticlePath );
2239 }
2240 $hookRunner->onGetLocalURL__Article( $this, $url );
2241 } else {
2243 $url = false;
2244 $matches = [];
2245
2246 $articlePaths = PathRouter::getActionPaths( $wgActionPaths, $wgArticlePath );
2247
2248 if ( $articlePaths
2249 && preg_match( '/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches )
2250 ) {
2251 $action = urldecode( $matches[2] );
2252 if ( isset( $articlePaths[$action] ) ) {
2253 $query = $matches[1];
2254 if ( isset( $matches[4] ) ) {
2255 $query .= $matches[4];
2256 }
2257 $url = str_replace( '$1', $dbkey, $articlePaths[$action] );
2258 if ( $query != '' ) {
2259 $url = wfAppendQuery( $url, $query );
2260 }
2261 }
2262 }
2263
2264 if ( $url === false
2266 && preg_match( '/^variant=([^&]*)$/', $query, $matches )
2267 && $this->getPageLanguage()->equals( $services->getContentLanguage() )
2268 && $this->getPageLanguageConverter()->hasVariants()
2269 ) {
2270 $variant = urldecode( $matches[1] );
2271 if ( $this->getPageLanguageConverter()->hasVariant( $variant ) ) {
2272 // Only do the variant replacement if the given variant is a valid
2273 // variant for the page's language.
2274 $url = str_replace( '$2', urlencode( $variant ), $wgVariantArticlePath );
2275 $url = str_replace( '$1', $dbkey, $url );
2276 }
2277 }
2278
2279 if ( $url === false ) {
2280 if ( $query == '-' ) {
2281 $query = '';
2282 }
2283 $url = "{$wgScript}?title={$dbkey}&{$query}";
2284 }
2285 }
2286 $hookRunner->onGetLocalURL__Internal( $this, $url, $query );
2287 }
2288
2289 $hookRunner->onGetLocalURL( $this, $url, $query );
2290 return $url;
2291 }
2292
2310 public function getLinkURL( $query = '', $query2 = false, $proto = false ) {
2311 if ( $this->isExternal() || $proto !== false ) {
2312 $ret = $this->getFullURL( $query, false, $proto );
2313 } elseif ( $this->getPrefixedText() === '' && $this->hasFragment() ) {
2314 $ret = $this->getFragmentForURL();
2315 } else {
2316 $ret = $this->getLocalURL( $query ) . $this->getFragmentForURL();
2317 }
2318 return $ret;
2319 }
2320
2334 public function getInternalURL( $query = '' ) {
2336 $services = MediaWikiServices::getInstance();
2337
2338 $query = is_array( $query ) ? wfArrayToCgi( $query ) : $query;
2339
2340 $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
2341 $url = (string)$services->getUrlUtils()->expand( $server . $this->getLocalURL( $query ), PROTO_HTTP );
2342 ( new HookRunner( $services->getHookContainer() ) )
2343 ->onGetInternalURL( $this, $url, $query );
2344 return $url;
2345 }
2346
2359 public function getCanonicalURL( $query = '' ) {
2360 $services = MediaWikiServices::getInstance();
2361
2362 $query = is_array( $query ) ? wfArrayToCgi( $query ) : $query;
2363
2364 $url = (string)$services->getUrlUtils()->expand(
2365 $this->getLocalURL( $query ) . $this->getFragmentForURL(),
2367 );
2368 ( new HookRunner( $services->getHookContainer() ) )
2369 ->onGetCanonicalURL( $this, $url, $query );
2370 return $url;
2371 }
2372
2378 public function getEditURL() {
2379 if ( $this->isExternal() ) {
2380 return '';
2381 }
2382 $s = $this->getLocalURL( 'action=edit' );
2383
2384 return $s;
2385 }
2386
2392 public static function purgeExpiredRestrictions() {
2393 if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
2394 return;
2395 }
2396
2397 DeferredUpdates::addUpdate( new AutoCommitUpdate(
2398 MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase(),
2399 __METHOD__,
2400 static function ( IDatabase $dbw, $fname ) {
2401 $config = MediaWikiServices::getInstance()->getMainConfig();
2402 $ids = $dbw->newSelectQueryBuilder()
2403 ->select( 'pr_id' )
2404 ->from( 'page_restrictions' )
2405 ->where( $dbw->expr( 'pr_expiry', '<', $dbw->timestamp() ) )
2406 ->limit( $config->get( MainConfigNames::UpdateRowsPerQuery ) ) // T135470
2407 ->caller( $fname )->fetchFieldValues();
2408 if ( $ids ) {
2409 $dbw->newDeleteQueryBuilder()
2410 ->deleteFrom( 'page_restrictions' )
2411 ->where( [ 'pr_id' => $ids ] )
2412 ->caller( $fname )->execute();
2413 }
2414
2415 $dbw->newDeleteQueryBuilder()
2416 ->deleteFrom( 'protected_titles' )
2417 ->where( $dbw->expr( 'pt_expiry', '<', $dbw->timestamp() ) )
2418 ->caller( $fname )->execute();
2419 }
2420 ) );
2421 }
2422
2428 public function hasSubpages() {
2429 if (
2430 !MediaWikiServices::getInstance()->getNamespaceInfo()->
2431 hasSubpages( $this->mNamespace )
2432 ) {
2433 # Duh
2434 return false;
2435 }
2436
2437 # We dynamically add a member variable for the purpose of this method
2438 # alone to cache the result. There's no point in having it hanging
2439 # around uninitialized in every Title object; therefore we only add it
2440 # if needed and don't declare it statically.
2441 if ( $this->mHasSubpages === null ) {
2442 $subpages = $this->getSubpages( 1 );
2443 $this->mHasSubpages = $subpages instanceof TitleArrayFromResult && $subpages->count();
2444 }
2445
2446 return $this->mHasSubpages;
2447 }
2448
2456 public function getSubpages( $limit = -1 ) {
2457 if (
2458 !MediaWikiServices::getInstance()->getNamespaceInfo()->
2459 hasSubpages( $this->mNamespace )
2460 ) {
2461 return [];
2462 }
2463
2464 $services = MediaWikiServices::getInstance();
2465 $pageStore = $services->getPageStore();
2466 $titleFactory = $services->getTitleFactory();
2467 $query = $pageStore->newSelectQueryBuilder()
2468 ->fields( $pageStore->getSelectFields() )
2469 ->whereTitlePrefix( $this->getNamespace(), $this->getDBkey() . '/' )
2470 ->caller( __METHOD__ );
2471 if ( $limit > -1 ) {
2472 $query->limit( $limit );
2473 }
2474
2475 return $titleFactory->newTitleArrayFromResult( $query->fetchResultSet() );
2476 }
2477
2484 public function isDeleted() {
2485 return $this->getDeletedEditsCount();
2486 }
2487
2494 public function getDeletedEditsCount() {
2495 if ( $this->mNamespace < 0 ) {
2496 return 0;
2497 }
2498
2499 $dbr = $this->getDbProvider()->getReplicaDatabase();
2500 $n = (int)$dbr->newSelectQueryBuilder()
2501 ->select( 'COUNT(*)' )
2502 ->from( 'archive' )
2503 ->where( [ 'ar_namespace' => $this->mNamespace, 'ar_title' => $this->mDbkeyform ] )
2504 ->caller( __METHOD__ )->fetchField();
2505 if ( $this->mNamespace === NS_FILE ) {
2506 $n += $dbr->newSelectQueryBuilder()
2507 ->select( 'COUNT(*)' )
2508 ->from( 'filearchive' )
2509 ->where( [ 'fa_name' => $this->mDbkeyform ] )
2510 ->caller( __METHOD__ )->fetchField();
2511 }
2512 return $n;
2513 }
2514
2521 public function isDeletedQuick() {
2522 return $this->hasDeletedEdits();
2523 }
2524
2531 public function hasDeletedEdits() {
2532 if ( $this->mNamespace < 0 ) {
2533 return false;
2534 }
2535 $dbr = $this->getDbProvider()->getReplicaDatabase();
2536 $deleted = (bool)$dbr->newSelectQueryBuilder()
2537 ->select( '1' )
2538 ->from( 'archive' )
2539 ->where( [ 'ar_namespace' => $this->mNamespace, 'ar_title' => $this->mDbkeyform ] )
2540 ->caller( __METHOD__ )->fetchField();
2541 if ( !$deleted && $this->mNamespace === NS_FILE ) {
2542 $deleted = (bool)$dbr->newSelectQueryBuilder()
2543 ->select( '1' )
2544 ->from( 'filearchive' )
2545 ->where( [ 'fa_name' => $this->mDbkeyform ] )
2546 ->caller( __METHOD__ )->fetchField();
2547 }
2548 return $deleted;
2549 }
2550
2558 public function getArticleID( $flags = 0 ) {
2559 if ( $this->mArticleID === -1 && !$this->canExist() ) {
2560 $this->mArticleID = 0;
2561
2562 return $this->mArticleID;
2563 }
2564
2565 if ( $this->mArticleID === -1 || $this->shouldReadLatest( $flags ) ) {
2566 $this->mArticleID = (int)$this->getFieldFromPageStore( 'page_id', $flags );
2567 }
2568
2569 return $this->mArticleID;
2570 }
2571
2586 public function isRedirect( $flags = 0 ) {
2587 if ( $this->shouldReadLatest( $flags ) || $this->mRedirect === null ) {
2588 $this->mRedirect = (bool)$this->getFieldFromPageStore( 'page_is_redirect', $flags );
2589 }
2590
2591 return $this->mRedirect;
2592 }
2593
2601 public function getLength( $flags = 0 ) {
2602 if ( $this->shouldReadLatest( $flags ) || $this->mLength < 0 ) {
2603 $this->mLength = (int)$this->getFieldFromPageStore( 'page_len', $flags );
2604 }
2605
2606 if ( $this->mLength < 0 ) {
2607 $this->mLength = 0;
2608 }
2609
2610 return $this->mLength;
2611 }
2612
2619 public function getLatestRevID( $flags = 0 ) {
2620 if ( $this->shouldReadLatest( $flags ) || $this->mLatestID === false ) {
2621 $this->mLatestID = (int)$this->getFieldFromPageStore( 'page_latest', $flags );
2622 }
2623
2624 if ( !$this->mLatestID ) {
2625 $this->mLatestID = 0;
2626 }
2627
2628 return $this->mLatestID;
2629 }
2630
2644 public function resetArticleID( $id ) {
2645 if ( $id === false ) {
2646 $this->mArticleID = -1;
2647 } else {
2648 $this->mArticleID = (int)$id;
2649 }
2650 $this->mRedirect = null;
2651 $this->mLength = -1;
2652 $this->mLatestID = false;
2653 $this->mContentModel = false;
2654 $this->mForcedContentModel = false;
2655 $this->mEstimateRevisions = null;
2656 $this->mPageLanguage = null;
2657 $this->mDbPageLanguage = false;
2658 $this->mIsBigDeletion = null;
2659
2660 $this->uncache();
2661 MediaWikiServices::getInstance()->getLinkCache()->clearLink( $this );
2662 MediaWikiServices::getInstance()->getRestrictionStore()->flushRestrictions( $this );
2663 }
2664
2665 public static function clearCaches() {
2666 if ( MediaWikiServices::hasInstance() ) {
2667 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2668 $linkCache->clear();
2669 }
2670
2671 // Reset cached main page instance (T395214).
2672 self::$cachedMainPage = null;
2673
2674 $titleCache = self::getTitleCache();
2675 $titleCache->clear();
2676 }
2677
2685 public static function capitalize( $text, $ns = NS_MAIN ) {
2686 $services = MediaWikiServices::getInstance();
2687 if ( $services->getNamespaceInfo()->isCapitalized( $ns ) ) {
2688 return $services->getContentLanguage()->ucfirst( $text );
2689 } else {
2690 return $text;
2691 }
2692 }
2693
2710 private function secureAndSplit( $text, $defaultNamespace = null ) {
2711 $defaultNamespace ??= self::DEFAULT_NAMESPACE;
2712
2713 // @note: splitTitleString() is a temporary hack to allow TitleParser to share
2714 // the parsing code with Title, while avoiding massive refactoring.
2715 // @todo: get rid of secureAndSplit, refactor parsing code.
2716 $titleParser = MediaWikiServices::getInstance()->getTitleParser();
2717 // MalformedTitleException can be thrown here
2718 $parts = $titleParser->splitTitleString( $text, $defaultNamespace );
2719
2720 # Fill fields
2721 $this->setFragment( '#' . $parts['fragment'] );
2722 $this->mInterwiki = $parts['interwiki'];
2723 $this->mLocalInterwiki = $parts['local_interwiki'];
2724 $this->mNamespace = $parts['namespace'];
2725
2726 $this->mDbkeyform = $parts['dbkey'];
2727 $this->mUrlform = wfUrlencode( $this->mDbkeyform );
2728 $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
2729
2730 // splitTitleString() guarantees that this title is valid.
2731 $this->mIsValid = true;
2732
2733 # We already know that some pages won't be in the database!
2734 if ( $this->isExternal() || $this->isSpecialPage() || $this->mTextform === '' ) {
2735 $this->mArticleID = 0;
2736 }
2737 }
2738
2751 public function getLinksTo( $options = [], $table = 'pagelinks', $prefix = 'pl' ) {
2752 $domainMap = [
2753 'categorylinks' => CategoryLinksTable::VIRTUAL_DOMAIN,
2754 'imagelinks' => ImageLinksTable::VIRTUAL_DOMAIN,
2755 'pagelinks' => PageLinksTable::VIRTUAL_DOMAIN,
2756 'templatelinks' => TemplateLinksTable::VIRTUAL_DOMAIN,
2757 ];
2758 $domain = $domainMap[$table] ?? false;
2759
2760 if ( count( $options ) > 0 ) {
2761 $db = $this->getDbProvider()->getPrimaryDatabase( $domain );
2762 } else {
2763 $db = $this->getDbProvider()->getReplicaDatabase( $domain );
2764 }
2765
2766 $linksMigration = MediaWikiServices::getInstance()->getLinksMigration();
2767 if ( isset( $linksMigration::$mapping[$table] ) ) {
2768 $titleConds = $linksMigration->getLinksConditions( $table, $this );
2769 } else {
2770 $titleConds = [
2771 "{$prefix}_namespace" => $this->mNamespace,
2772 "{$prefix}_title" => $this->mDbkeyform
2773 ];
2774 }
2775
2776 $res = $db->newSelectQueryBuilder()
2777 ->select( LinkCache::getSelectFields() )
2778 ->from( $table )
2779 ->join( 'page', null, "{$prefix}_from=page_id" )
2780 ->where( $titleConds )
2781 ->options( $options )
2782 ->caller( __METHOD__ )
2783 ->fetchResultSet();
2784
2785 $retVal = [];
2786 if ( $res->numRows() ) {
2787 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2788 foreach ( $res as $row ) {
2789 $titleObj = self::makeTitle( $row->page_namespace, $row->page_title );
2790 if ( $titleObj ) {
2791 $linkCache->addGoodLinkObjFromRow( $titleObj, $row );
2792 $retVal[] = $titleObj;
2793 }
2794 }
2795 }
2796 return $retVal;
2797 }
2798
2809 public function getTemplateLinksTo( $options = [] ) {
2810 return $this->getLinksTo( $options, 'templatelinks', 'tl' );
2811 }
2812
2825 public function getLinksFrom( $options = [], $table = 'pagelinks', $prefix = 'pl' ) {
2826 $id = $this->getArticleID();
2827
2828 # If the page doesn't exist; there can't be any link from this page
2829 if ( !$id ) {
2830 return [];
2831 }
2832
2833 $domainMap = [
2834 'categorylinks' => CategoryLinksTable::VIRTUAL_DOMAIN,
2835 'imagelinks' => ImageLinksTable::VIRTUAL_DOMAIN,
2836 'pagelinks' => PageLinksTable::VIRTUAL_DOMAIN,
2837 'templatelinks' => TemplateLinksTable::VIRTUAL_DOMAIN,
2838 ];
2839 $domain = $domainMap[$table] ?? false;
2840
2841 $db = $this->getDbProvider()->getReplicaDatabase( $domain );
2842 $linksMigration = MediaWikiServices::getInstance()->getLinksMigration();
2843
2844 $queryBuilder = $db->newSelectQueryBuilder();
2845 if ( isset( $linksMigration::$mapping[$table] ) ) {
2846 [ $blNamespace, $blTitle ] = $linksMigration->getTitleFields( $table );
2847 $linktargetQueryInfo = $linksMigration->getQueryInfo( $table );
2848 $queryBuilder->queryInfo( $linktargetQueryInfo );
2849 } else {
2850 $blNamespace = "{$prefix}_namespace";
2851 $blTitle = "{$prefix}_title";
2852 $queryBuilder->select( [ $blNamespace, $blTitle ] )
2853 ->from( $table );
2854 }
2855
2856 $pageQuery = WikiPage::getQueryInfo();
2857 $res = $queryBuilder
2858 ->where( [ "{$prefix}_from" => $id ] )
2859 ->leftJoin( 'page', null, [ "page_namespace=$blNamespace", "page_title=$blTitle" ] )
2860 ->fields( $pageQuery['fields'] )
2861 ->options( $options )
2862 ->caller( __METHOD__ )
2863 ->fetchResultSet();
2864
2865 $retVal = [];
2866 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2867 foreach ( $res as $row ) {
2868 if ( $row->page_id ) {
2869 $titleObj = self::newFromRow( $row );
2870 } else {
2871 $titleObj = self::makeTitle( $row->$blNamespace, $row->$blTitle );
2872 $linkCache->addBadLinkObj( $titleObj );
2873 }
2874 $retVal[] = $titleObj;
2875 }
2876
2877 return $retVal;
2878 }
2879
2890 public function getTemplateLinksFrom( $options = [] ) {
2891 return $this->getLinksFrom( $options, 'templatelinks', 'tl' );
2892 }
2893
2901 public function isSingleRevRedirect() {
2902 $dbw = $this->getDbProvider()->getPrimaryDatabase();
2903 $dbw->startAtomic( __METHOD__ );
2904 $pageStore = MediaWikiServices::getInstance()->getPageStore();
2905
2906 $row = $dbw->newSelectQueryBuilder()
2907 ->select( $pageStore->getSelectFields() )
2908 ->from( 'page' )
2909 ->where( $this->pageCond() )
2910 ->caller( __METHOD__ )->fetchRow();
2911 // Update the cached fields
2912 $this->loadFromRow( $row );
2913
2914 if ( $this->mRedirect && $this->mLatestID ) {
2915 $isSingleRevRedirect = !$dbw->newSelectQueryBuilder()
2916 ->select( '1' )
2917 ->forUpdate()
2918 ->from( 'revision' )
2919 ->where( [ 'rev_page' => $this->mArticleID, $dbw->expr( 'rev_id', '!=', (int)$this->mLatestID ) ] )
2920 ->caller( __METHOD__ )->fetchField();
2921 } else {
2922 $isSingleRevRedirect = false;
2923 }
2924
2925 $dbw->endAtomic( __METHOD__ );
2926
2927 return $isSingleRevRedirect;
2928 }
2929
2937 public function getParentCategories() {
2938 $data = [];
2939
2940 $titleKey = $this->getArticleID();
2941
2942 if ( $titleKey === 0 ) {
2943 return $data;
2944 }
2945
2946 $dbr = $this->getDbProvider()->getReplicaDatabase( CategoryLinksTable::VIRTUAL_DOMAIN );
2947 $res = $dbr->newSelectQueryBuilder()
2948 ->select( 'lt_title' )
2949 ->from( 'categorylinks' )
2950 ->join( 'linktarget', null, 'cl_target_id = lt_id' )
2951 ->where( [ 'cl_from' => $titleKey, 'lt_namespace' => NS_CATEGORY ] )
2952 ->caller( __METHOD__ )
2953 ->fetchResultSet();
2954
2955 if ( $res->numRows() > 0 ) {
2956 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
2957 foreach ( $res as $row ) {
2958 // $data[] = Title::newFromText( $contLang->getNsText ( NS_CATEGORY ).':'.$row->lt_title);
2959 $data[$contLang->getNsText( NS_CATEGORY ) . ':' . $row->lt_title] =
2960 $this->getFullText();
2961 }
2962 }
2963 return $data;
2964 }
2965
2972 public function getParentCategoryTree( $children = [] ) {
2973 $stack = [];
2974 $parents = $this->getParentCategories();
2975
2976 if ( $parents ) {
2977 foreach ( $parents as $parent => $current ) {
2978 if ( array_key_exists( $parent, $children ) ) {
2979 # Circular reference
2980 $stack[$parent] = [];
2981 } else {
2982 $nt = self::newFromText( $parent );
2983 if ( $nt ) {
2984 $stack[$parent] = $nt->getParentCategoryTree( $children + [ $parent => 1 ] );
2985 }
2986 }
2987 }
2988 }
2989
2990 return $stack;
2991 }
2992
2999 public function pageCond() {
3000 if ( $this->mArticleID > 0 ) {
3001 // PK avoids secondary lookups in InnoDB, shouldn't hurt other DBs
3002 return [ 'page_id' => $this->mArticleID ];
3003 } else {
3004 return [ 'page_namespace' => $this->mNamespace, 'page_title' => $this->mDbkeyform ];
3005 }
3006 }
3007
3016 public function isNewPage( $flags = IDBAccessObject::READ_NORMAL ) {
3017 // NOTE: we rely on PHP casting "0" to false here.
3018 return (bool)$this->getFieldFromPageStore( 'page_is_new', $flags );
3019 }
3020
3027 public function isBigDeletion() {
3029
3030 if ( !$wgDeleteRevisionsLimit ) {
3031 return false;
3032 }
3033
3034 if ( $this->mIsBigDeletion === null ) {
3035 $dbr = $this->getDbProvider()->getReplicaDatabase();
3036 $revCount = $dbr->newSelectQueryBuilder()
3037 ->select( '1' )
3038 ->from( 'revision' )
3039 ->where( [ 'rev_page' => $this->getArticleID() ] )
3040 ->limit( $wgDeleteRevisionsLimit + 1 )
3041 ->caller( __METHOD__ )->fetchRowCount();
3042
3043 $this->mIsBigDeletion = $revCount > $wgDeleteRevisionsLimit;
3044 }
3045
3046 return $this->mIsBigDeletion;
3047 }
3048
3054 public function estimateRevisionCount() {
3055 if ( !$this->exists() ) {
3056 return 0;
3057 }
3058
3059 if ( $this->mEstimateRevisions === null ) {
3060 $dbr = $this->getDbProvider()->getReplicaDatabase();
3061 $this->mEstimateRevisions = $dbr->newSelectQueryBuilder()
3062 ->select( '*' )
3063 ->from( 'revision' )
3064 ->where( [ 'rev_page' => $this->getArticleID() ] )
3065 ->caller( __METHOD__ )
3066 ->estimateRowCount();
3067 }
3068
3069 return $this->mEstimateRevisions;
3070 }
3071
3086 public function equals( object $other ) {
3087 // NOTE: In contrast to isSameLinkAs(), this ignores the fragment part!
3088 // NOTE: In contrast to isSamePageAs(), this ignores the page ID!
3089 // NOTE: === is necessary for proper matching of number-like titles
3090 return $other instanceof Title
3091 && $this->getInterwiki() === $other->getInterwiki()
3092 && $this->getNamespace() === $other->getNamespace()
3093 && $this->getDBkey() === $other->getDBkey();
3094 }
3095
3100 public function isSamePageAs( PageReference $other ): bool {
3101 // NOTE: keep in sync with PageReferenceValue::isSamePageAs()!
3102 return $this->getWikiId() === $other->getWikiId()
3103 && $this->getNamespace() === $other->getNamespace()
3104 && $this->getDBkey() === $other->getDBkey();
3105 }
3106
3113 public function isSubpageOf( Title $title ) {
3114 return $this->mInterwiki === $title->mInterwiki
3115 && $this->mNamespace == $title->mNamespace
3116 && str_starts_with( $this->mDbkeyform, $title->mDbkeyform . '/' );
3117 }
3118
3129 public function exists( $flags = 0 ): bool {
3130 $exists = $this->getArticleID( $flags ) != 0;
3131 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onTitleExists( $this, $exists );
3132 return $exists;
3133 }
3134
3151 public function isAlwaysKnown() {
3152 $isKnown = null;
3153
3154 $services = MediaWikiServices::getInstance();
3155 ( new HookRunner( $services->getHookContainer() ) )->onTitleIsAlwaysKnown( $this, $isKnown );
3156
3157 if ( $isKnown !== null ) {
3158 return $isKnown;
3159 }
3160
3161 if ( $this->isExternal() ) {
3162 return true; // any interwiki link might be viewable, for all we know
3163 }
3164
3165 switch ( $this->mNamespace ) {
3166 case NS_MEDIA:
3167 case NS_FILE:
3168 // file exists, possibly in a foreign repo
3169 return (bool)$services->getRepoGroup()->findFile( $this );
3170 case NS_SPECIAL:
3171 // valid special page
3172 return $services->getSpecialPageFactory()->exists( $this->mDbkeyform );
3173 case NS_MAIN:
3174 // selflink, possibly with fragment
3175 return $this->mDbkeyform == '';
3176 case NS_MEDIAWIKI:
3177 // known system message
3178 return $this->hasSourceText() !== false;
3179 default:
3180 return false;
3181 }
3182 }
3183
3195 public function isKnown() {
3196 return $this->isAlwaysKnown() || $this->exists();
3197 }
3198
3204 public function hasSourceText() {
3205 if ( $this->exists() ) {
3206 return true;
3207 }
3208
3209 if ( $this->mNamespace === NS_MEDIAWIKI ) {
3210 $services = MediaWikiServices::getInstance();
3211 // If the page doesn't exist but is a known system message, default
3212 // message content will be displayed, same for language subpages-
3213 // Use always content language to avoid loading hundreds of languages
3214 // to get the link color.
3215 $contLang = $services->getContentLanguage();
3216 [ $name, ] = $services->getMessageCache()->figureMessage(
3217 $contLang->lcfirst( $this->getText() )
3218 );
3219 $message = wfMessage( $name )->inLanguage( $contLang )->useDatabase( false );
3220 return $message->exists();
3221 }
3222
3223 return false;
3224 }
3225
3263 public function getDefaultMessageText() {
3264 $message = $this->getDefaultSystemMessage();
3265
3266 return $message ? $message->plain() : false;
3267 }
3268
3276 public function getDefaultSystemMessage(): ?Message {
3277 if ( $this->mNamespace !== NS_MEDIAWIKI ) { // Just in case
3278 return null;
3279 }
3280
3281 [ $name, $lang ] = MediaWikiServices::getInstance()->getMessageCache()->figureMessage(
3282 MediaWikiServices::getInstance()->getContentLanguage()->lcfirst( $this->getText() )
3283 );
3284
3285 if ( wfMessage( $name )->inLanguage( $lang )->useDatabase( false )->exists() ) {
3286 return wfMessage( $name )->inLanguage( $lang );
3287 } else {
3288 return null;
3289 }
3290 }
3291
3298 public function invalidateCache( $purgeTime = null ) {
3299 if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
3300 return false;
3301 }
3302 if ( $this->mArticleID === 0 ) {
3303 // avoid gap locking if we know it's not there
3304 return true;
3305 }
3306
3307 $conds = $this->pageCond();
3308
3309 // Periodically recompute page_random (T309477). This mitigates bias on
3310 // Special:Random due deleted pages leaving "gaps" in the distribution.
3311 //
3312 // Optimization: Update page_random only for 10% of updates.
3313 // Optimization: Do this outside the main transaction to avoid locking for too long.
3314 // Optimization: Update page_random alongside page_touched to avoid extra database writes.
3315 DeferredUpdates::addUpdate(
3316 new AutoCommitUpdate(
3317 $this->getDbProvider()->getPrimaryDatabase(),
3318 __METHOD__,
3319 function ( IDatabase $dbw, $fname ) use ( $conds, $purgeTime ) {
3320 $dbTimestamp = $dbw->timestamp( $purgeTime ?: time() );
3321 $update = $dbw->newUpdateQueryBuilder()
3322 ->update( 'page' )
3323 ->set( [ 'page_touched' => $dbTimestamp ] )
3324 ->where( $conds )
3325 ->andWhere( $dbw->expr( 'page_touched', '<', $dbTimestamp ) );
3326
3327 if ( mt_rand( 1, 10 ) === 1 ) {
3328 $update->andSet( [ 'page_random' => wfRandom() ] );
3329 }
3330
3331 $update->caller( $fname )->execute();
3332
3333 MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
3334 }
3335 ),
3336 DeferredUpdates::PRESEND
3337 );
3338
3339 return true;
3340 }
3341
3347 public function touchLinks() {
3348 $jobs = [];
3349 $jobs[] = HTMLCacheUpdateJob::newForBacklinks(
3350 $this,
3351 'pagelinks',
3352 [ 'causeAction' => 'page-touch' ]
3353 );
3354 $jobs[] = HTMLCacheUpdateJob::newForBacklinks(
3355 $this,
3356 'existencelinks',
3357 [ 'causeAction' => 'existence-touch' ]
3358 );
3359 if ( $this->mNamespace === NS_CATEGORY ) {
3360 $jobs[] = HTMLCacheUpdateJob::newForBacklinks(
3361 $this,
3362 'categorylinks',
3363 [ 'causeAction' => 'category-touch' ]
3364 );
3365 }
3366
3367 MediaWikiServices::getInstance()->getJobQueueGroup()->lazyPush( $jobs );
3368 }
3369
3376 public function getTouched( int $flags = IDBAccessObject::READ_NORMAL ) {
3377 $touched = $this->getFieldFromPageStore( 'page_touched', $flags );
3378 return $touched ? MWTimestamp::convert( TS::MW, $touched ) : false;
3379 }
3380
3387 public function getNamespaceKey( $prepend = 'nstab-' ) {
3388 // Gets the subject namespace of this title
3389 $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
3390 $subjectNS = $nsInfo->getSubject( $this->mNamespace );
3391 // Prefer canonical namespace name for HTML IDs
3392 $namespaceKey = $nsInfo->getCanonicalName( $subjectNS );
3393 if ( $namespaceKey === false ) {
3394 // Fallback to localised text
3395 $namespaceKey = $this->getSubjectNsText();
3396 }
3397 // Makes namespace key lowercase
3398 $namespaceKey = MediaWikiServices::getInstance()->getContentLanguage()->lc( $namespaceKey );
3399 // Uses main
3400 if ( $namespaceKey == '' ) {
3401 $namespaceKey = 'main';
3402 }
3403 // Changes file to image for backwards compatibility
3404 if ( $namespaceKey == 'file' ) {
3405 $namespaceKey = 'image';
3406 }
3407 return $prepend . $namespaceKey;
3408 }
3409
3416 public function getRedirectsHere( $ns = null ) {
3417 $redirs = [];
3418
3419 $queryBuilder = $this->getDbProvider()->getReplicaDatabase()->newSelectQueryBuilder()
3420 ->select( [ 'page_namespace', 'page_title' ] )
3421 ->from( 'redirect' )
3422 ->join( 'page', null, 'rd_from = page_id' )
3423 ->where( [
3424 'rd_namespace' => $this->mNamespace,
3425 'rd_title' => $this->mDbkeyform,
3426 'rd_interwiki' => $this->isExternal() ? $this->mInterwiki : '',
3427 ] );
3428
3429 if ( $ns !== null ) {
3430 $queryBuilder->andWhere( [ 'page_namespace' => $ns ] );
3431 }
3432
3433 $res = $queryBuilder->caller( __METHOD__ )->fetchResultSet();
3434
3435 foreach ( $res as $row ) {
3436 $redirs[] = self::newFromRow( $row );
3437 }
3438 return $redirs;
3439 }
3440
3446 public function isValidRedirectTarget() {
3448
3449 if ( $this->isSpecialPage() ) {
3450 // invalid redirect targets are stored in a global array, but explicitly disallow Userlogout here
3451 foreach ( [ 'Userlogout', ...$wgInvalidRedirectTargets ] as $target ) {
3452 if ( $this->isSpecial( $target ) ) {
3453 return false;
3454 }
3455 }
3456 return true;
3457 }
3458
3459 // relative section links are not valid redirect targets (T278367)
3460 return $this->getDBkey() !== '' && $this->isValid();
3461 }
3462
3468 public function canUseNoindex() {
3470
3471 $bannedNamespaces = $wgExemptFromUserRobotsControl ??
3472 MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces();
3473
3474 return !in_array( $this->mNamespace, $bannedNamespaces );
3475 }
3476
3487 public function getCategorySortkey( $prefix = '' ) {
3488 $unprefixed = $this->getText();
3489
3490 // Anything that uses this hook should only depend
3491 // on the Title object passed in, and should probably
3492 // tell the users to run updateCollations.php --force
3493 // in order to re-sort existing category relations.
3494 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
3495 ->onGetDefaultSortkey( $this, $unprefixed );
3496 if ( $prefix !== '' ) {
3497 # Separate with a line feed, so the unprefixed part is only used as
3498 # a tiebreaker when two pages have the exact same prefix.
3499 # In UCA, tab is the only character that can sort above LF
3500 # so we strip both of them from the original prefix.
3501 $prefix = strtr( $prefix, "\n\t", ' ' );
3502 return "$prefix\n$unprefixed";
3503 }
3504 return $unprefixed;
3505 }
3506
3516 private function getDbPageLanguageCode( int $flags = 0 ): ?string {
3517 global $wgPageLanguageUseDB;
3518
3519 // check, if the page language could be saved in the database, and if so and
3520 // the value is not requested already, lookup the page language using PageStore
3521 if ( $wgPageLanguageUseDB && $this->mDbPageLanguage === false ) {
3522 $this->mDbPageLanguage = $this->getFieldFromPageStore( 'page_lang', $flags ) ?: null;
3523 }
3524
3525 return $this->mDbPageLanguage ?: null;
3526 }
3527
3535 private function getDbPageLanguage(): ?Language {
3536 $languageCode = $this->getDbPageLanguageCode();
3537 if ( $languageCode === null ) {
3538 return null;
3539 }
3540 $services = MediaWikiServices::getInstance();
3541 if ( !$services->getLanguageNameUtils()->isKnownLanguageTag( $languageCode ) ) {
3542 return null;
3543 }
3544 return $services->getLanguageFactory()->getLanguage( $languageCode );
3545 }
3546
3555 public function getPageLanguage() {
3556 global $wgLanguageCode;
3557 if ( $this->isSpecialPage() ) {
3558 // special pages are in the user language
3559 return RequestContext::getMain()->getLanguage();
3560 }
3561
3562 // Checking if DB language is set
3563 $dbPageLanguage = $this->getDbPageLanguage();
3564 if ( $dbPageLanguage ) {
3565 return $dbPageLanguage;
3566 }
3567
3568 $services = MediaWikiServices::getInstance();
3569 if ( !$this->mPageLanguage || $this->mPageLanguage[1] !== $wgLanguageCode ) {
3570 // Note that this may depend on user settings, so the cache should
3571 // be only per-request.
3572 // NOTE: ContentHandler::getPageLanguage() may need to load the
3573 // content to determine the page language!
3574 // Checking $wgLanguageCode hasn't changed for the benefit of unit
3575 // tests.
3576 $contentHandler = $services->getContentHandlerFactory()
3577 ->getContentHandler( $this->getContentModel() );
3578 $langObj = $contentHandler->getPageLanguage( $this );
3579 $this->mPageLanguage = [ $langObj->getCode(), $wgLanguageCode ];
3580 } else {
3581 $langObj = $services->getLanguageFactory()
3582 ->getLanguage( $this->mPageLanguage[0] );
3583 }
3584
3585 return $langObj;
3586 }
3587
3598 public function getPageViewLanguage() {
3599 wfDeprecated( __METHOD__, '1.42' );
3600 $services = MediaWikiServices::getInstance();
3601
3602 if ( $this->isSpecialPage() ) {
3603 // If the user chooses a variant, the content is actually
3604 // in a language whose code is the variant code.
3605 $userLang = RequestContext::getMain()->getLanguage();
3606 $variant = $this->getLanguageConverter( $userLang )->getPreferredVariant();
3607 if ( $userLang->getCode() !== $variant ) {
3608 return $services->getLanguageFactory()
3609 ->getLanguage( $variant );
3610 }
3611
3612 return $userLang;
3613 }
3614
3615 // Checking if DB language is set
3616 $pageLang = $this->getDbPageLanguage();
3617 if ( $pageLang ) {
3618 $variant = $this->getLanguageConverter( $pageLang )->getPreferredVariant();
3619 if ( $pageLang->getCode() !== $variant ) {
3620 return $services->getLanguageFactory()
3621 ->getLanguage( $variant );
3622 }
3623
3624 return $pageLang;
3625 }
3626
3627 // @note Can't be cached persistently, depends on user settings.
3628 // @note ContentHandler::getPageViewLanguage() may need to load the
3629 // content to determine the page language!
3630 $contentHandler = $services->getContentHandlerFactory()
3631 ->getContentHandler( $this->getContentModel() );
3632 $pageLang = $contentHandler->getPageViewLanguage( $this );
3633 return $pageLang;
3634 }
3635
3646 public function getEditNotices( $oldid = 0 ) {
3647 $notices = [];
3648
3649 $editnotice_base = 'editnotice-' . $this->mNamespace;
3650 // Optional notice for the entire namespace
3651 $messages = [ $editnotice_base => 'namespace' ];
3652
3653 if (
3654 MediaWikiServices::getInstance()->getNamespaceInfo()->
3655 hasSubpages( $this->mNamespace )
3656 ) {
3657 // Optional notice for page itself and any parent page
3658 foreach ( explode( '/', $this->mDbkeyform ) as $part ) {
3659 $editnotice_base .= '-' . $part;
3660 $messages[$editnotice_base] = 'base';
3661 }
3662 } else {
3663 // Even if there are no subpages in namespace, we still don't want "/" in MediaWiki message keys
3664 $messages[$editnotice_base . '-' . strtr( $this->mDbkeyform, '/', '-' )] = 'page';
3665 }
3666
3667 foreach ( $messages as $editnoticeText => $class ) {
3668 // The following messages are used here:
3669 // * editnotice-0
3670 // * editnotice-0-Title
3671 // * editnotice-0-Title-Subpage
3672 // * editnotice-…
3673 $msg = wfMessage( $editnoticeText )->page( $this );
3674 if ( $msg->exists() ) {
3675 $html = $msg->parseAsBlock();
3676 // Edit notices may have complex logic, but output nothing (T91715)
3677 if ( trim( $html ) !== '' ) {
3678 $notices[$editnoticeText] = Html::rawElement(
3679 'div',
3680 [ 'class' => [
3681 'mw-editnotice',
3682 // The following classes are used here:
3683 // * mw-editnotice-namespace
3684 // * mw-editnotice-base
3685 // * mw-editnotice-page
3686 "mw-editnotice-$class",
3687 // The following classes are used here:
3688 // * mw-editnotice-0
3689 // * mw-editnotice-…
3690 Sanitizer::escapeClass( "mw-$editnoticeText" )
3691 ] ],
3692 $html
3693 );
3694 }
3695 }
3696 }
3697
3698 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
3699 ->onTitleGetEditNotices( $this, $oldid, $notices );
3700 return $notices;
3701 }
3702
3708 private function getFieldFromPageStore( $field, $flags ) {
3709 $pageStore = MediaWikiServices::getInstance()->getPageStore();
3710
3711 if ( !in_array( $field, $pageStore->getSelectFields(), true ) ) {
3712 throw new InvalidArgumentException( "Unknown field: $field" );
3713 }
3714
3715 if ( $flags === IDBAccessObject::READ_NORMAL && $this->mArticleID === 0 ) {
3716 // page does not exist
3717 return false;
3718 }
3719
3720 if ( !$this->canExist() ) {
3721 return false;
3722 }
3723
3724 $page = $pageStore->getPageByReference( $this, $flags );
3725
3726 if ( $page instanceof PageStoreRecord ) {
3727 return $page->getField( $field );
3728 } else {
3729 // The page record failed to load, remember the page as non-existing.
3730 // Note that this can happen even if a page ID was known before under some
3731 // rare circumstances, if this method is called with the READ_LATEST bit set
3732 // and the page has been deleted since the ID had initially been determined.
3733 $this->mArticleID = 0;
3734 return false;
3735 }
3736 }
3737
3741 public function __sleep() {
3742 return [
3743 'mNamespace',
3744 'mDbkeyform',
3745 'mFragment',
3746 'mInterwiki',
3747 'mLocalInterwiki',
3748 ];
3749 }
3750
3751 public function __wakeup() {
3752 $this->mArticleID = ( $this->mNamespace >= 0 ) ? -1 : 0;
3753 $this->mUrlform = wfUrlencode( $this->mDbkeyform );
3754 $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
3755 }
3756
3757 public function __clone() {
3758 $this->mInstanceCacheKey = null;
3759 }
3760
3770 public function getWikiId() {
3771 return self::LOCAL;
3772 }
3773
3790 public function getId( $wikiId = self::LOCAL ): int {
3791 $this->assertWiki( $wikiId );
3792 $this->assertProperPage();
3793 return $this->getArticleID();
3794 }
3795
3808 private function assertProperPage() {
3809 Assert::precondition(
3810 $this->canExist(),
3811 'This Title instance does not represent a proper page, but merely a link target.'
3812 );
3813 }
3814
3828 // TODO: replace individual member fields with a PageIdentityValue that is always present
3829
3830 $this->assertProperPage();
3831
3832 return new PageIdentityValue(
3833 $this->getId(),
3834 $this->getNamespace(),
3835 $this->getDBkey(),
3836 $this->getWikiId()
3837 );
3838 }
3839
3854 public function toPageRecord( $flags = 0 ): ExistingPageRecord {
3855 // TODO: Cache this? Construct is more efficiently?
3856
3857 $this->assertProperPage();
3858
3859 Assert::precondition(
3860 $this->exists( $flags ),
3861 'This Title instance does not represent an existing page: ' . $this
3862 );
3863
3864 return new PageStoreRecord(
3865 (object)[
3866 'page_id' => $this->getArticleID( $flags ),
3867 'page_namespace' => $this->getNamespace(),
3868 'page_title' => $this->getDBkey(),
3869 'page_wiki_id' => $this->getWikiId(),
3870 'page_latest' => $this->getLatestRevID( $flags ),
3871 'page_is_new' => $this->isNewPage( $flags ),
3872 'page_is_redirect' => $this->isRedirect( $flags ),
3873 'page_touched' => $this->getTouched( $flags ),
3874 'page_lang' => $this->getDbPageLanguageCode( $flags ),
3875 ],
3876 PageIdentity::LOCAL
3877 );
3878 }
3879
3887 public function toPageReference(): PageReference {
3888 $this->assertProperPage();
3889 return new PageReferenceValue(
3890 $this->getNamespace(),
3891 $this->getDBkey(),
3892 PageReferenceValue::LOCAL
3893 );
3894 }
3895
3896}
const PROTO_CANONICAL
Definition Defines.php:223
const CONTENT_MODEL_VUE
Definition Defines.php:241
const NS_USER
Definition Defines.php:53
const CONTENT_MODEL_CSS
Definition Defines.php:237
const NS_FILE
Definition Defines.php:57
const PROTO_CURRENT
Definition Defines.php:222
const NS_MAIN
Definition Defines.php:51
const NS_MEDIAWIKI
Definition Defines.php:59
const NS_SPECIAL
Definition Defines.php:40
const CONTENT_MODEL_WIKITEXT
Definition Defines.php:235
const CONTENT_MODEL_JSON
Definition Defines.php:239
const PROTO_HTTP
Definition Defines.php:217
const NS_MEDIA
Definition Defines.php:39
const PROTO_RELATIVE
Definition Defines.php:219
const NS_CATEGORY
Definition Defines.php:65
const CONTENT_MODEL_JAVASCRIPT
Definition Defines.php:236
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfRandom()
Get a random decimal value in the domain of [0, 1), in a way not likely to give duplicate values for ...
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
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:68
Group all the pieces relevant to the context of a request into one instance.
Deferrable Update for closure/callback updates that should use auto-commit mode.
Defer callable updates to run later in the PHP process.
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
Job to purge the HTML/file cache for all pages that link to or use another page or file.
Base class for language-specific code.
Definition Language.php:70
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
inLanguage( $lang)
Request the message in any language that is supported.
Definition Message.php:890
Immutable value object representing a page identity.
Immutable value object representing a page reference.
Immutable data record representing an editable page on a wiki.
Base representation for an editable wiki page.
Definition WikiPage.php:82
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:32
MediaWiki\Request\PathRouter class.
Parent class for all special pages.
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Represents the target of a wiki link.
Represents a title within MediaWiki.
Definition Title.php:69
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
Definition Title.php:1881
getTalkPage()
Get a Title object associated with the talk page of this article.
Definition Title.php:1615
getSubpageUrlForm()
Get a URL-encoded form of the subpage text.
Definition Title.php:2124
toPageRecord( $flags=0)
Returns the page represented by this Title as a ProperPageRecord.
Definition Title.php:3854
getOtherPage()
Get the other title for this page, if this is a subject page get the talk page, if it is a subject pa...
Definition Title.php:1717
isKnown()
Does this title refer to a page that can (or might) be meaningfully viewed? In particular,...
Definition Title.php:3195
canExist()
Can this title represent a page in the wiki's database?
Definition Title.php:1205
toPageReference()
Returns the page represented by this Title as a PageReferenceValue.
Definition Title.php:3887
getPrefixedURL()
Get a URL-encoded title (not an actual URL) including interwiki.
Definition Title.php:2135
isSubpage()
Is this a subpage?
Definition Title.php:1389
static convertByteClassToUnicodeClass( $byteClass)
Utility method for converting a character sequence from bytes to Unicode.
Definition Title.php:723
isMovable()
Would anybody with sufficient privileges be able to move this page? Some pages just aren't movable.
Definition Title.php:1357
getFragment()
Get the Title fragment (i.e.
Definition Title.php:1744
isLocal()
Determine whether the object refers to a page within this project (either this wiki or a wiki with a ...
Definition Title.php:921
getLocalURL( $query='')
Get a URL with no fragment or server name (relative URL) from a Title object.
Definition Title.php:2215
getEditNotices( $oldid=0)
Get a list of rendered edit notices for this page.
Definition Title.php:3646
canHaveTalkPage()
Can this title have a corresponding talk page?
Definition Title.php:1191
isSamePageAs(PageReference $other)
Checks whether the given PageReference refers to the same page as this PageReference....
Definition Title.php:3100
getDefaultMessageText()
Get the default (plain) message contents for a page that overrides an interface message key.
Definition Title.php:3263
static capitalize( $text, $ns=NS_MAIN)
Capitalize a text string for a title if it belongs to a namespace that capitalizes.
Definition Title.php:2685
static newFromTextThrow( $text, $defaultNamespace=NS_MAIN)
Like Title::newFromText(), but throws MalformedTitleException when the title is invalid,...
Definition Title.php:423
canUseNoindex()
Whether the magic words INDEX and NOINDEX function for this page.
Definition Title.php:3468
getPageLanguage()
Get the language in which the content of this page is written in wikitext.
Definition Title.php:3555
const NEW_CLONE
Flag for use with factory methods like newFromLinkTarget() that have a $forceClone parameter.
Definition Title.php:96
getLatestRevID( $flags=0)
What is the page_latest field for this page?
Definition Title.php:2619
getDeletedEditsCount()
Is there a version of this page in the deletion archive?
Definition Title.php:2494
isTrans()
Determine whether the object refers to a page within this project and is transcludable.
Definition Title.php:957
getNamespaceKey( $prepend='nstab-')
Generate strings used for xml 'id' names in monobook tabs.
Definition Title.php:3387
inNamespaces(... $namespaces)
Returns true if the title is inside one of the specified namespaces.
Definition Title.php:1307
isUserJsConfigPage()
Is this a JS "config" subpage of a user page?
Definition Title.php:1509
getSubjectNsText()
Get the namespace text of the subject (rather than talk) page.
Definition Title.php:1163
isRawHtmlMessage()
Is this a message which can contain raw HTML?
Definition Title.php:1584
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition Title.php:522
getSubpageText()
Get the lowest-level subpage name, i.e.
Definition Title.php:2060
getEditURL()
Get the edit URL for this Title.
Definition Title.php:2378
getSkinFromConfigSubpage()
Trim down a .css, .json, or .js subpage title to get the corresponding skin name.
Definition Title.php:1460
static purgeExpiredRestrictions()
Purge expired restrictions from the page_restrictions table.
Definition Title.php:2392
touchLinks()
Update page_touched timestamps and send CDN purge messages for pages linking to this title.
Definition Title.php:3347
getFullUrlForRedirect( $query='', $proto=PROTO_CURRENT)
Get a url appropriate for making redirects based on an untrusted url arg.
Definition Title.php:2187
setContentModel( $model)
Set a proposed content model for the page for permissions checking.
Definition Title.php:1107
static newFromRow( $row)
Make a Title object from a DB row.
Definition Title.php:549
getNsText()
Get the namespace text.
Definition Title.php:1133
isSiteJsonConfigPage()
Is this a sitewide JSON "config" page?
Definition Title.php:1543
isSiteConfigPage()
Could this MediaWiki namespace page contain custom CSS, JSON, or JavaScript for the global UI.
Definition Title.php:1432
isValid()
Returns true if the title is a valid link target, and that it has been properly normalized.
Definition Title.php:881
isValidRedirectTarget()
Check if this Title is a valid redirect target.
Definition Title.php:3446
createFragmentTarget(string $fragment)
Creates a new Title for a different fragment of the same page.
Definition Title.php:1790
setFragment( $fragment)
Set the fragment for this title.
Definition Title.php:1778
getSubpages( $limit=-1)
Get all subpages of this page.
Definition Title.php:2456
isNewPage( $flags=IDBAccessObject::READ_NORMAL)
Check if this is a new page.
Definition Title.php:3016
isRedirect( $flags=0)
Is this an article that is a redirect page? Uses link cache, adding it if necessary.
Definition Title.php:2586
int $mLength
The page length, 0 for special pages.
Definition Title.php:166
static newFromLinkTarget(ParsoidLinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition Title.php:279
isSiteJsConfigPage()
Is this a sitewide JS "config" page?
Definition Title.php:1561
getCanonicalURL( $query='')
Get the URL for a canonical link, for use in things like IRC and e-mail notifications.
Definition Title.php:2359
int false $mLatestID
ID of most recent revision.
Definition Title.php:131
isSingleRevRedirect()
Locks the page row and check if this page is single revision redirect.
Definition Title.php:2901
isDeletedQuick()
Is there a version of this page in the deletion archive?
Definition Title.php:2521
getTalkPageIfDefined()
Get a Title object associated with the talk page of this article, if such a talk page can exist.
Definition Title.php:1645
static newMainPage(?MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition Title.php:676
static makeName( $ns, $title, $fragment='', $interwiki='', $canonicalNamespace=false)
Make a prefixed DB key from a DB key and a namespace index.
Definition Title.php:829
inNamespace(int $ns)
Returns true if the title is inside the specified namespace.
Definition Title.php:1295
isConversionTable()
Is this a conversion table for the LanguageConverter?
Definition Title.php:1401
isUserCssConfigPage()
Is this a CSS "config" subpage of a user page?
Definition Title.php:1481
hasSubjectNamespace( $ns)
Returns true if the title has the same subject namespace as the namespace specified.
Definition Title.php:1334
static compare( $a, $b)
Callback for usort() to do title sorts by (namespace, title)
Definition Title.php:860
exists( $flags=0)
Check if page exists.
Definition Title.php:3129
getSubpage( $text)
Get the title for a subpage of the current page.
Definition Title.php:2087
static newFromPageIdentity(PageIdentity $pageIdentity)
Return a Title for a given PageIdentity.
Definition Title.php:318
equals(object $other)
Compares with another Title.
Definition Title.php:3086
hasSourceText()
Does this page have source text?
Definition Title.php:3204
pageCond()
Get an associative array for selecting this title from the "page" table.
Definition Title.php:2999
getLinksTo( $options=[], $table='pagelinks', $prefix='pl')
Get an array of Title objects linking to this Title Also stores the IDs in the link cache.
Definition Title.php:2751
isBigDeletion()
Check whether the number of revisions of this page surpasses $wgDeleteRevisionsLimit.
Definition Title.php:3027
getBaseTitle()
Get the base page name title, i.e.
Definition Title.php:2029
estimateRevisionCount()
Get the approximate revision count of this page.
Definition Title.php:3054
isUserConfigPage()
Is this a "config" (.css, .json, or .js) subpage of a user page?
Definition Title.php:1446
resetArticleID( $id)
Inject a page ID, reset DB-loaded fields, and clear the link cache for this title.
Definition Title.php:2644
getTouched(int $flags=IDBAccessObject::READ_NORMAL)
Get the last touched timestamp.
Definition Title.php:3376
isTalkPage()
Is this a talk page of some sort?
Definition Title.php:1599
hasDeletedEdits()
Is there a version of this page in the deletion archive?
Definition Title.php:2531
static castFromPageReference(?PageReference $pageReference)
Same as newFromPageReference(), but if passed null, returns null.
Definition Title.php:362
getId( $wikiId=self::LOCAL)
Returns the page ID.
Definition Title.php:3790
getFullURL( $query='', $query2=false, $proto=PROTO_RELATIVE)
Get a real URL referring to this title, with interwiki link and fragment.
Definition Title.php:2152
null bool $mRedirect
Is the article at this title a redirect?
Definition Title.php:169
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition Title.php:2558
getPageViewLanguage()
Get the language in which the content of this page is written when viewed by user.
Definition Title.php:3598
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition Title.php:388
getFragmentForURL()
Get the fragment in URL form, including the "#" character if there is one.
Definition Title.php:1753
getNamespace()
Get the namespace index, i.e.
Definition Title.php:1037
static newFromURL( $url)
THIS IS NOT THE FUNCTION YOU WANT.
Definition Title.php:485
getInterwiki()
Get the interwiki prefix.
Definition Title.php:938
getTemplateLinksTo( $options=[])
Get an array of Title objects using this Title as a template Also stores the IDs in the link cache.
Definition Title.php:2809
getLinksFrom( $options=[], $table='pagelinks', $prefix='pl')
Get an array of Title objects linked from this Title Also stores the IDs in the link cache.
Definition Title.php:2825
hasContentModel( $id)
Convenience method for checking a title's content model name.
Definition Title.php:1087
getSubjectPage()
Get a title object associated with the subject page of this talk page.
Definition Title.php:1660
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition Title.php:640
getDefaultSystemMessage()
Same as getDefaultMessageText, but returns a Message object.
Definition Title.php:3276
getFullSubpageText()
Get the entire subpage string of a title.
Definition Title.php:2108
getPartialURL()
Get the URL-encoded form of the main part.
Definition Title.php:1019
getWikiId()
Returns false to indicate that this Title belongs to the local wiki.
Definition Title.php:3770
getLength( $flags=0)
What is the length of this page? Uses link cache, adding it if necessary.
Definition Title.php:2601
getDBkey()
Get the main part with underscores.
Definition Title.php:1028
getContentModel( $flags=0)
Get the page's content model id, see the CONTENT_MODEL_XXX constants.
Definition Title.php:1059
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition Title.php:614
static castFromPageIdentity(?PageIdentity $pageIdentity)
Same as newFromPageIdentity(), but if passed null, returns null.
Definition Title.php:329
static castFromLinkTarget(?ParsoidLinkTarget $linkTarget)
Same as newFromLinkTarget(), but if passed null, returns null.
Definition Title.php:303
getTitleValue()
Get a TitleValue object representing this Title.
Definition Title.php:987
int $mArticleID
Article ID, fetched from the link cache on demand.
Definition Title.php:128
isSubpageOf(Title $title)
Check if this title is a subpage of another title.
Definition Title.php:3113
isSpecialPage()
Returns true if this is a special page.
Definition Title.php:1246
getText()
Get the text form (spaces not underscores) of the main part.
Definition Title.php:1010
isMainPage()
Is this the mainpage?
Definition Title.php:1379
isAlwaysKnown()
Should links to this title be shown as potentially viewable (i.e.
Definition Title.php:3151
toPageIdentity()
Returns the page represented by this Title as a ProperPageIdentity.
Definition Title.php:3827
getParentCategories()
Get categories to which this Title belongs and return an array of categories' names.
Definition Title.php:2937
string null $prefixedText
Text form including namespace/interwiki, initialised on demand.
Definition Title.php:156
static newFromDBkey( $key)
Create a new Title from a prefixed DB key.
Definition Title.php:257
isSpecial( $name)
Returns true if this title resolves to the named special page.
Definition Title.php:1256
getPrefixedDBkey()
Get the prefixed database key form.
Definition Title.php:1845
getRootText()
Get the root page name text without a namespace, i.e.
Definition Title.php:1941
isWikitextPage()
Does that page contain wikitext, or it is JS, CSS or whatever?
Definition Title.php:1414
fixSpecialName()
If the Title refers to a special page alias which is not the local default, resolve the alias,...
Definition Title.php:1274
getTransWikiID()
Returns the DB name of the distant wiki which owns the object.
Definition Title.php:970
getTemplateLinksFrom( $options=[])
Get an array of Title objects used on this Title as a template Also stores the IDs in the link cache.
Definition Title.php:2890
invalidateCache( $purgeTime=null)
Updates page_touched for this page; called from LinksUpdate.php.
Definition Title.php:3298
getTalkNsText()
Get the namespace text of the talk page.
Definition Title.php:1174
hasSubpages()
Does this have subpages? (Warning, usually requires an extra DB query.)
Definition Title.php:2428
getRedirectsHere( $ns=null)
Get all extant redirects to this Title.
Definition Title.php:3416
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1857
wasLocalInterwiki()
Was this a local interwiki link?
Definition Title.php:947
getLinkURL( $query='', $query2=false, $proto=false)
Get a URL that's the simplest URL that will be valid to link, locally, to the current Title.
Definition Title.php:2310
getCategorySortkey( $prefix='')
Returns the raw sort key to be used for categories, with the specified prefix.
Definition Title.php:3487
getInternalURL( $query='')
Get the URL form for an internal link.
Definition Title.php:2334
static newFromPageReference(PageReference $pageReference)
Return a Title for a given Reference.
Definition Title.php:341
isContentPage()
Is this Title in a namespace which contains content? In other words, is this a content page,...
Definition Title.php:1346
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition Title.php:709
getParentCategoryTree( $children=[])
Get a tree of parent categories.
Definition Title.php:2972
getRootTitle()
Get the root page name title, i.e.
Definition Title.php:1968
isSiteCssConfigPage()
Is this a sitewide CSS "config" page?
Definition Title.php:1525
isDeleted()
Is there a version of this page in the deletion archive?
Definition Title.php:2484
isUserJsonConfigPage()
Is this a JSON "config" subpage of a user page?
Definition Title.php:1495
__toString()
Return a string representation of this title.
Definition Title.php:1871
getBaseText()
Get the base page name without a namespace, i.e.
Definition Title.php:2002
loadFromRow( $row)
Load Title object fields from a DB row.
Definition Title.php:561
Library for creating and parsing MW-style timestamps.
Store key-value entries in a size-limited in-memory LRU cache.
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'=> false, '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, 'EnableSpecialMute'=> false, 'EnableUserEmailMuteList'=> false, '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'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> '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'=> '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' => [ ], '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, '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', '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', '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.', ],]
$wgExemptFromUserRobotsControl
Config variable stub for the ExemptFromUserRobotsControl setting, for use by phpdoc and IDEs.
$wgLegalTitleChars
Config variable stub for the LegalTitleChars setting, for use by phpdoc and IDEs.
$wgLanguageCode
Config variable stub for the LanguageCode setting, for use by phpdoc and IDEs.
$wgPageLanguageUseDB
Config variable stub for the PageLanguageUseDB setting, for use by phpdoc and IDEs.
$wgScript
Config variable stub for the Script setting, for use by phpdoc and IDEs.
$wgInternalServer
Config variable stub for the InternalServer setting, for use by phpdoc and IDEs.
$wgActionPaths
Config variable stub for the ActionPaths setting, for use by phpdoc and IDEs.
$wgMainPageIsDomainRoot
Config variable stub for the MainPageIsDomainRoot setting, for use by phpdoc and IDEs.
$wgInvalidRedirectTargets
Config variable stub for the InvalidRedirectTargets setting, for use by phpdoc and IDEs.
$wgArticlePath
Config variable stub for the ArticlePath setting, for use by phpdoc and IDEs.
$wgDeleteRevisionsLimit
Config variable stub for the DeleteRevisionsLimit setting, for use by phpdoc and IDEs.
$wgVariantArticlePath
Config variable stub for the VariantArticlePath setting, for use by phpdoc and IDEs.
$wgRawHtmlMessages
Config variable stub for the RawHtmlMessages setting, for use by phpdoc and IDEs.
$wgServer
Config variable stub for the Server setting, for use by phpdoc and IDEs.
assertWiki( $wikiId)
Throws if $wikiId is different from the return value of getWikiId().
Service interface for looking up Interwiki records.
The shared interface for all language converters.
Represents the target of a wiki link.
Data record representing a page that currently exists as an editable page on a wiki.
Interface for objects (potentially) representing an editable wiki page.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Interface for a page that is (or could be, or used to be) an editable wiki page.
Interface for localizing messages in MediaWiki.
Provide primary and replica IDatabase connections.
Interface for database access objects.
Interface to a relational database.
Definition IDatabase.php:31
newUpdateQueryBuilder()
Get an UpdateQueryBuilder bound to this connection.
newDeleteQueryBuilder()
Get an DeleteQueryBuilder bound to this connection.
newSelectQueryBuilder()
Create an empty SelectQueryBuilder which can be used to run queries against this connection.
expr(string $field, string $op, $value)
See Expression::__construct()
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
__construct(array $options, callable $shouldModifyCallback, callable $modifyCallback)