MediaWiki master
MessageCache.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Language;
8
9use Exception;
10use InvalidArgumentException;
11use LogicException;
12use MapCacheLRU;
18use MediaWiki\Languages\LanguageConverterFactory;
19use MediaWiki\Languages\LanguageFallback;
20use MediaWiki\Languages\LanguageNameUtils;
32use Psr\Log\LoggerAwareInterface;
33use Psr\Log\LoggerInterface;
34use RuntimeException;
35use Throwable;
44use Wikimedia\RequestTimeout\TimeoutException;
45use Wikimedia\ScopedCallback;
46use Wikimedia\Timestamp\TimestampFormat as TS;
47
53class MessageCache implements LoggerAwareInterface {
57 public const CONSTRUCTOR_OPTIONS = [
63 ];
64
68 private const CACHE_VERSION = 2;
69
74 public const MAX_REQUEST_LANGUAGES = 10;
75
77 private const FOR_UPDATE = 1;
78
80 private const LOCK_WAIT_TIME = 15;
82 private const LOCK_TTL = 30;
83
87 private const WAN_TTL = BagOStuff::TTL_DAY;
88
90 private $logger;
91
97 private $cache;
98
104 private $systemMessageNames;
105
111 private $isCacheVolatile = [];
112
118 private $disabled;
119
121 private $maxEntrySize;
123 private $adaptive;
125 private $useXssLanguage;
127 private $rawHtmlMessages;
128
130 private $wanCache;
132 private $mainCache;
134 private $srvCache;
136 private $contLang;
138 private $contLangCode;
140 private $contLangConverter;
142 private $localisationCache;
144 private $languageNameUtils;
146 private $languageFallback;
148 private $hookRunner;
150 private $messageParser;
151
153 private $messageKeyOverrides;
154
170 public function __construct(
171 WANObjectCache $wanCache,
172 BagOStuff $mainCache,
173 BagOStuff $serverCache,
174 Language $contLang,
175 LanguageConverterFactory $langConverterFactory,
176 LoggerInterface $logger,
177 ServiceOptions $options,
178 LocalisationCache $localisationCache,
179 LanguageNameUtils $languageNameUtils,
180 LanguageFallback $languageFallback,
181 HookContainer $hookContainer,
182 MessageParser $messageParser
183 ) {
184 $this->wanCache = $wanCache;
185 $this->mainCache = $mainCache;
186 $this->srvCache = $serverCache;
187 $this->contLang = $contLang;
188 $this->contLangConverter = $langConverterFactory->getLanguageConverter( $contLang );
189 $this->contLangCode = $contLang->getCode();
190 $this->logger = $logger;
191 $this->localisationCache = $localisationCache;
192 $this->languageNameUtils = $languageNameUtils;
193 $this->languageFallback = $languageFallback;
194 $this->hookRunner = new HookRunner( $hookContainer );
195 $this->messageParser = $messageParser;
196
197 $this->cache = new MapCacheLRU( self::MAX_REQUEST_LANGUAGES );
198
199 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
200 if ( !$options->get( MainConfigNames::UseDatabaseMessages ) ) {
201 $this->disable( 'config' );
202 }
203 $this->maxEntrySize = $options->get( MainConfigNames::MaxMsgCacheEntrySize );
204 $this->adaptive = $options->get( MainConfigNames::AdaptiveMessageCache );
205 $this->useXssLanguage = $options->get( MainConfigNames::UseXssLanguage );
206 $this->rawHtmlMessages = $options->get( MainConfigNames::RawHtmlMessages );
207 }
208
209 public function setLogger( LoggerInterface $logger ): void {
210 $this->logger = $logger;
211 }
212
219 private function getLocalCache( $code ) {
220 $cacheKey = $this->srvCache->makeKey( __CLASS__, $code );
221
222 return $this->srvCache->get( $cacheKey );
223 }
224
231 private function saveToLocalCache( $code, $cache ) {
232 $cacheKey = $this->srvCache->makeKey( __CLASS__, $code );
233 $this->srvCache->set( $cacheKey, $cache );
234 }
235
256 private function load( string $code, $mode = null ) {
257 // Check if loading is done already
258 if ( $this->disabled ||
259 ( $mode !== self::FOR_UPDATE && $this->isLanguageLoaded( $code ) )
260 ) {
261 return true;
262 }
263
264 try {
265 return $this->loadUnguarded( $code, $mode );
266 } catch ( Throwable $e ) {
267 // Don't try to load again during the exception handler
268 $this->disable();
269 throw $e;
270 }
271 }
272
280 private function loadUnguarded( $code, $mode ) {
281 $success = false; // Keep track of success
282 $staleCache = false; // a cache array with expired data, or false if none has been loaded
283 $where = []; // Debug info, delayed to avoid spamming debug log too much
284
285 // A hash of the expected content is stored in a WAN cache key, providing a way
286 // to invalidate the local cache on every server whenever a message page changes.
287 [ $hash, $isCacheVolatile ] = $this->getValidationHash( $code );
288 $this->isCacheVolatile[$code] = $isCacheVolatile;
289 $isStaleDueToVolatility = false;
290
291 // Try the local cache and check against the main cache hash key...
292 $cache = $this->getLocalCache( $code );
293 if ( !$cache ) {
294 $where[] = 'local cache is empty';
295 } elseif ( !isset( $cache['HASH'] ) || $cache['HASH'] !== $hash ) {
296 $where[] = 'local cache has the wrong hash';
297 $staleCache = $cache;
298 } elseif ( $this->isCacheExpired( $cache ) ) {
299 $where[] = 'local cache is expired';
300 $staleCache = $cache;
301 } elseif ( $isCacheVolatile ) {
302 // Some recent message page changes might not show due to DB lag
303 $where[] = 'local cache validation key is expired/volatile';
304 $staleCache = $cache;
305 $isStaleDueToVolatility = true;
306 } else {
307 $where[] = 'got from local cache';
308 $this->cache->set( $code, $cache );
309 $success = true;
310 }
311
312 if ( !$success ) {
313 // Try the main cache, using a lock for regeneration...
314 $cacheKey = $this->mainCache->makeKey( 'messages', $code );
315 for ( $failedAttempts = 0; $failedAttempts <= 1; $failedAttempts++ ) {
316 if ( $isStaleDueToVolatility ) {
317 // While the main cache *might* be more up-to-date, we do not want
318 // the I/O strain of every application server fetching the key here during
319 // the volatility period. Either this thread wins the lock and regenerates
320 // the cache or the stale local cache value gets reused.
321 $where[] = 'global cache is presumed expired';
322 } else {
323 $cache = $this->mainCache->get( $cacheKey );
324 if ( !$cache ) {
325 $where[] = 'global cache is empty';
326 } elseif ( $this->isCacheExpired( $cache ) ) {
327 $where[] = 'global cache is expired';
328 $staleCache = $cache;
329 } elseif ( $isCacheVolatile ) {
330 // Some recent message page changes might not show due to DB lag
331 $where[] = 'global cache is expired/volatile';
332 $staleCache = $cache;
333 } else {
334 $where[] = 'got from global cache';
335 $this->cache->set( $code, $cache );
336 $this->saveToCaches( $cache, 'local-only', $code );
337 $success = true;
338 break;
339 }
340 }
341
342 // We need to call loadFromDB(). Limit the concurrency to one thread.
343 // This prevents the site from going down when the cache expires.
344 // Note that the DB slam protection lock here is non-blocking.
345 $loadStatus = $this->loadFromDBWithMainLock( $code, $where, $mode );
346 if ( $loadStatus === true ) {
347 $success = true;
348 break;
349 } elseif ( $staleCache ) {
350 // Use the stale cache while some other thread constructs the new one
351 $where[] = 'using stale cache';
352 $this->cache->set( $code, $staleCache );
353 $success = true;
354 break;
355 } elseif ( $failedAttempts > 0 ) {
356 $where[] = 'failed to find cache after waiting';
357 // Already blocked once, so avoid another lock/unlock cycle.
358 // This case will typically be hit if memcached is down, or if
359 // loadFromDB() takes longer than LOCK_WAIT.
360 break;
361 } elseif ( $loadStatus === 'cant-acquire' ) {
362 // Wait for the other thread to finish, then retry. Normally,
363 // the memcached get() will then yield the other thread's result.
364 $where[] = 'waiting for other thread to complete';
365 [ , $ioError ] = $this->getReentrantScopedLock( $code );
366 if ( $ioError ) {
367 $where[] = 'failed waiting';
368 // Call loadFromDB() with concurrency limited to one thread per server.
369 // It should be rare for all servers to lack even a stale local cache.
370 $success = $this->loadFromDBWithLocalLock( $code, $where, $mode );
371 break;
372 }
373 } else {
374 // Disable cache; $loadStatus is 'disabled'
375 break;
376 }
377 }
378 }
379
380 if ( !$success ) {
381 $where[] = 'loading FAILED - cache is disabled';
382 $this->disable();
383 $this->cache->set( $code, [] );
384 $this->logger->error( __METHOD__ . ": Failed to load $code" );
385 // This used to throw an exception, but that led to nasty side effects like
386 // the whole wiki being instantly down if the memcached server died
387 }
388
389 if ( !$this->isLanguageLoaded( $code ) ) {
390 throw new LogicException( "Process cache for '$code' should be set by now." );
391 }
392
393 $info = implode( ', ', $where );
394 $this->logger->debug( __METHOD__ . ": Loading $code... $info" );
395
396 return $success;
397 }
398
405 private function loadFromDBWithMainLock( $code, array &$where, $mode = null ) {
406 // If cache updates on all levels fail, give up on message overrides.
407 // This is to avoid easy site outages; see $saveSuccess comments below.
408 $statusKey = $this->mainCache->makeKey( 'messages', $code, 'status' );
409 $status = $this->mainCache->get( $statusKey );
410 if ( $status === 'error' ) {
411 $where[] = "could not load; method is still globally disabled";
412 return 'disabled';
413 }
414
415 // Now let's regenerate
416 $where[] = 'loading from DB';
417
418 // Lock the cache to prevent conflicting writes.
419 // This lock is non-blocking so stale cache can quickly be used.
420 // Note that load() will call a blocking getReentrantScopedLock()
421 // after this if it really needs to wait for any current thread.
422 [ $scopedLock ] = $this->getReentrantScopedLock( $code, 0 );
423 if ( !$scopedLock ) {
424 $where[] = 'could not acquire main lock';
425 return 'cant-acquire';
426 }
427
428 $cache = $this->loadFromDB( $code, $mode );
429 $this->cache->set( $code, $cache );
430 $saveSuccess = $this->saveToCaches( $cache, 'all', $code );
431
432 if ( !$saveSuccess ) {
442 if ( $this->srvCache instanceof EmptyBagOStuff ) {
443 $this->mainCache->set( $statusKey, 'error', 60 * 5 );
444 $where[] = 'could not save cache, disabled globally for 5 minutes';
445 } else {
446 $where[] = "could not save global cache";
447 }
448 }
449
450 return true;
451 }
452
459 private function loadFromDBWithLocalLock( $code, array &$where, $mode = null ) {
460 $success = false;
461 $where[] = 'loading from DB using local lock';
462
463 $scopedLock = $this->srvCache->getScopedLock(
464 $this->srvCache->makeKey( 'messages', $code ),
465 self::LOCK_WAIT_TIME,
466 self::LOCK_TTL,
467 __METHOD__
468 );
469 if ( $scopedLock ) {
470 $cache = $this->loadFromDB( $code, $mode );
471 $this->cache->set( $code, $cache );
472 $this->saveToCaches( $cache, 'local-only', $code );
473 $success = true;
474 }
475
476 return $success;
477 }
478
488 private function loadFromDB( $code, $mode = null ) {
489 $icp = MediaWikiServices::getInstance()->getConnectionProvider();
490
491 $dbr = ( $mode === self::FOR_UPDATE ) ? $icp->getPrimaryDatabase() : $icp->getReplicaDatabase();
492
493 $cache = [];
494
495 $mostUsed = []; // list of "<cased message key>/<code>"
496 if ( $this->adaptive && $code !== $this->contLangCode ) {
497 if ( !$this->cache->has( $this->contLangCode ) ) {
498 $this->load( $this->contLangCode );
499 }
500 $mostUsed = array_keys( $this->cache->get( $this->contLangCode ) );
501 foreach ( $mostUsed as $key => $value ) {
502 $mostUsed[$key] = "$value/$code";
503 }
504 }
505
506 // Common conditions
507 $conds = [
508 // Treat redirects as not existing (T376398)
509 'page_is_redirect' => 0,
510 'page_namespace' => NS_MEDIAWIKI,
511 ];
512 if ( count( $mostUsed ) ) {
513 $conds['page_title'] = $mostUsed;
514 } elseif ( $code !== $this->contLangCode ) {
515 $conds[] = $dbr->expr(
516 'page_title',
517 IExpression::LIKE,
518 new LikeValue( $dbr->anyString(), '/', $code )
519 );
520 } else {
521 // Effectively disallows use of '/' character in NS_MEDIAWIKI for uses
522 // other than language code.
523 $conds[] = $dbr->expr(
524 'page_title',
525 IExpression::NOT_LIKE,
526 new LikeValue( $dbr->anyString(), '/', $dbr->anyString() )
527 );
528 }
529
530 // Set the stubs for oversized software-defined messages in the main cache map
531 $res = $dbr->newSelectQueryBuilder()
532 ->select( [ 'page_title', 'page_latest' ] )
533 ->from( 'page' )
534 ->where( $conds )
535 ->andWhere( $dbr->expr( 'page_len', '>', intval( $this->maxEntrySize ) ) )
536 ->caller( __METHOD__ . "($code)-big" )->fetchResultSet();
537 foreach ( $res as $row ) {
538 // Include entries/stubs for all keys in $mostUsed in adaptive mode
539 if ( $this->adaptive || $this->isMainCacheable( $row->page_title ) ) {
540 $cache[$row->page_title] = '!TOO BIG';
541 }
542 // At least include revision ID so page changes are reflected in the hash
543 $cache['EXCESSIVE'][$row->page_title] = $row->page_latest;
544 }
545
546 // RevisionStore cannot be injected as it would break the installer since
547 // it instantiates MessageCache before the DB.
548 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
549 // Set the text for small software-defined messages in the main cache map
550 $revQuery = $revisionStore->getQueryInfo( [ 'page' ] );
551
552 // T231196: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` then
553 // `revision` then `page` is somehow better than starting with `page`. Tell it not to reorder the
554 // query (and also reorder it ourselves because as generated by RevisionStore it'll have
555 // `revision` first rather than `page`).
556 $revQuery['joins']['revision'] = $revQuery['joins']['page'];
557 unset( $revQuery['joins']['page'] );
558 // It isn't actually necessary to reorder $revQuery['tables'] as Database does the right thing
559 // when join conditions are given for all joins, but Gergő is wary of relying on that so pull
560 // `page` to the start.
561 $revQuery['tables'] = array_merge(
562 [ 'page' ],
563 array_diff( $revQuery['tables'], [ 'page' ] )
564 );
565
566 $res = $dbr->newSelectQueryBuilder()
567 ->queryInfo( $revQuery )
568 ->where( $conds )
569 ->andWhere( [
570 $dbr->expr( 'page_len', '<=', intval( $this->maxEntrySize ) ),
571 'page_latest = rev_id' // get the latest revision only
572 ] )
573 ->caller( __METHOD__ . "($code)-small" )
574 ->straightJoinOption()
575 ->fetchResultSet();
576
577 // Don't load content from uncacheable rows (T313004)
578 [ $cacheableRows, $uncacheableRows ] = $this->separateCacheableRows( $res );
579 $result = $revisionStore->newRevisionsFromBatch( $cacheableRows, [
580 'slots' => [ SlotRecord::MAIN ],
581 'content' => true
582 ] );
583 $revisions = $result->isOK() ? $result->getValue() : [];
584
585 foreach ( $cacheableRows as $row ) {
586 try {
587 $rev = $revisions[$row->rev_id] ?? null;
588 $content = $rev ? $rev->getContent( SlotRecord::MAIN ) : null;
589 $text = $this->getMessageTextFromContent( $content );
590 } catch ( TimeoutException $e ) {
591 throw $e;
592 } catch ( Exception ) {
593 $text = false;
594 }
595
596 if ( !is_string( $text ) ) {
597 $entry = '!ERROR';
598 $this->logger->error(
599 __METHOD__
600 . ": failed to load message page text for {$row->page_title} ($code)"
601 );
602 } else {
603 $entry = ' ' . $text;
604 }
605 $cache[$row->page_title] = $entry;
606 }
607
608 foreach ( $uncacheableRows as $row ) {
609 // T193271: The cache object gets too big and slow to generate.
610 // At least include revision ID, so that page changes are reflected in the hash.
611 $cache['EXCESSIVE'][$row->page_title] = $row->page_latest;
612 }
613
614 $cache['VERSION'] = self::CACHE_VERSION;
615 ksort( $cache );
616
617 // Hash for validating local cache (APC). No need to take into account
618 // messages larger than $wgMaxMsgCacheEntrySize, since those are only
619 // stored and fetched from memcache.
620 $cache['HASH'] = md5( serialize( $cache ) );
621 $cache['EXPIRY'] = wfTimestamp( TS::MW, time() + self::WAN_TTL );
622 unset( $cache['EXCESSIVE'] ); // only needed for hash
623
624 return $cache;
625 }
626
633 private function isLanguageLoaded( $lang ) {
634 // It is important that this only returns true if the cache was fully
635 // populated by load(), so that callers can assume all cache keys exist.
636 // It is possible for $this->cache to be only partially populated through
637 // methods like MessageCache::replace(), which must not make this method
638 // return true (T208897). And this method must cease to return true
639 // if the language was evicted by MapCacheLRU (T230690).
640 return $this->cache->hasField( $lang, 'VERSION' );
641 }
642
654 private function isMainCacheable( $name, $code = null ) {
655 // Convert the first letter to lowercase, and strip /code suffix
656 $name = $this->contLang->lcfirst( $name );
657 // Include common conversion table pages. This also avoids problems with
658 // Installer::parse() bailing out due to disallowed DB queries (T207979).
659 if ( str_starts_with( $name, 'conversiontable/' ) ) {
660 return true;
661 }
662 $msg = preg_replace( '/\/[a-z0-9-]{2,}$/', '', $name );
663
664 if ( $code === null ) {
665 // Bulk load
666 if ( $this->systemMessageNames === null ) {
667 $this->systemMessageNames = array_fill_keys(
668 $this->localisationCache->getSubitemList( $this->contLangCode, 'messages' ),
669 true );
670 }
671 return isset( $this->systemMessageNames[$msg] );
672 } else {
673 // Use individual subitem
674 return $this->localisationCache->getSubitem( $code, 'messages', $msg ) !== null;
675 }
676 }
677
685 private function separateCacheableRows( $res ) {
686 if ( $this->adaptive ) {
687 // Include entries/stubs for all keys in $mostUsed in adaptive mode
688 return [ $res, [] ];
689 }
690 $cacheableRows = [];
691 $uncacheableRows = [];
692 foreach ( $res as $row ) {
693 if ( $this->isMainCacheable( $row->page_title ) ) {
694 $cacheableRows[] = $row;
695 } else {
696 $uncacheableRows[] = $row;
697 }
698 }
699 return [ $cacheableRows, $uncacheableRows ];
700 }
701
708 public function replace( $title, $text ) {
709 if ( $this->disabled ) {
710 return;
711 }
712
713 [ $msg, $code ] = $this->figureMessage( $title );
714 if ( str_contains( $title, '/' ) && $code === $this->contLangCode ) {
715 // Content language overrides do not use the /<code> suffix
716 return;
717 }
718
719 // (a) Update the process cache with the new message text
720 if ( $text === false ) {
721 // Page deleted
722 $this->cache->setField( $code, $title, '!NONEXISTENT' );
723 } else {
724 // Ignore $wgMaxMsgCacheEntrySize so the process cache is up-to-date
725 $this->cache->setField( $code, $title, ' ' . $text );
726 }
727
728 // (b) Update the shared caches in a deferred update with a fresh DB snapshot
729 DeferredUpdates::addUpdate(
730 new MessageCacheUpdate( $code, $title, $msg ),
731 DeferredUpdates::PRESEND
732 );
733 }
734
740 public function refreshAndReplaceInternal( string $code, array $replacements ) {
741 // Allow one caller at a time to avoid race conditions
742 [ $scopedLock ] = $this->getReentrantScopedLock( $code );
743 if ( !$scopedLock ) {
744 foreach ( $replacements as [ $title ] ) {
745 $this->logger->error(
746 __METHOD__ . ': could not acquire lock to update {title} ({code})',
747 [ 'title' => $title, 'code' => $code ] );
748 }
749
750 return;
751 }
752
753 // Load the existing cache to update it in the local DC cache.
754 // The other DCs will see a hash mismatch.
755 if ( $this->load( $code, self::FOR_UPDATE ) ) {
756 $cache = $this->cache->get( $code );
757 } else {
758 // Err? Fall back to loading from the database.
759 $cache = $this->loadFromDB( $code, self::FOR_UPDATE );
760 }
761 // Check if individual cache keys should exist and update cache accordingly
762 $newTextByTitle = []; // map of (title => content)
763 $newBigTitles = []; // map of (title => latest revision ID), like EXCESSIVE in loadFromDB()
764 // Can not inject the WikiPageFactory as it would break the installer since
765 // it instantiates MessageCache before the DB.
766 $wikiPageFactory = MediaWikiServices::getInstance()->getWikiPageFactory();
767 foreach ( $replacements as [ $title ] ) {
768 $page = $wikiPageFactory->newFromTitle( Title::makeTitle( NS_MEDIAWIKI, $title ) );
769 $page->loadPageData( IDBAccessObject::READ_LATEST );
770 $text = $this->getMessageTextFromContent( $page->getContent() );
771 // Remember the text for the blob store update later on
772 $newTextByTitle[$title] = $text ?? '';
773 // Note that if $text is false, then $cache should have a !NONEXISTENT entry
774 if ( !is_string( $text ) ) {
775 $cache[$title] = '!NONEXISTENT';
776 } elseif ( strlen( $text ) > $this->maxEntrySize ) {
777 $cache[$title] = '!TOO BIG';
778 $newBigTitles[$title] = $page->getLatest();
779 } else {
780 $cache[$title] = ' ' . $text;
781 }
782 }
783 // Update HASH for the new key. Incorporates various administrative keys,
784 // including the old HASH (and thereby the EXCESSIVE value from loadFromDB()
785 // and previous replace() calls), but that doesn't really matter since we
786 // only ever compare it for equality with a copy saved by saveToCaches().
787 $cache['HASH'] = md5( serialize( $cache + [ 'EXCESSIVE' => $newBigTitles ] ) );
788 // Update the too-big WAN cache entries now that we have the new HASH
789 foreach ( $newBigTitles as $title => $id ) {
790 // Match logic of loadCachedMessagePageEntry()
791 $this->wanCache->set(
792 $this->bigMessageCacheKey( $cache['HASH'], $title ),
793 ' ' . $newTextByTitle[$title],
794 self::WAN_TTL
795 );
796 }
797 // Mark this cache as definitely being "latest" (non-volatile) so
798 // load() calls do not try to refresh the cache with replica DB data
799 $cache['LATEST'] = time();
800 // Update the process cache
801 $this->cache->set( $code, $cache );
802 // Pre-emptively update the local datacenter cache so things like edit filter and
803 // prevented changes are reflected immediately; these often use MediaWiki: pages.
804 // The datacenter handling replace() calls should be the same one handling edits
805 // as they require HTTP POST.
806 $this->saveToCaches( $cache, 'all', $code );
807 // Release the lock now that the cache is saved
808 ScopedCallback::consume( $scopedLock );
809
810 // Relay the purge. Touching this check key expires cache contents
811 // and local cache (APC) validation hash across all datacenters.
812 $this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
813
814 // Purge the messages in the message blob store and fire any hook handlers
815 $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
816 foreach ( $replacements as [ $title, $msg ] ) {
817 $blobStore->updateMessage( $this->contLang->lcfirst( $msg ) );
818 $this->hookRunner->onMessageCacheReplace( $title, $newTextByTitle[$title] );
819 }
820 }
821
828 private function isCacheExpired( $cache ) {
829 return !isset( $cache['VERSION'] ) ||
830 !isset( $cache['EXPIRY'] ) ||
831 $cache['VERSION'] !== self::CACHE_VERSION ||
832 $cache['EXPIRY'] <= wfTimestampNow();
833 }
834
845 private function saveToCaches( array $cache, $dest, $code = false ) {
846 if ( $dest === 'all' ) {
847 $cacheKey = $this->mainCache->makeKey( 'messages', $code );
848 $success = $this->mainCache->set( $cacheKey, $cache );
849 $this->setValidationHash( $code, $cache );
850 } else {
851 $success = true;
852 }
853
854 $this->saveToLocalCache( $code, $cache );
855
856 return $success;
857 }
858
865 private function getValidationHash( $code ) {
866 $curTTL = null;
867 $value = $this->wanCache->get(
868 $this->wanCache->makeKey( 'messages', $code, 'hash', 'v1' ),
869 $curTTL,
870 [ $this->getCheckKey( $code ) ]
871 );
872
873 if ( $value ) {
874 $hash = $value['hash'];
875 if ( ( time() - $value['latest'] ) < WANObjectCache::TTL_MINUTE ) {
876 // Cache was recently updated via replace() and should be up-to-date.
877 // That method is only called in the primary datacenter and uses FOR_UPDATE.
878 $isCacheVolatile = false;
879 } else {
880 // See if the "check" key was bumped after the hash was generated
881 $isCacheVolatile = ( $curTTL < 0 );
882 }
883 } else {
884 // No hash found at all; cache must regenerate to be safe
885 $hash = false;
886 $isCacheVolatile = true;
887 }
888
889 return [ $hash, $isCacheVolatile ];
890 }
891
902 private function setValidationHash( $code, array $cache ) {
903 $this->wanCache->set(
904 $this->wanCache->makeKey( 'messages', $code, 'hash', 'v1' ),
905 [
906 'hash' => $cache['HASH'],
907 'latest' => $cache['LATEST'] ?? 0
908 ],
909 WANObjectCache::TTL_INDEFINITE
910 );
911 }
912
919 private function getReentrantScopedLock( $code, $timeout = self::LOCK_WAIT_TIME ) {
920 $key = $this->mainCache->makeKey( 'messages', $code );
921
922 $watchPoint = $this->mainCache->watchErrors();
923 $scopedLock = $this->mainCache->getScopedLock(
924 $key,
925 $timeout,
926 self::LOCK_TTL,
927 __METHOD__
928 );
929 $error = ( !$scopedLock && $this->mainCache->getLastError( $watchPoint ) );
930
931 return [ $scopedLock, $error ];
932 }
933
940 public function normalizeKey( string $key ): string {
941 if ( $key === '' ) {
942 return '';
943 }
944 $lckey = strtr( $key, ' ', '_' );
945 if ( ord( $lckey[0] ) < 128 ) {
946 $lckey[0] = strtolower( $lckey[0] );
947 } else {
948 $lckey = $this->contLang->lcfirst( $lckey );
949 }
950
951 return $lckey;
952 }
953
985 public function get( $key, $useDB = true, $language = null, $info = null ) {
986 if ( is_int( $key ) ) {
987 // Fix numerical strings that somehow become ints on their way here
988 $key = (string)$key;
989 } elseif ( !is_string( $key ) ) {
990 throw new InvalidArgumentException( 'Message key must be a string' );
991 } elseif ( $key === '' ) {
992 // Shortcut: the empty key is always missing
993 return false;
994 }
995
996 // Ignore legacy $usedKey parameter
997 if ( $info && !( $info instanceof MessageInfo ) ) {
998 $info = null;
999 }
1000
1001 $langCode = $this->getLanguageCode( $language ?? $this->contLangCode );
1002
1003 // Normalise title-case input (with some inlining)
1004 $lckey = $this->normalizeKey( $key );
1005
1006 // Initialize the overrides here to prevent calling the hook too early.
1007 if ( $this->messageKeyOverrides === null ) {
1008 $this->messageKeyOverrides = [];
1009 $this->hookRunner->onMessageCacheFetchOverrides( $this->messageKeyOverrides );
1010 }
1011
1012 if ( isset( $this->messageKeyOverrides[$lckey] ) ) {
1013 $override = $this->messageKeyOverrides[$lckey];
1014
1015 // Strings are deliberately interpreted as message keys,
1016 // to prevent ambiguity between message keys and functions.
1017 if ( is_string( $override ) ) {
1018 $lckey = $override;
1019 } else {
1020 $lckey = $override( $lckey, $this );
1021 }
1022 }
1023
1024 $this->hookRunner->onMessageCache__get( $lckey );
1025
1026 if ( $info ) {
1027 $info->usedKey = $lckey;
1028 }
1029
1030 // Loop through each language in the fallback list until we find something useful
1031 $message = $this->getMessageFromFallbackChain(
1032 $langCode,
1033 $lckey,
1034 !$this->disabled && $useDB,
1035 $info
1036 );
1037
1038 // If we still have no message, maybe the key was in fact a full key, so try that
1039 if ( $message === false ) {
1040 $parts = explode( '/', $lckey );
1041 // We may get calls for things that are HTTP URLs from the sidebar
1042 // Let's not load nonexistent languages for those
1043 // They usually have more than one slash.
1044 if ( count( $parts ) === 2 && $parts[1] !== '' ) {
1045 $message = $this->localisationCache->getSubitem( $parts[1], 'messages', $parts[0] ) ?? false;
1046 if ( $message !== false && $info ) {
1047 $info->usedKey = $parts[0];
1048 $info->langCode = $parts[1];
1049 }
1050 }
1051 }
1052
1053 // Post-processing if the message exists
1054 if ( $message !== false ) {
1055 // Fix whitespace
1056 $message = str_replace(
1057 [
1058 // Fix for trailing whitespace, removed by textarea
1059 '&#32;',
1060 // Fix for NBSP, converted to space by firefox
1061 '&nbsp;',
1062 '&#160;',
1063 '&shy;'
1064 ],
1065 [
1066 ' ',
1067 "\u{00A0}",
1068 "\u{00A0}",
1069 "\u{00AD}"
1070 ],
1071 $message
1072 );
1073 }
1074
1075 return $message;
1076 }
1077
1090 private function getLanguageCode( $lang ): string {
1091 if ( is_object( $lang ) ) {
1092 StubObject::unstub( $lang );
1093 if ( $lang instanceof Language ) {
1094 wfDeprecatedMsg( 'Calling MessageCache::get with a Language object ' .
1095 'was deprecated in MediaWiki 1.44', '1.44' );
1096 return $lang->getCode();
1097 } else {
1098 throw new InvalidArgumentException( 'Invalid language object of class ' .
1099 get_class( $lang ) );
1100 }
1101 } elseif ( is_string( $lang ) ) {
1102 if ( $this->languageNameUtils->isValidCode( $lang ) ) {
1103 return $lang;
1104 }
1105 // $lang is a string, but not a valid language code; use content language.
1106 $this->logger->debug( 'Invalid language code passed to' . __METHOD__ .
1107 ', falling back to content language.' );
1108 return $this->contLangCode;
1109 } elseif ( is_bool( $lang ) ) {
1110 wfDeprecatedMsg( 'Calling MessageCache::get with a boolean language parameter ' .
1111 'was deprecated in MediaWiki 1.43', '1.43' );
1112 if ( $lang ) {
1113 return $this->contLangCode;
1114 } else {
1115 global $wgLang;
1116 return $wgLang->getCode();
1117 }
1118 } else {
1119 throw new InvalidArgumentException( 'Invalid language' );
1120 }
1121 }
1122
1134 private function getMessageFromFallbackChain( $code, $lckey, $useDB, $info ) {
1135 $alreadyTried = [];
1136
1137 // First try the requested language.
1138 $message = $this->getMessageForLang( $code, $lckey, $useDB, $alreadyTried, $info );
1139 if ( $message !== false ) {
1140 return $message;
1141 }
1142
1143 // Now try checking the site language.
1144 $message = $this->getMessageForLang( $this->contLangCode, $lckey, $useDB, $alreadyTried, $info );
1145 return $message;
1146 }
1147
1159 private function getMessageForLang( $langCode, $lckey, $useDB, &$alreadyTried, $info ) {
1160 // Try checking the database for the requested language
1161 if ( $useDB ) {
1162 $uckey = $this->contLang->ucfirst( $lckey );
1163
1164 if ( !isset( $alreadyTried[$langCode] ) ) {
1165 $message = $this->getMsgFromNamespace(
1166 $this->getMessagePageName( $langCode, $uckey ),
1167 $langCode
1168 );
1169 if ( $message !== false ) {
1170 if ( $info ) {
1171 $info->langCode = $langCode;
1172 }
1173 return $message;
1174 }
1175 $alreadyTried[$langCode] = true;
1176 }
1177 } else {
1178 $uckey = null;
1179 }
1180
1181 // Return a special value handled in Message::format() to display the message key
1182 // (and fallback keys) and the parameters passed to the message.
1183 // TODO: Move to a better place.
1184 if ( $langCode === 'qqx' ) {
1185 return '($*)';
1186 } elseif (
1187 $langCode === 'x-xss' &&
1188 $this->useXssLanguage &&
1189 !in_array( $lckey, $this->rawHtmlMessages, true )
1190 ) {
1191 $lcKeyForAlert = str_replace( [ '"', "'" ], '_', $lckey );
1192 $xssViaInnerHtml = "<img src=\"\" onerror='alert(\"$lcKeyForAlert\")'/>";
1193 $xssViaAttribute = '">' . $xssViaInnerHtml . '<x y="';
1194 return $xssViaInnerHtml . $xssViaAttribute . '($*)';
1195 }
1196
1197 // Check the localisation cache
1198 [ $defaultMessage, $messageSource ] =
1199 $this->localisationCache->getSubitemWithSource( $langCode, 'messages', $lckey );
1200 if ( $messageSource === $langCode ) {
1201 if ( $info ) {
1202 $info->langCode = $langCode;
1203 }
1204 return $defaultMessage;
1205 }
1206
1207 // Try checking the database for all of the fallback languages
1208 if ( $useDB ) {
1209 $fallbackChain = $this->languageFallback->getAll( $langCode );
1210
1211 foreach ( $fallbackChain as $code ) {
1212 if ( isset( $alreadyTried[$code] ) ) {
1213 continue;
1214 }
1215
1216 $message = $this->getMsgFromNamespace(
1217 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable uckey is set when used
1218 $this->getMessagePageName( $code, $uckey ), $code );
1219
1220 if ( $message !== false ) {
1221 if ( $info ) {
1222 $info->langCode = $code;
1223 }
1224 return $message;
1225 }
1226 $alreadyTried[$code] = true;
1227
1228 // Reached the source language of the default message. Don't look for DB overrides
1229 // further back in the fallback chain. (T229992)
1230 if ( $code === $messageSource ) {
1231 if ( $info ) {
1232 $info->langCode = $code;
1233 }
1234 return $defaultMessage;
1235 }
1236 }
1237 }
1238
1239 if ( $defaultMessage !== null && $info ) {
1240 $info->langCode = $messageSource;
1241 }
1242 return $defaultMessage ?? false;
1243 }
1244
1252 private function getMessagePageName( $langCode, $uckey ) {
1253 if ( $langCode === $this->contLangCode ) {
1254 // Messages created in the content language will not have the /lang extension
1255 return $uckey;
1256 } else {
1257 return "$uckey/$langCode";
1258 }
1259 }
1260
1273 public function getMsgFromNamespace( $title, $code ) {
1274 // Load all MediaWiki page definitions into cache. Note that individual keys
1275 // already loaded into the cache during this request remain in the cache, which
1276 // includes the value of hook-defined messages.
1277 $this->load( $code );
1278
1279 $entry = $this->cache->getField( $code, $title );
1280
1281 if ( $entry !== null ) {
1282 // Message page exists as an override of a software messages
1283 if ( str_starts_with( $entry, ' ' ) ) {
1284 // The message exists and is not '!TOO BIG' or '!ERROR'
1285 return substr( $entry, 1 );
1286 } elseif ( $entry === '!NONEXISTENT' ) {
1287 // The text might be '-' or missing due to some data loss
1288 return false;
1289 }
1290 // Load the message page, utilizing the individual message cache.
1291 // If the page does not exist, there will be no hook handler fallbacks.
1292 $entry = $this->loadCachedMessagePageEntry(
1293 $title,
1294 $code,
1295 $this->cache->getField( $code, 'HASH' )
1296 );
1297 } else {
1298 // Message page either does not exist or does not override a software message
1299 if ( !$this->isMainCacheable( $title, $code ) ) {
1300 // Message page does not override any software-defined message. A custom
1301 // message might be defined to have content or settings specific to the wiki.
1302 // Load the message page, utilizing the individual message cache as needed.
1303 $entry = $this->loadCachedMessagePageEntry(
1304 $title,
1305 $code,
1306 $this->cache->getField( $code, 'HASH' )
1307 );
1308 }
1309 if ( $entry === null || !str_starts_with( $entry, ' ' ) ) {
1310 // Message does not have a MediaWiki page definition; try hook handlers
1311 $message = false;
1312 // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
1313 $this->hookRunner->onMessagesPreLoad( $title, $message, $code );
1314 if ( $message !== false ) {
1315 $this->cache->setField( $code, $title, ' ' . $message );
1316 } else {
1317 $this->cache->setField( $code, $title, '!NONEXISTENT' );
1318 }
1319
1320 return $message;
1321 }
1322 }
1323
1324 if ( $entry !== false && str_starts_with( $entry, ' ' ) ) {
1325 if ( $this->isCacheVolatile[$code] ) {
1326 // Make sure that individual keys respect the WAN cache holdoff period too
1327 $this->logger->debug(
1328 __METHOD__ . ': loading volatile key \'{titleKey}\'',
1329 [ 'titleKey' => $title, 'code' => $code ] );
1330 } else {
1331 $this->cache->setField( $code, $title, $entry );
1332 }
1333 // The message exists, so make sure a string is returned
1334 return substr( $entry, 1 );
1335 }
1336
1337 $this->cache->setField( $code, $title, '!NONEXISTENT' );
1338
1339 return false;
1340 }
1341
1348 private function loadCachedMessagePageEntry( $dbKey, $code, $hash ) {
1349 $fname = __METHOD__;
1350 return $this->srvCache->getWithSetCallback(
1351 $this->srvCache->makeKey( 'messages-big', $hash, $dbKey ),
1352 BagOStuff::TTL_HOUR,
1353 function () use ( $code, $dbKey, $hash, $fname ) {
1354 return $this->wanCache->getWithSetCallback(
1355 $this->bigMessageCacheKey( $hash, $dbKey ),
1356 self::WAN_TTL,
1357 function ( $oldValue, &$ttl, &$setOpts ) use ( $dbKey, $code, $fname ) {
1358 // Try loading the message from the database
1359 $setOpts += Database::getCacheSetOptions(
1360 MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase()
1361 );
1362 // Use newKnownCurrent() to avoid querying revision/user tables
1363 $title = Title::makeTitle( NS_MEDIAWIKI, $dbKey );
1364 // Injecting RevisionStore breaks installer since it
1365 // instantiates MessageCache before DB.
1366 $revision = MediaWikiServices::getInstance()
1367 ->getRevisionLookup()
1368 ->getKnownCurrentRevision( $title );
1369 if ( !$revision ) {
1370 // The wiki doesn't have a local override page. Cache absence with normal TTL.
1371 // When overrides are created, self::replace() takes care of the cache.
1372 return '!NONEXISTENT';
1373 }
1374 $content = $revision->getContent( SlotRecord::MAIN );
1375 if ( $content ) {
1376 $message = $this->getMessageTextFromContent( $content );
1377 } else {
1378 $this->logger->warning(
1379 $fname . ': failed to load page text for \'{titleKey}\'',
1380 [ 'titleKey' => $dbKey, 'code' => $code ]
1381 );
1382 $message = null;
1383 }
1384
1385 if ( !is_string( $message ) ) {
1386 // Revision failed to load Content, or Content is incompatible with wikitext.
1387 // Possibly a temporary loading failure.
1388 $ttl = 5;
1389
1390 return '!NONEXISTENT';
1391 }
1392
1393 return ' ' . $message;
1394 }
1395 );
1396 }
1397 );
1398 }
1399
1409 public function transform( $message, $interface = false, $language = null, ?PageReference $page = null ) {
1410 return $this->messageParser->transform(
1411 $message, $interface, $language, $page );
1412 }
1413
1428 string $text, PageReference $contextPage,
1429 bool $linestart = true,
1430 bool $interface = false,
1431 $language = null
1432 ): ParserOutput {
1433 return $this->messageParser->parse(
1434 $text, $contextPage, $linestart, $interface, $language );
1435 }
1436
1447 public function parse( $text, ?PageReference $page = null,
1448 $linestart = true, $interface = false, $language = null
1449 ) {
1450 // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle
1451 global $wgTitle;
1452 if ( !$page ) {
1453 $logger = LoggerFactory::getInstance( 'GlobalTitleFail' );
1454 $logger->info(
1455 __METHOD__ . ' called with no title set.',
1456 [ 'exception' => new RuntimeException ]
1457 );
1458 $page = $wgTitle;
1459 }
1460 // Sometimes $wgTitle isn't set either...
1461 if ( !$page ) {
1462 // It's not uncommon having a null $wgTitle in scripts. See r80898
1463 // Create a ghost title in such case
1464 $page = PageReferenceValue::localReference(
1465 NS_SPECIAL,
1466 'Badtitle/title not set in ' . __METHOD__
1467 );
1468 }
1469
1470 return $this->messageParser->parseWithoutPostprocessing(
1471 $text, $page, $linestart, $interface, $language );
1472 }
1473
1480 public function disable( $logReason = '' ) {
1481 if ( $logReason !== '' ) {
1482 $this->logger->debug( "disabling MessageCache: $logReason" );
1483 }
1484 $this->disabled = true;
1485 }
1486
1490 public function enable() {
1491 $this->logger->debug( "re-enabling MessageCache" );
1492 $this->disabled = false;
1493 }
1494
1508 public function isDisabled() {
1509 return $this->disabled;
1510 }
1511
1517 public function clear() {
1518 $langs = $this->languageNameUtils->getLanguageNames();
1519 foreach ( $langs as $code => $_ ) {
1520 $this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
1521 }
1522 $this->cache->clear();
1523 }
1524
1532 public function figureMessage( $key ) {
1533 $pieces = explode( '/', $key );
1534 if ( count( $pieces ) < 2 ) {
1535 return [ $key, $this->contLangCode ];
1536 }
1537
1538 $lang = array_pop( $pieces );
1539 if ( !$this->languageNameUtils->getLanguageName(
1540 $lang,
1541 LanguageNameUtils::AUTONYMS,
1542 LanguageNameUtils::DEFINED
1543 ) ) {
1544 return [ $key, $this->contLangCode ];
1545 }
1546
1547 $message = implode( '/', $pieces );
1548
1549 return [ $message, $lang ];
1550 }
1551
1561 public function getAllMessageKeys( $code ) {
1562 $this->load( $code );
1563 if ( !$this->cache->has( $code ) ) {
1564 // Apparently load() failed
1565 return null;
1566 }
1567 // Remove administrative keys
1568 $cache = $this->cache->get( $code );
1569 unset( $cache['VERSION'] );
1570 unset( $cache['EXPIRY'] );
1571 unset( $cache['EXCESSIVE'] );
1572 // Remove any !NONEXISTENT keys
1573 $cache = array_diff( $cache, [ '!NONEXISTENT' ] );
1574
1575 // Keys may appear with a capital first letter. lcfirst them.
1576 return array_map( $this->contLang->lcfirst( ... ), array_keys( $cache ) );
1577 }
1578
1587 public function updateMessageOverride( $page, ?Content $content = null ) {
1588 // treat null as not existing
1589 $msgText = $this->getMessageTextFromContent( $content ) ?? false;
1590
1591 $this->replace( $page->getDBkey(), $msgText );
1592
1593 if ( $this->contLangConverter->hasVariants() ) {
1594 $this->contLangConverter->updateConversionTable( $page );
1595 }
1596 }
1597
1602 public function getCheckKey( $code ) {
1603 return $this->wanCache->makeKey( 'messages', $code );
1604 }
1605
1610 private function getMessageTextFromContent( ?Content $content = null ) {
1611 // @TODO: could skip pseudo-messages like js/css here, based on content model
1612 if ( $content && $content->isRedirect() ) {
1613 // Treat redirects as not existing (T376398)
1614 $msgText = false;
1615 } elseif ( $content ) {
1616 // Message page exists...
1617 // XXX: Is this the right way to turn a Content object into a message?
1618 // NOTE: $content is typically either WikitextContent, JavaScriptContent or
1619 // CssContent.
1620 $msgText = $content->getWikitextForTransclusion();
1621 if ( $msgText === false || $msgText === null ) {
1622 // This might be due to some kind of misconfiguration...
1623 $msgText = null;
1624 $this->logger->warning(
1625 __METHOD__ . ": message content doesn't provide wikitext "
1626 . "(content model: " . $content->getModel() . ")" );
1627 }
1628 } else {
1629 // Message page does not exist...
1630 $msgText = false;
1631 }
1632
1633 return $msgText;
1634 }
1635
1641 private function bigMessageCacheKey( $hash, $title ) {
1642 return $this->wanCache->makeKey( 'messages-big', $hash, $title );
1643 }
1644}
1645
1647class_alias( MessageCache::class, 'MessageCache' );
const NS_MEDIAWIKI
Definition Defines.php:59
const NS_SPECIAL
Definition Defines.php:40
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(MW_ENTRY_POINT==='index') if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:551
if(MW_ENTRY_POINT==='index') if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgTitle
Definition Setup.php:551
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:68
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Defer callable updates to run later in the PHP process.
makeTitle( $linkId)
Convert a link ID to a Title.to override Title
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
An interface for creating language converters.
getLanguageConverter( $language=null)
Provide a LanguageConverter for given language.
A service that provides utilities to do with language names and codes.
Base class for language-specific code.
Definition Language.php:69
getCode()
Get the internal language code for this language object.
Caching for the contents of localisation files.
Message cache purging and in-place update handler for specific message page changes.
Cache messages that are defined by MediaWiki-namespace pages or by hooks.
__construct(WANObjectCache $wanCache, BagOStuff $mainCache, BagOStuff $serverCache, Language $contLang, LanguageConverterFactory $langConverterFactory, LoggerInterface $logger, ServiceOptions $options, LocalisationCache $localisationCache, LanguageNameUtils $languageNameUtils, LanguageFallback $languageFallback, HookContainer $hookContainer, MessageParser $messageParser)
isDisabled()
Whether DB/cache usage is disabled for determining messages.
getMsgFromNamespace( $title, $code)
Get a message from the MediaWiki namespace, with caching.
const MAX_REQUEST_LANGUAGES
The size of the MapCacheLRU which stores message data.
parseWithPostprocessing(string $text, PageReference $contextPage, bool $linestart=true, bool $interface=false, $language=null)
replace( $title, $text)
Update the cache as necessary when a message page is changed.
getAllMessageKeys( $code)
Get all message keys stored in the message cache for a given language.
refreshAndReplaceInternal(string $code, array $replacements)
updateMessageOverride( $page, ?Content $content=null)
Purge message caches when a MediaWiki: page is created, updated, or deleted.
parse( $text, ?PageReference $page=null, $linestart=true, $interface=false, $language=null)
figureMessage( $key)
Given a title string possibly containing a slash, determine the message key and language code.
const CONSTRUCTOR_OPTIONS
Options to be included in the ServiceOptions.
transform( $message, $interface=false, $language=null, ?PageReference $page=null)
enable()
Re-enable the MessageCache if it was disabled by a call to disable()
normalizeKey(string $key)
Normalize message key input.
setLogger(LoggerInterface $logger)
disable( $logReason='')
Disable loading of messages from the MediaWiki namespace.
clear()
Clear all stored messages in global and local cache.
Class to hold extra information about the result of a MessageCache::get() call.
Service for transformation of interface message text.
Create PSR-3 logger objects.
A class containing constants representing the names of configuration variables.
const MaxMsgCacheEntrySize
Name constant for the MaxMsgCacheEntrySize setting, for use with Config::get()
const AdaptiveMessageCache
Name constant for the AdaptiveMessageCache setting, for use with Config::get()
const UseXssLanguage
Name constant for the UseXssLanguage setting, for use with Config::get()
const UseDatabaseMessages
Name constant for the UseDatabaseMessages setting, for use with Config::get()
const RawHtmlMessages
Name constant for the RawHtmlMessages setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Immutable value object representing a page reference.
ParserOutput is a rendering of a Content object or a message.
Value object representing a content slot associated with a page revision.
Class to implement stub globals, which are globals that delay loading the their associated module cod...
Stub object for the user language.
Represents a title within MediaWiki.
Definition Title.php:69
Store key-value entries in a size-limited in-memory LRU cache.
set( $key, $value, $rank=self::RANK_TOP)
Set a key/value pair.
get( $key, $maxAge=INF, $default=null)
Get the value for a key.
hasField( $key, $field, $maxAge=INF)
Abstract class for any ephemeral data store.
Definition BagOStuff.php:73
No-op implementation that stores nothing.
Multi-datacenter aware caching interface.
Content of like value.
Definition LikeValue.php:14
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'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'UseLegacyMediaStyles' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], '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.', ],]
Content objects represent page content, e.g.
Definition Content.php:28
The shared interface for all language converters.
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 database access objects.
Result wrapper for grabbing data queried from an IDatabase object.