MediaWiki master
Sanitizer.php
Go to the documentation of this file.
1<?php
2declare( strict_types = 1 );
3
15namespace MediaWiki\Parser;
16
17use InvalidArgumentException;
18use LogicException;
22use UnexpectedValueException;
23use Wikimedia\RemexHtml\HTMLData;
24use Wikimedia\RemexHtml\Serializer\Serializer as RemexSerializer;
25use Wikimedia\RemexHtml\Tokenizer\Tokenizer as RemexTokenizer;
26use Wikimedia\RemexHtml\TreeBuilder\Dispatcher as RemexDispatcher;
27use Wikimedia\RemexHtml\TreeBuilder\TreeBuilder as RemexTreeBuilder;
29
34class Sanitizer {
41 private const CHAR_REFS_REGEX =
42 '/&([A-Za-z0-9\x80-\xff]+;)
43 |&\#([0-9]+);
44 |&\#[xX]([0-9A-Fa-f]+);
45 |&/x';
46
47 private const INSECURE_RE = '! expression
48 | accelerator\s*:
49 | -o-link\s*:
50 | -o-link-source\s*:
51 | -o-replace\s*:
52 | url\s*\‍(
53 | src\s*\‍(
54 | image\s*\‍(
55 | image-set\s*\‍(
56 | attr\s*\‍([^)]+[\s,]+url
57 !ix';
58
63 private const ELEMENT_BITS_REGEX = '!^(/?)([A-Za-z][^\t\n\v />\0]*+)([^>]*?)(/?>)([^<]*)$!';
64
74 private const EVIL_URI_PATTERN = '!(^|\s|\*/\s*)(javascript|vbscript)([^\w]|$)!i';
75 private const XMLNS_ATTRIBUTE_PATTERN = "/^xmlns:[:A-Z_a-z-.0-9]+$/";
76
82 public const ID_PRIMARY = 0;
83
90 public const ID_FALLBACK = 1;
91
97 private const IDN_RE_G = "/
98 \\s| # general whitespace
99 \u{00AD}| # SOFT HYPHEN
100 \u{034F}| # COMBINING GRAPHEME JOINER
101 \u{061C}| # ARABIC LETTER MARK
102 [\u{115F}-\u{1160}]| # HANGUL CHOSEONG FILLER..
103 # HANGUL JUNGSEONG FILLER
104 [\u{17B4}-\u{17B5}]| # KHMER VOWEL INHERENT AQ..
105 # KHMER VOWEL INHERENT AA
106 [\u{180B}-\u{180D}]| # MONGOLIAN FREE VARIATION SELECTOR ONE..
107 # MONGOLIAN FREE VARIATION SELECTOR THREE
108 \u{180E}| # MONGOLIAN VOWEL SEPARATOR
109 [\u{200B}-\u{200F}]| # ZERO WIDTH SPACE..
110 # RIGHT-TO-LEFT MARK
111 [\u{202A}-\u{202E}]| # LEFT-TO-RIGHT EMBEDDING..
112 # RIGHT-TO-LEFT OVERRIDE
113 [\u{2060}-\u{2064}]| # WORD JOINER..
114 # INVISIBLE PLUS
115 \u{2065}| # <reserved-2065>
116 [\u{2066}-\u{206F}]| # LEFT-TO-RIGHT ISOLATE..
117 # NOMINAL DIGIT SHAPES
118 \u{3164}| # HANGUL FILLER
119 [\u{FE00}-\u{FE0F}]| # VARIATION SELECTOR-1..
120 # VARIATION SELECTOR-16
121 \u{FEFF}| # ZERO WIDTH NO-BREAK SPACE
122 \u{FFA0}| # HALFWIDTH HANGUL FILLER
123 [\u{FFF0}-\u{FFF8}]| # <reserved-FFF0>..
124 # <reserved-FFF8>
125 [\u{1BCA0}-\u{1BCA3}]| # SHORTHAND FORMAT LETTER OVERLAP..
126 # SHORTHAND FORMAT UP STEP
127 [\u{1D173}-\u{1D17A}]| # MUSICAL SYMBOL BEGIN BEAM..
128 # MUSICAL SYMBOL END PHRASE
129 \u{E0000}| # <reserved-E0000>
130 \u{E0001}| # LANGUAGE TAG
131 [\u{E0002}-\u{E001F}]| # <reserved-E0002>..
132 # <reserved-E001F>
133 [\u{E0020}-\u{E007F}]| # TAG SPACE..
134 # CANCEL TAG
135 [\u{E0080}-\u{E00FF}]| # <reserved-E0080>..
136 # <reserved-E00FF>
137 [\u{E0100}-\u{E01EF}]| # VARIATION SELECTOR-17..
138 # VARIATION SELECTOR-256
139 [\u{E01F0}-\u{E0FFF}]| # <reserved-E01F0>..
140 # <reserved-E0FFF>
141 /xuD";
142
147 private const MW_ENTITY_ALIASES = [
148 'רלמ;' => 'rlm;',
149 'رلم;' => 'rlm;',
150 ];
151
155 private static ?string $attribsRegex = null;
156
162 private static function getAttribsRegex(): string {
163 if ( self::$attribsRegex === null ) {
164 $spaceChars = '\x09\x0a\x0c\x0d\x20';
165 $space = "[{$spaceChars}]";
166 $attrib = "[^{$spaceChars}\/>=]";
167 $attribFirst = "(?:{$attrib}|=)";
168 self::$attribsRegex =
169 "/({$attribFirst}{$attrib}*)
170 ($space*=$space*
171 (?:
172 # The attribute value: quoted or alone
173 \"([^\"]*)(?:\"|\$)
174 | '([^']*)(?:'|\$)
175 | (((?!$space|>).)*)
176 )
177 )?/sxu";
178 }
179 return self::$attribsRegex;
180 }
181
185 private static ?string $attribNameRegex = null;
186
190 private static function getAttribNameRegex(): string {
191 if ( self::$attribNameRegex === null ) {
192 $attribFirst = "[:_\p{L}\p{N}]";
193 $attrib = "[:_\.\-\p{L}\p{N}]";
194 self::$attribNameRegex = "/^({$attribFirst}{$attrib}*)$/sxu";
195 }
196 return self::$attribNameRegex;
197 }
198
206 public static function getRecognizedTagData( array $extratags = [], array $removetags = [] ): array {
207 static $commonCase, $staticInitialised = false;
208 $isCommonCase = ( $extratags === [] && $removetags === [] );
209 if ( $staticInitialised && $isCommonCase && $commonCase ) {
210 return $commonCase;
211 }
212
213 static $htmlpairsStatic, $htmlsingle, $htmlsingleonly, $htmlnest, $tabletags,
214 $htmllist, $listtags, $htmlsingleallowed, $htmlelementsStatic;
215
216 if ( !$staticInitialised ) {
217 $htmlpairsStatic = [ # Tags that must be closed
218 'b', 'bdi', 'del', 'i', 'ins', 'u', 'font', 'big', 'small', 'sub', 'sup', 'h1',
219 'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's',
220 'strike', 'strong', 'tt', 'var', 'div', 'center',
221 'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre',
222 'ruby', 'rb', 'rp', 'rt', 'rtc', 'p', 'span', 'abbr', 'dfn',
223 'kbd', 'samp', 'data', 'time', 'mark'
224 ];
225 # These tags can be self-closed. For tags not also on
226 # $htmlsingleonly, a self-closed tag will be emitted as
227 # an empty element (open-tag/close-tag pair).
228 $htmlsingle = [
229 'br', 'wbr', 'hr', 'li', 'dt', 'dd', 'meta', 'link'
230 ];
231
232 # Elements that cannot have close tags. This is (not coincidentally)
233 # also the list of tags for which the HTML 5 parsing algorithm
234 # requires you to "acknowledge the token's self-closing flag", i.e.
235 # a self-closing tag like <br/> is not an HTML 5 parse error only
236 # for this list.
237 $htmlsingleonly = [
238 'br', 'wbr', 'hr', 'meta', 'link'
239 ];
240
241 $htmlnest = [ # Tags that can be nested--??
242 'table', 'tr', 'td', 'th', 'div', 'blockquote', 'ol', 'ul',
243 'li', 'dl', 'dt', 'dd', 'font', 'big', 'small', 'sub', 'sup', 'span',
244 'var', 'kbd', 'samp', 'em', 'strong', 'q', 'ruby', 'bdo'
245 ];
246 $tabletags = [ # Can only appear inside table, we will close them
247 'td', 'th', 'tr',
248 ];
249 $htmllist = [ # Tags used by list
250 'ul', 'ol',
251 ];
252 $listtags = [ # Tags that can appear in a list
253 'li',
254 ];
255
256 $htmlsingleallowed = array_unique( array_merge( $htmlsingle, $tabletags ) );
257 $htmlelementsStatic = array_unique( array_merge( $htmlsingle, $htmlpairsStatic, $htmlnest ) );
258
259 # Convert them all to hashtables for faster lookup
260 $vars = [ 'htmlpairsStatic', 'htmlsingle', 'htmlsingleonly', 'htmlnest', 'tabletags',
261 'htmllist', 'listtags', 'htmlsingleallowed', 'htmlelementsStatic' ];
262 foreach ( $vars as $var ) {
263 $$var = array_fill_keys( $$var, true );
264 }
265 $staticInitialised = true;
266 }
267
268 # Populate $htmlpairs and $htmlelements with the $extratags and $removetags arrays
269 $extratags = array_fill_keys( $extratags, true );
270 $removetags = array_fill_keys( $removetags, true );
271 $htmlpairs = array_merge( $extratags, $htmlpairsStatic );
272 $htmlelements = array_diff_key( array_merge( $extratags, $htmlelementsStatic ), $removetags );
273
274 $result = [
275 'htmlpairs' => $htmlpairs,
276 'htmlsingle' => $htmlsingle,
277 'htmlsingleonly' => $htmlsingleonly,
278 'htmlnest' => $htmlnest,
279 'tabletags' => $tabletags,
280 'htmllist' => $htmllist,
281 'listtags' => $listtags,
282 'htmlsingleallowed' => $htmlsingleallowed,
283 'htmlelements' => $htmlelements,
284 ];
285 if ( $isCommonCase ) {
286 $commonCase = $result;
287 }
288 return $result;
289 }
290
319 public static function internalRemoveHtmlTags( string $text, ?callable $processCallback = null,
320 $args = [], array $extratags = [], array $removetags = []
321 ): string {
322 $tagData = self::getRecognizedTagData( $extratags, $removetags );
323 $htmlsingle = $tagData['htmlsingle'];
324 $htmlsingleonly = $tagData['htmlsingleonly'];
325 $htmlelements = $tagData['htmlelements'];
326
327 # Remove HTML comments
328 $text = self::removeHTMLcomments( $text );
329 $bits = explode( '<', $text );
330 $text = str_replace( '>', '&gt;', array_shift( $bits ) );
331
332 # this might be possible using remex tidy itself
333 foreach ( $bits as $x ) {
334 if ( preg_match( self::ELEMENT_BITS_REGEX, $x, $regs ) ) {
335 [ /* $qbar */, $slash, $t, $params, $brace, $rest ] = $regs;
336
337 $badtag = false;
338 $t = strtolower( $t );
339 if ( isset( $htmlelements[$t] ) ) {
340 if ( is_callable( $processCallback ) ) {
341 $processCallback( $params, $args );
342 }
343
344 if ( $brace == '/>' && !( isset( $htmlsingle[$t] ) || isset( $htmlsingleonly[$t] ) ) ) {
345 // Remove the self-closing slash, to be consistent
346 // with HTML5 semantics. T134423
347 $brace = '>';
348 }
349 if ( !self::validateTag( $params, $t ) ) {
350 $badtag = true;
351 }
352
353 $newparams = self::fixTagAttributes( $params, $t );
354 if ( !$badtag ) {
355 if ( $brace === '/>' && !isset( $htmlsingleonly[$t] ) ) {
356 # Interpret self-closing tags as empty tags even when
357 # HTML 5 would interpret them as start tags. Such input
358 # is commonly seen on Wikimedia wikis with this intention.
359 $brace = "></$t>";
360 }
361
362 $rest = str_replace( '>', '&gt;', $rest );
363 $text .= "<$slash$t$newparams$brace$rest";
364 continue;
365 }
366 }
367 }
368 $text .= '&lt;' . str_replace( '>', '&gt;', $x );
369 }
370 return $text;
371 }
372
396 public static function removeSomeTags(
397 string $text, array $options = []
398 ): string {
399 $extraTags = $options['extraTags'] ?? [];
400 $removeTags = $options['removeTags'] ?? [];
401 // These options are @internal:
402 $attrCallback = $options['attrCallback'] ?? null;
403 $attrCallbackArgs = $options['attrCallbackArgs'] ?? [];
404
405 // This disallows HTML5-style "missing trailing semicolon" attributes
406 // In wikitext "clean&copy" does *not* contain an entity.
407 $text = self::normalizeCharReferences( $text );
408
409 $tagData = self::getRecognizedTagData( $extraTags, $removeTags );
410 // Use RemexHtml to tokenize $text and remove the barred tags
411 $formatter = new RemexCompatFormatter;
412 $serializer = new RemexSerializer( $formatter );
413 $treeBuilder = new RemexTreeBuilder( $serializer, [
414 'ignoreErrors' => true,
415 'ignoreNulls' => true,
416 ] );
417 $dispatcher = new RemexDispatcher( $treeBuilder );
418 $tokenHandler = $dispatcher;
419 $remover = new RemexRemoveTagHandler(
420 $tokenHandler, $text, $tagData,
421 $attrCallback, $attrCallbackArgs,
422 [ 'commentRegex' => $options['commentRegex'] ?? null ]
423 );
424 $tokenizer = new RemexTokenizer( $remover, $text, [
425 'ignoreErrors' => true,
426 // don't ignore char refs, we want them to be decoded
427 'ignoreNulls' => true,
428 'skipPreprocess' => true,
429 ] );
430 $tokenizer->execute( [
431 'fragmentNamespace' => HTMLData::NS_HTML,
432 'fragmentName' => 'body',
433 ] );
434 return $serializer->getResult();
435 }
436
443 public static function removeHTMLcomments( string $text ): string {
444 // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
445 while ( ( $start = strpos( $text, '<!--' ) ) !== false ) {
446 $end = strpos( $text, '-->', $start + 4 );
447 if ( $end === false ) {
448 # Unterminated comment; bail out
449 break;
450 }
451
452 $end += 3;
453
454 # Trim space and newline if the comment is both
455 # preceded and followed by a newline
456 $spaceStart = max( $start - 1, 0 );
457 $spaceLen = $end - $spaceStart;
458 while ( substr( $text, $spaceStart, 1 ) === ' ' && $spaceStart > 0 ) {
459 $spaceStart--;
460 $spaceLen++;
461 }
462 while ( substr( $text, $spaceStart + $spaceLen, 1 ) === ' ' ) {
463 $spaceLen++;
464 }
465 if ( substr( $text, $spaceStart, 1 ) === "\n"
466 && substr( $text, $spaceStart + $spaceLen, 1 ) === "\n" ) {
467 # Remove the comment, leading and trailing
468 # spaces, and leave only one newline.
469 $text = substr_replace( $text, "\n", $spaceStart, $spaceLen + 1 );
470 } else {
471 # Remove just the comment.
472 $text = substr_replace( $text, '', $start, $end - $start );
473 }
474 }
475 return $text;
476 }
477
488 private static function validateTag( string $params, string $element ): bool {
489 $params = self::decodeTagAttributes( $params );
490
491 if ( $element == 'meta' || $element == 'link' ) {
492 if ( !isset( $params['itemprop'] ) ) {
493 // <meta> and <link> must have an itemprop="" otherwise they are not valid or safe in content
494 return false;
495 }
496 if ( $element == 'meta' && !isset( $params['content'] ) ) {
497 // <meta> must have a content="" for the itemprop
498 return false;
499 }
500 if ( $element == 'link' && !isset( $params['href'] ) ) {
501 // <link> must have an associated href=""
502 return false;
503 }
504 }
505
506 return true;
507 }
508
520 public static function validateTagAttributes( array $attribs, string $element ): array {
521 return self::validateAttributes( $attribs,
522 self::attributesAllowedInternal( $element ) );
523 }
524
543 public static function validateAttributes( array $attribs, array $allowed ): array {
544 if ( isset( $allowed[0] ) ) {
545 // Calling this function with a sequential array is
546 // deprecated. For now just convert it.
547 wfDeprecated( __METHOD__ . ' with sequential array', '1.35' );
548 $allowed = array_fill_keys( $allowed, true );
549 }
550 $validProtocols = MediaWikiServices::getInstance()->getUrlUtils()->validProtocols();
551 $hrefExp = '/^(' . $validProtocols . ')[^\s]+$/';
552
553 $out = [];
554 foreach ( $attribs as $attribute => $value ) {
555 # convert numeric attribute names back to strings.
556 $attribute = (string)$attribute;
557 # Allow XML namespace declaration to allow RDFa
558 if ( preg_match( self::XMLNS_ATTRIBUTE_PATTERN, $attribute ) ) {
559 if ( !preg_match( self::EVIL_URI_PATTERN, $value ) ) {
560 $out[$attribute] = $value;
561 }
562
563 continue;
564 }
565
566 # Allow any attribute beginning with "data-"
567 # However:
568 # * Disallow data attributes used by MediaWiki code
569 # * Ensure that the attribute is not namespaced by banning
570 # colons.
571 # * Ensure attribute name will be accepted by the HTML
572 # parser; see
573 # https://github.com/whatwg/dom/issues/849#issuecomment-1007541209
574 # * Underscore and double-wide underscore (U+FF3F) is disallowed
575 # here (but not in Parsoid): T407131
576 if ( (
577 !preg_match( '|^data-[^:= \t\r\n/>\0__]*$|i', $attribute ) &&
578 !array_key_exists( $attribute, $allowed )
579 ) || self::isReservedDataAttribute( $attribute ) ) {
580 continue;
581 }
582
583 # Strip javascript "expression" from stylesheets.
584 # https://msdn.microsoft.com/en-us/library/ms537634.aspx
585 if ( $attribute == 'style' ) {
586 $value = self::checkCss( $value );
587 }
588
589 # Escape HTML id attributes
590 if ( $attribute === 'id' ) {
591 $value = self::escapeIdForAttribute( $value, self::ID_PRIMARY );
592 if ( $value === false || $value === '' ) {
593 continue;
594 }
595 }
596
597 # Escape HTML id reference lists
598 if ( $attribute === 'aria-describedby'
599 || $attribute === 'aria-flowto'
600 || $attribute === 'aria-labelledby'
601 || $attribute === 'aria-owns'
602 ) {
603 $value = self::escapeIdReferenceListInternal( $value );
604 }
605
606 // RDFa and microdata properties allow URLs, URIs and/or CURIs.
607 if ( $attribute === 'rel' || $attribute === 'rev'
608 # RDFa
609 || $attribute === 'about' || $attribute === 'property'
610 || $attribute === 'resource' || $attribute === 'datatype'
611 || $attribute === 'typeof'
612 # HTML5 microdata
613 || $attribute === 'itemid' || $attribute === 'itemprop'
614 || $attribute === 'itemref' || $attribute === 'itemscope'
615 || $attribute === 'itemtype'
616 ) {
617 // Paranoia. Allow "simple" values but suppress javascript
618 if ( preg_match( self::EVIL_URI_PATTERN, $value ) ) {
619 continue;
620 }
621 }
622
623 # NOTE: even though elements using href/src are not allowed directly, supply
624 # validation code that can be used by tag hook handlers, etc
625 if ( $attribute === 'href' || $attribute === 'src' || $attribute === 'poster' ) {
626 if ( !preg_match( $hrefExp, $value ) ) {
627 continue; // drop any href or src attributes not using an allowed protocol.
628 // NOTE: this also drops all relative URLs
629 }
630 }
631
632 if ( $attribute === 'tabindex' && $value !== '0' ) {
633 // Only allow tabindex of 0, which is useful for accessibility.
634 continue;
635 }
636
637 // If this attribute was previously set, override it.
638 // Output should only have one attribute of each name.
639 $out[$attribute] = $value;
640 }
641
642 # itemtype, itemid, itemref don't make sense without itemscope
643 if ( !array_key_exists( 'itemscope', $out ) ) {
644 unset( $out['itemtype'] );
645 unset( $out['itemid'] );
646 unset( $out['itemref'] );
647 }
648 # TODO: Strip itemprop if we aren't descendants of an itemscope or pointed to by an itemref.
649
650 return $out;
651 }
652
660 public static function isReservedDataAttribute( string $attr ): bool {
661 // data-ooui is reserved for ooui.
662 // data-mw and data-parsoid are reserved for parsoid.
663 // data-mw-<name here> is reserved for extensions (or core) if
664 // they need to communicate some data to the client and want to be
665 // sure that it isn't coming from an untrusted user.
666 // We ignore the possibility of namespaces since user-generated HTML
667 // can't use them anymore.
668 return (bool)preg_match( '/^data-(ooui|mw|parsoid)/i', $attr );
669 }
670
680 public static function mergeAttributes( array $a, array $b ): array {
681 $out = array_merge( $a, $b );
682 if ( isset( $a['class'] ) && isset( $b['class'] )
683 && is_string( $a['class'] ) && is_string( $b['class'] )
684 && $a['class'] !== $b['class']
685 ) {
686 $classes = preg_split( '/\s+/', "{$a['class']} {$b['class']}",
687 -1, PREG_SPLIT_NO_EMPTY );
688 $out['class'] = implode( ' ', array_unique( $classes ) );
689 }
690 return $out;
691 }
692
701 public static function normalizeCss( string $value ): string {
702 // Decode character references like &#123;
703 $value = self::decodeCharReferences( $value );
704
705 // Decode escape sequences and line continuation
706 // See the grammar in the CSS 2 spec, appendix D.
707 // This has to be done AFTER decoding character references.
708 // This means it isn't possible for this function to return
709 // unsanitized escape sequences. It is possible to manufacture
710 // input that contains character references that decode to
711 // escape sequences that decode to character references, but
712 // it's OK for the return value to contain character references
713 // because the caller is supposed to escape those anyway.
714 static $decodeRegex;
715 if ( !$decodeRegex ) {
716 $space = '[\\x20\\t\\r\\n\\f]';
717 $nl = '(?:\\n|\\r\\n|\\r|\\f)';
718 $backslash = '\\\\';
719 $decodeRegex = "/ $backslash
720 (?:
721 ($nl) | # 1. Line continuation
722 ([0-9A-Fa-f]{1,6})$space? | # 2. character number
723 (.) | # 3. backslash cancelling special meaning
724 () | # 4. backslash at end of string
725 )/xu";
726 }
727 $value = preg_replace_callback( $decodeRegex,
728 self::cssDecodeCallback( ... ), $value );
729
730 // Let the value through if it's nothing but a single comment, to
731 // allow other functions which may reject it to pass some error
732 // message through.
733 if ( !preg_match( '! ^ \s* /\* [^*\\/]* \*/ \s* $ !x', $value ) ) {
734 // Remove any comments; IE gets token splitting wrong
735 // This must be done AFTER decoding character references and
736 // escape sequences, because those steps can introduce comments
737 // This step cannot introduce character references or escape
738 // sequences, because it replaces comments with spaces rather
739 // than removing them completely.
740 $value = StringUtils::delimiterReplace( '/*', '*/', ' ', $value );
741
742 // Remove anything after a comment-start token, to guard against
743 // incorrect client implementations.
744 $commentPos = strpos( $value, '/*' );
745 if ( $commentPos !== false ) {
746 $value = substr( $value, 0, $commentPos );
747 }
748 }
749
750 return $value;
751 }
752
773 public static function checkCss( $value ) {
774 $value = self::normalizeCss( $value );
775
776 // Reject problematic keywords and control characters
777 if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ||
778 str_contains( $value, \UtfNormal\Constants::UTF8_REPLACEMENT ) ) {
779 return '/* invalid control char */';
780 } elseif ( preg_match( self::INSECURE_RE, $value ) ) {
781 return '/* insecure input */';
782 }
783 return $value;
784 }
785
786 private static function cssDecodeCallback( array $matches ): string {
787 if ( $matches[1] !== '' ) {
788 // Line continuation
789 return '';
790 } elseif ( $matches[2] !== '' ) {
791 # hexdec could return a float if the match is too long, but the
792 # regexp in question limits the string length to 6.
793 $char = \UtfNormal\Utils::codepointToUtf8( hexdec( $matches[2] ) );
794 } elseif ( $matches[3] !== '' ) {
795 $char = $matches[3];
796 } else {
797 $char = '\\';
798 }
799 if ( $char == "\n" || $char == '"' || $char == "'" || $char == '\\' ) {
800 // These characters need to be escaped in strings
801 // Clean up the escape sequence to avoid parsing errors by clients
802 return '\\' . dechex( ord( $char ) ) . ' ';
803 } else {
804 // Decode unnecessary escape
805 return $char;
806 }
807 }
808
830 public static function fixTagAttributes( string $text, string $element, bool $sorted = false ): string {
831 if ( trim( $text ) == '' ) {
832 return '';
833 }
834
835 $decoded = self::decodeTagAttributes( $text );
836 $stripped = self::validateTagAttributes( $decoded, $element );
837
838 if ( $sorted ) {
839 ksort( $stripped );
840 }
841
842 return self::safeEncodeTagAttributes( $stripped );
843 }
844
852 public static function encodeAttribute( string $text ): string {
853 $encValue = htmlspecialchars( $text, ENT_QUOTES );
854
855 // Whitespace is normalized during attribute decoding,
856 // so if we've been passed non-spaces we must encode them
857 // ahead of time or they won't be preserved.
858 $encValue = strtr( $encValue, [
859 "\n" => '&#10;',
860 "\r" => '&#13;',
861 "\t" => '&#9;',
862 ] );
863
864 return $encValue;
865 }
866
875 public static function armorFrenchSpaces( string $text, string $space = '&#160;' ): string {
876 // Replace $ with \$ and \ with \\
877 $space = preg_replace( '#(?<!\\\\‍)(\\$|\\\\‍)#', '\\\\$1', $space );
878 $fixtags = [
879 # French spaces, last one Guillemet-left
880 # only if it isn't followed by a word character.
881 '/ (?=[?:;!%»›](?!\w))/u' => "$space",
882 # French spaces, Guillemet-right
883 # only if it isn't preceded by a word character.
884 '/(?<!\w)([«‹]) /u' => "\\1$space",
885 ];
886 return preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
887 }
888
897 public static function safeEncodeAttribute( string $text ): string {
898 $encValue = self::encodeAttribute( $text );
899
900 # Templates and links may be expanded in later parsing,
901 # creating invalid or dangerous output. Suppress this.
902 $encValue = strtr( $encValue, [
903 // '<', '>', and '"' should never happen, as they indicate that we've received invalid input which should
904 // have been escaped.
905 '<' => '&lt;',
906 '>' => '&gt;',
907 '"' => '&quot;',
908 '{' => '&#123;',
909 '}' => '&#125;', // prevent unpaired language conversion syntax
910 '[' => '&#91;',
911 ']' => '&#93;',
912 "''" => '&#39;&#39;',
913 'ISBN' => '&#73;SBN',
914 'RFC' => '&#82;FC',
915 'PMID' => '&#80;MID',
916 '|' => '&#124;',
917 '_' => '&#95;',
918 '_' => '&#xFF3F;', // Japanese magic words
919 ] );
920
921 # Stupid hack
922 $validProtocols = MediaWikiServices::getInstance()->getUrlUtils()->validProtocols();
923 $encValue = preg_replace_callback(
924 '/((?i)' . $validProtocols . ')/',
925 static function ( $matches ) {
926 return str_replace( ':', '&#58;', $matches[1] );
927 },
928 $encValue );
929 return $encValue;
930 }
931
947 public static function escapeIdForAttribute( string $id, int $mode = self::ID_PRIMARY ) {
948 global $wgFragmentMode;
949
950 if ( !isset( $wgFragmentMode[$mode] ) ) {
951 if ( $mode === self::ID_PRIMARY ) {
952 throw new UnexpectedValueException( '$wgFragmentMode is configured with no primary mode' );
953 }
954 return false;
955 }
956
957 $internalMode = $wgFragmentMode[$mode];
958
959 return self::escapeIdInternal( $id, $internalMode );
960 }
961
974 public static function escapeIdForLink( string $id ): string {
975 global $wgFragmentMode;
976
977 if ( !isset( $wgFragmentMode[self::ID_PRIMARY] ) ) {
978 throw new UnexpectedValueException( '$wgFragmentMode is configured with no primary mode' );
979 }
980
981 $mode = $wgFragmentMode[self::ID_PRIMARY];
982
983 $id = self::escapeIdInternalUrl( $id, $mode );
984
985 return $id;
986 }
987
997 public static function escapeIdForExternalInterwiki( string $id ): string {
999
1000 $id = self::escapeIdInternalUrl( $id, $wgExternalInterwikiFragmentMode );
1001
1002 return $id;
1003 }
1004
1014 private static function escapeIdInternalUrl( string $id, string $mode ): string {
1015 $id = self::escapeIdInternal( $id, $mode );
1016 if ( $mode === 'html5' ) {
1017 $id = preg_replace( '/%([a-fA-F0-9]{2})/', '%25$1', $id );
1018 }
1019 return $id;
1020 }
1021
1029 private static function escapeIdInternal( string $id, string $mode ): string {
1030 // Truncate overly-long IDs. This isn't an HTML limit, it's just
1031 // griefer protection. [T251506]
1032 $id = mb_substr( $id, 0, 1024 );
1033
1034 switch ( $mode ) {
1035 case 'html5':
1036 // html5 spec says ids must not have any of the following:
1037 // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE
1038 // In practice, in wikitext, only tab, LF, CR (and SPACE) are
1039 // possible using either Lua or html entities.
1040 $id = str_replace( [ "\t", "\n", "\f", "\r", " " ], '_', $id );
1041 break;
1042
1043 case 'legacy':
1044 // This corresponds to 'noninitial' mode of the former escapeId()
1045 static $replace = [
1046 '%3A' => ':',
1047 '%' => '.'
1048 ];
1049
1050 $id = urlencode( str_replace( ' ', '_', $id ) );
1051 $id = strtr( $id, $replace );
1052 break;
1053
1054 default:
1055 throw new InvalidArgumentException( "Invalid mode '$mode' passed to '" . __METHOD__ );
1056 }
1057
1058 return $id;
1059 }
1060
1068 private static function escapeIdReferenceListInternal( string $referenceString ): string {
1069 # Explode the space delimited list string into an array of tokens
1070 $references = preg_split( '/\s+/', "{$referenceString}", -1, PREG_SPLIT_NO_EMPTY );
1071
1072 # Escape each token as an id
1073 foreach ( $references as &$ref ) {
1074 $ref = self::escapeIdForAttribute( $ref );
1075 }
1076
1077 # Merge the array back to a space delimited list string
1078 # If the array is empty, the result will be an empty string ('')
1079 $referenceString = implode( ' ', $references );
1080
1081 return $referenceString;
1082 }
1083
1092 public static function escapeClass( string $class ): string {
1093 // Convert ugly stuff to underscores and kill underscores in ugly places
1094 return rtrim( preg_replace(
1095 [ '/(^[0-9\\-])|[\\x00-\\x20!"#$%&\'()*+,.\\/:;<=>?@[\\]^`{|}~]|\\xC2\\xA0/', '/_+/' ],
1096 '_',
1097 $class ), '_' );
1098 }
1099
1100 public static function escapeCombiningChar( string $html ): string {
1101 return strtr( $html, [
1102 "\u{0338}" => '&#x338;', # T387130
1103 ] );
1104 }
1105
1115 public static function escapeHtmlAllowEntities( string $html ): string {
1116 $html = self::decodeCharReferences( $html );
1117 # It seems wise to escape ' as well as ", as a matter of course. Can't
1118 # hurt. Use ENT_SUBSTITUTE so that incorrectly truncated multibyte characters
1119 # don't cause the entire string to disappear.
1120 $html = htmlspecialchars( $html, ENT_QUOTES | ENT_SUBSTITUTE );
1121 return self::escapeCombiningChar( $html );
1122 }
1123
1129 public static function decodeTagAttributes( string $text ): array {
1130 if ( trim( $text ) == '' ) {
1131 return [];
1132 }
1133
1134 $pairs = [];
1135 if ( !preg_match_all(
1136 self::getAttribsRegex(),
1137 $text,
1138 $pairs,
1139 PREG_SET_ORDER ) ) {
1140 return [];
1141 }
1142
1143 $attribs = [];
1144 foreach ( $pairs as $set ) {
1145 $attribute = strtolower( $set[1] );
1146
1147 // Filter attribute names with unacceptable characters
1148 if ( !preg_match( self::getAttribNameRegex(), $attribute ) ) {
1149 continue;
1150 }
1151
1152 $value = self::getTagAttributeCallback( $set );
1153
1154 // Normalize whitespace
1155 $value = preg_replace( '/[\t\r\n ]+/', ' ', $value );
1156 $value = trim( $value );
1157
1158 // Decode character references
1159 $attribs[$attribute] = self::decodeCharReferences( $value );
1160 }
1161 return $attribs;
1162 }
1163
1168 public static function safeEncodeTagAttributes( array $assoc_array ): string {
1169 $attribs = [];
1170 foreach ( $assoc_array as $attribute => $value ) {
1171 # convert numeric attribute names back to strings.
1172 $attribute = (string)$attribute;
1173 $encAttribute = htmlspecialchars( $attribute, ENT_COMPAT );
1174 $encValue = self::safeEncodeAttribute( $value );
1175
1176 $attribs[] = "$encAttribute=\"$encValue\"";
1177 }
1178 return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : '';
1179 }
1180
1185 private static function getTagAttributeCallback( array $set ): string {
1186 if ( isset( $set[5] ) ) {
1187 # No quotes.
1188 return $set[5];
1189 } elseif ( isset( $set[4] ) ) {
1190 # Single-quoted
1191 return $set[4];
1192 } elseif ( isset( $set[3] ) ) {
1193 # Double-quoted
1194 return $set[3];
1195 } elseif ( !isset( $set[2] ) ) {
1196 # In XHTML, attributes must have a value so return an empty string.
1197 # See "Empty attribute syntax",
1198 # https://www.w3.org/TR/html5/syntax.html#syntax-attribute-name
1199 return "";
1200 } else {
1201 throw new LogicException( "Tag conditions not met. This should never happen and is a bug." );
1202 }
1203 }
1204
1205 private static function normalizeWhitespace( string $text ): string {
1206 $normalized = preg_replace( '/[ \r\n\t]+/', ' ', $text );
1207 if ( $normalized === null ) {
1208 wfLogWarning( __METHOD__ . ': Failed to normalize whitespace: ' . preg_last_error() );
1209 return '';
1210 }
1211 return trim( $normalized );
1212 }
1213
1219 public static function normalizeSectionNameWhitespace( string $section ): string {
1220 $normalized = preg_replace( '/[ _]+/', ' ', $section );
1221 if ( $normalized === null ) {
1222 wfLogWarning( __METHOD__ . ': Failed to normalize whitespace: ' . preg_last_error() );
1223 return '';
1224 }
1225 return trim( $normalized );
1226 }
1227
1241 public static function normalizeCharReferences( string $text ): string {
1242 return preg_replace_callback(
1243 self::CHAR_REFS_REGEX,
1244 self::normalizeCharReferencesCallback( ... ),
1245 $text, -1, $count, PREG_UNMATCHED_AS_NULL
1246 );
1247 }
1248
1249 private static function normalizeCharReferencesCallback( array $matches ): string {
1250 $ret = null;
1251 if ( isset( $matches[1] ) ) {
1252 $ret = self::normalizeEntity( $matches[1] );
1253 } elseif ( isset( $matches[2] ) ) {
1254 $ret = self::decCharReference( $matches[2] );
1255 } elseif ( isset( $matches[3] ) ) {
1256 $ret = self::hexCharReference( $matches[3] );
1257 }
1258 if ( $ret === null ) {
1259 return htmlspecialchars( $matches[0], ENT_COMPAT );
1260 } else {
1261 return $ret;
1262 }
1263 }
1264
1275 private static function normalizeEntity( string $name ): string {
1276 if ( isset( self::MW_ENTITY_ALIASES[$name] ) ) {
1277 // Non-standard MediaWiki-specific entities
1278 return '&' . self::MW_ENTITY_ALIASES[$name];
1279 } elseif ( in_array( $name, [ 'lt;', 'gt;', 'amp;', 'quot;' ], true ) ) {
1280 // Keep these in word form
1281 return "&$name";
1282 } elseif ( isset( HTMLData::NAMED_ENTITY_TRANSLATION[$name] ) ) {
1283 // Beware: some entities expand to more than 1 codepoint
1284 return preg_replace_callback( '/./Ssu', static function ( $m ) {
1285 return '&#' . \UtfNormal\Utils::utf8ToCodepoint( $m[0] ) . ';';
1286 }, HTMLData::NAMED_ENTITY_TRANSLATION[$name] );
1287 } else {
1288 return "&amp;$name";
1289 }
1290 }
1291
1292 private static function decCharReference( string $codepoint ): ?string {
1293 # intval() will (safely) saturate at the maximum signed integer
1294 # value if $codepoint is too many digits
1295 $point = intval( $codepoint );
1296 if ( self::validateCodepoint( $point ) ) {
1297 return "&#$point;";
1298 } else {
1299 return null;
1300 }
1301 }
1302
1303 private static function hexCharReference( string $codepoint ): ?string {
1304 $point = hexdec( $codepoint );
1305 // hexdec() might return a float if the string is too long
1306 if ( is_int( $point ) && self::validateCodepoint( $point ) ) {
1307 return sprintf( '&#x%x;', $point );
1308 } else {
1309 return null;
1310 }
1311 }
1312
1317 private static function validateCodepoint( int $codepoint ): bool {
1318 # U+000C is valid in HTML5 but not allowed in XML.
1319 # U+000D is valid in XML but not allowed in HTML5.
1320 # U+007F - U+009F are disallowed in HTML5 (control characters).
1321 return $codepoint == 0x09
1322 || $codepoint == 0x0a
1323 || ( $codepoint >= 0x20 && $codepoint <= 0x7e )
1324 || ( $codepoint >= 0xa0 && $codepoint <= 0xd7ff )
1325 || ( $codepoint >= 0xe000 && $codepoint <= 0xfffd )
1326 || ( $codepoint >= 0x10000 && $codepoint <= 0x10ffff );
1327 }
1328
1333 public static function decodeCharReferences( string $text ): string {
1334 return preg_replace_callback(
1335 self::CHAR_REFS_REGEX,
1336 self::decodeCharReferencesCallback( ... ),
1337 $text, -1, $count, PREG_UNMATCHED_AS_NULL
1338 );
1339 }
1340
1351 public static function decodeCharReferencesAndNormalize( string $text ): string {
1352 $text = preg_replace_callback(
1353 self::CHAR_REFS_REGEX,
1354 self::decodeCharReferencesCallback( ... ),
1355 $text, -1, $count, PREG_UNMATCHED_AS_NULL
1356 );
1357
1358 if ( $count ) {
1359 return MediaWikiServices::getInstance()->getContentLanguage()->normalize( $text );
1360 } else {
1361 return $text;
1362 }
1363 }
1364
1365 private static function decodeCharReferencesCallback( array $matches ): string {
1366 if ( isset( $matches[1] ) ) {
1367 return self::decodeEntity( $matches[1] );
1368 } elseif ( isset( $matches[2] ) ) {
1369 // Value is user provided string and may exceed native int bounds.
1370 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1371 return self::decodeChar( @intval( $matches[2] ) );
1372 } elseif ( isset( $matches[3] ) ) {
1373 $point = hexdec( $matches[3] );
1374 // hexdec() might return a float if the string is too long
1375 if ( !is_int( $point ) ) {
1376 // Invalid character reference.
1377 return \UtfNormal\Constants::UTF8_REPLACEMENT;
1378 }
1379 return self::decodeChar( $point );
1380 }
1381 # Last case should be an ampersand by itself
1382 return $matches[0];
1383 }
1384
1390 private static function decodeChar( int $codepoint ): string {
1391 if ( self::validateCodepoint( $codepoint ) ) {
1392 return \UtfNormal\Utils::codepointToUtf8( $codepoint );
1393 } else {
1394 return \UtfNormal\Constants::UTF8_REPLACEMENT;
1395 }
1396 }
1397
1406 private static function decodeEntity( string $name ): string {
1407 // These are MediaWiki-specific entities, not in the HTML standard
1408 if ( isset( self::MW_ENTITY_ALIASES[$name] ) ) {
1409 $name = self::MW_ENTITY_ALIASES[$name];
1410 }
1411 $trans = HTMLData::NAMED_ENTITY_TRANSLATION[$name] ?? null;
1412 return $trans ?? "&$name";
1413 }
1414
1422 private static function attributesAllowedInternal( string $element ): array {
1423 $list = self::setupAttributesAllowedInternal();
1424 return $list[$element] ?? [];
1425 }
1426
1434 private static function setupAttributesAllowedInternal(): array {
1435 static $allowed;
1436
1437 if ( $allowed !== null ) {
1438 return $allowed;
1439 }
1440
1441 // For lookup efficiency flip each attributes array so the keys are
1442 // the valid attributes.
1443 $merge = static function ( $a, $b, $c = [] ) {
1444 return array_merge(
1445 $a,
1446 array_fill_keys( $b, true ),
1447 array_fill_keys( $c, true ) );
1448 };
1449 $common = $merge( [], [
1450 # HTML
1451 'id',
1452 'class',
1453 'style',
1454 'lang',
1455 'dir',
1456 'title',
1457 'tabindex',
1458
1459 # WAI-ARIA
1460 'aria-describedby',
1461 'aria-flowto',
1462 'aria-hidden',
1463 'aria-label',
1464 'aria-labelledby',
1465 'aria-level',
1466 'aria-owns',
1467 'role',
1468
1469 # RDFa
1470 # These attributes are specified in section 9 of
1471 # https://www.w3.org/TR/2008/REC-rdfa-syntax-20081014
1472 'about',
1473 'property',
1474 'resource',
1475 'datatype',
1476 'typeof',
1477
1478 # Microdata. These are specified by
1479 # https://html.spec.whatwg.org/multipage/microdata.html#the-microdata-model
1480 'itemid',
1481 'itemprop',
1482 'itemref',
1483 'itemscope',
1484 'itemtype',
1485 ] );
1486
1487 $block = $merge( $common, [ 'align' ] );
1488
1489 $tablealign = [ 'align', 'valign' ];
1490 $tablecell = [
1491 'abbr',
1492 'axis',
1493 'headers',
1494 'scope',
1495 'rowspan',
1496 'colspan',
1497 'nowrap', # deprecated
1498 'width', # deprecated
1499 'height', # deprecated
1500 'bgcolor', # deprecated
1501 ];
1502
1503 # HTML 5 section numbers refer to sections in HTML 5 standard describing the element.
1504 # Current revision: 2024-03-13 commit a187fec
1505 # See: https://html.spec.whatwg.org/multipage/
1506 # See: https://github.com/whatwg/html/commits
1507 #
1508 # HTML 4.01 section numbers refer to sections in HTML 4.01 standard describing the element.
1509 # See: https://www.w3.org/TR/html4/
1510 $allowed = [
1511 # HTML 5 section 4.2 Document metadata
1512 # https://html.spec.whatwg.org/multipage/semantics.html#document-metadata
1513
1514 # HTML 5 section 4.2.5, 4.2.4
1515 # meta and link are only permitted by internalRemoveHtmlTags when Microdata
1516 # is enabled so we don't bother adding a conditional to hide these.
1517 # Also meta and link are only valid in wikitext as Microdata elements
1518 # (ie: validateTag rejects tags missing the attributes needed for Microdata)
1519 # So we don't bother including $common attributes that have no purpose.
1520 'meta' => $merge( [], [ 'itemprop', 'content' ] ),
1521 'link' => $merge( [], [ 'itemprop', 'href', 'title' ] ),
1522
1523 # HTML 5 section 4.3 Sections
1524 # https://html.spec.whatwg.org/multipage/sections.html
1525
1526 # HTML 5 section 4.3.2, 4.3.3, 4.3.4, 4.3.5
1527 # 'article' => $common,
1528 # 'section' => $common,
1529 # 'nav' => $common,
1530 'aside' => $common,
1531
1532 # HTML 5 section 4.3.6
1533 # HTML 4.01 section 7.5.5
1534 'h1' => $block,
1535 'h2' => $block,
1536 'h3' => $block,
1537 'h4' => $block,
1538 'h5' => $block,
1539 'h6' => $block,
1540
1541 # HTML 5 section 4.3.7
1542 # 'hgroup' => $common,
1543
1544 # HTML 5 section 4.3.8, 4.3.9
1545 # 'header' => $common,
1546 # 'footer' => $common,
1547
1548 # HTML 5 section 4.3.10
1549 # HTML 4.01 section 7.5.6
1550 # 'address' => $common,
1551
1552 # HTML 5 section 4.4 Grouping content
1553 # https://html.spec.whatwg.org/multipage/grouping-content.html
1554
1555 # HTML 5 section 4.4.1
1556 # HTML 4.01 section 9.3.1
1557 'p' => $block,
1558
1559 # HTML 5 section 4.4.2
1560 # HTML 4.01 section 15.3
1561 'hr' => $merge( $common, [ 'width' ] ),
1562
1563 # HTML 5 section 4.4.3
1564 # HTML 4.01 section 9.3.4
1565 'pre' => $merge( $common, [ 'width' ] ),
1566
1567 # HTML 5 section 4.4.4
1568 # HTML 4.01 section 9.2.2
1569 'blockquote' => $merge( $common, [ 'cite' ] ),
1570
1571 # HTML 5 section 4.4.5, 4.4.6
1572 # HTML 4.01 section 10.2
1573 'ol' => $merge( $common, [ 'type', 'start', 'reversed' ] ),
1574 'ul' => $merge( $common, [ 'type' ] ),
1575
1576 # HTML 5 section 4.4.7
1577 # 'menu' => $merge( $common, [ 'type' ] ),
1578
1579 # HTML 5 section 4.4.8
1580 # HTML 4.01 section 10.2
1581 'li' => $merge( $common, [ 'type', 'value' ] ),
1582
1583 # HTML 5 section 4.4.9, 4.4.10, 4.4.11
1584 # HTML 4.01 section 10.3
1585 'dl' => $common,
1586 'dt' => $common,
1587 'dd' => $common,
1588
1589 # HTML 5 section 4.4.12, 4.4.13 (was section 4.5)
1590 'figure' => $common,
1591 'figcaption' => $common,
1592
1593 # HTML 5 section 4.4.14
1594 # 'main' => $common,
1595
1596 # HTML 5 section 4.4.15
1597 # 'search'
1598
1599 # HTML 5 section 4.4.16
1600 # HTML 4.01 section 7.5.4
1601 'div' => $block,
1602
1603 # HTML 5 section 4.5 Text-level semantics
1604 # https://html.spec.whatwg.org/multipage/text-level-semantics.html
1605
1606 # HTML 5 section 4.5.1
1607 # HTML 4.01 section 12.2
1608 # NOTE: <a> is not allowed directly, but this list of allowed
1609 # attributes is used from the Parser object
1610 # See: HTML 5 section 4.6 Links
1611 # https://html.spec.whatwg.org/multipage/links.html
1612 'a' => $merge( $common, [ 'href', 'rel', 'rev' ] ), # rel/rev esp. for RDFa
1613
1614 # HTML 5 section 4.5.2, 4.5.3
1615 # HTML 4.01 section 9.2.1
1616 'em' => $common,
1617 'strong' => $common,
1618
1619 # HTML 5 section 4.5.4
1620 # HTML 4.01 section 15.2.1
1621 'small' => $common,
1622
1623 # HTML 5 section 4.5.5
1624 # HTML 4.01 section 15.2.1
1625 's' => $common,
1626
1627 # HTML 5 section 4.5.6
1628 # HTML 4.01 section 9.2.1
1629 'cite' => $common,
1630
1631 # HTML 5 section 4.5.7
1632 # HTML 4.01 section 9.2.2
1633 'q' => $merge( $common, [ 'cite' ] ),
1634
1635 # HTML 5 section 4.5.8, 4.5.9
1636 # HTML 4.01 section 9.2.1
1637 'dfn' => $common,
1638 'abbr' => $common,
1639
1640 # HTML 5 section 4.5.10, 4.5.11, 4.5.12
1641 # HTML Ruby annotation text module, simple ruby only.
1642 # https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-ruby-element
1643 'ruby' => $common,
1644 'rt' => $common, # $merge( $common, [ 'rbspan' ] ),
1645 'rp' => $common,
1646
1647 # HTML 5 section 4.5.13, 4.5.14
1648 'data' => $merge( $common, [ 'value' ] ),
1649 'time' => $merge( $common, [ 'datetime' ] ),
1650
1651 # HTML 5 section 4.5.15, 4.5.16, 4.5.17, 4.5.18
1652 # HTML 4.01 section 9.2.1
1653 'code' => $common,
1654 'var' => $common,
1655 'samp' => $common,
1656 'kbd' => $common,
1657
1658 # HTML 5 section 4.5.19
1659 # HTML 4.01 section 9.2.3
1660 'sub' => $common,
1661 'sup' => $common,
1662
1663 # HTML 5 section 4.5.20, 4.5.21, 4.5.22, 4.5.23
1664 # HTML 4.01 section 15.2.1
1665 'i' => $common,
1666 'b' => $common,
1667 'u' => $common,
1668 'mark' => $common,
1669
1670 # HTML 5 section 4.5.24 (was section 4.6)
1671 'bdi' => $common,
1672
1673 # HTML 5 section 4.5.25
1674 # HTML 4.01 section 8.2.4
1675 'bdo' => $common,
1676
1677 # HTML 5 section 4.5.26
1678 # HTML 4.01 section 7.5.4
1679 'span' => $common,
1680
1681 # HTML 5 section 4.5.27
1682 # HTML 4.01 section 9.3.2
1683 'br' => $merge( $common, [ 'clear' ] ),
1684
1685 # HTML 5 section 4.5.28
1686 'wbr' => $common,
1687
1688 # HTML 5 section 4.7 Edits
1689 # https://html.spec.whatwg.org/multipage/edits.html
1690
1691 # HTML 5 section 4.7.1, 4.7.2
1692 # HTML 4.01 section 9.4
1693 'ins' => $merge( $common, [ 'cite', 'datetime' ] ),
1694 'del' => $merge( $common, [ 'cite', 'datetime' ] ),
1695
1696 # HTML 5 section 4.8 Embedded content
1697 # https://html.spec.whatwg.org/multipage/embedded-content.html
1698
1699 # HTML 5 section 4.8.1
1700 # 'picture'
1701
1702 # HTML 5 section 4.8.2, 4.8.3, 4.8.8, 4.8.9, 4.8.10
1703 # HTML 4.01 section 13.2
1704 # Not usually allowed, but may be used for extension-style hooks
1705 # such as <math> when it is rasterized
1706 'source' => $merge( $common, [ 'type', 'src' ] ),
1707 'img' => $merge( $common, [ 'alt', 'src', 'width', 'height', 'srcset' ] ),
1708 # Attributes for A/V tags added in T163583 / T133673
1709 'video' => $merge( $common, [ 'poster', 'controls', 'preload', 'width', 'height' ] ),
1710 'audio' => $merge( $common, [ 'controls', 'preload', 'width', 'height' ] ),
1711 'track' => $merge( $common, [ 'type', 'src', 'srclang', 'kind', 'label' ] ),
1712
1713 # HTML 5 section 4.8.12, 4.8.13
1714 # 'map'
1715 # 'area'
1716
1717 # HTML 5 section 4.8.15
1718 # MathML root element, where used for extensions
1719 # 'title' may not be 100% valid here; it's XHTML
1720 # https://www.w3.org/TR/REC-MathML/
1721 'math' => $merge( [], [ 'class', 'style', 'id', 'title' ] ),
1722
1723 # HTML 5 section 4.8.16
1724 # 'svg'
1725
1726 # HTML 5 section 4.9 Tabular data
1727 # https://html.spec.whatwg.org/multipage/tables.html
1728
1729 # HTML 5 section 4.9.1
1730 # HTML 4.01 section 11.2.1
1731 'table' => $merge(
1732 $common,
1733 [
1734 'summary', 'width', 'border', 'frame',
1735 'rules', 'cellspacing', 'cellpadding',
1736 'align', 'bgcolor',
1737 ]
1738 ),
1739
1740 # HTML 5 section 4.9.2
1741 # HTML 4.01 section 11.2.2
1742 'caption' => $block,
1743
1744 # HTML 5 section 4.9.3, 4.9.4
1745 # HTML 4.01 section 11.2.4
1746 'colgroup' => $merge( $common, [ 'span' ] ),
1747 'col' => $merge( $common, [ 'span' ] ),
1748
1749 # HTML 5 section 4.9.5, 4.9.6, 4.9.7
1750 # HTML 4.01 section 11.2.3
1751 'tbody' => $common,
1752 'thead' => $common,
1753 'tfoot' => $common,
1754
1755 # HTML 5 section 4.9.8
1756 # HTML 4.01 section 11.2.5
1757 'tr' => $merge( $common, [ 'bgcolor' ], $tablealign ),
1758
1759 # HTML 5 section 4.9.9, 4.9.10
1760 # HTML 4.01 section 11.2.6
1761 'td' => $merge( $common, $tablecell, $tablealign ),
1762 'th' => $merge( $common, $tablecell, $tablealign ),
1763
1764 # HTML 5 section 4.10 Forms
1765 # https://html.spec.whatwg.org/multipage/forms.html
1766 # https://html.spec.whatwg.org/multipage/input.html
1767 # https://html.spec.whatwg.org/multipage/form-elements.html
1768 # https://html.spec.whatwg.org/multipage/form-control-infrastructure.html
1769
1770 # HTML 5 section 4.10.3, 4.10.4
1771 # 'form'
1772 # 'label'
1773
1774 # HTML 5 section 4.10.5
1775 # 'input'
1776
1777 # HTML 5 section 4.10.6, 4.10.7, 4.10.8, 4.10.9, 4.10.10, 4.10.11, 4.10.12
1778 # 'button'
1779 # 'select'
1780 # 'datalist'
1781 # 'optgroup'
1782 # 'option'
1783 # 'textarea'
1784 # 'output'
1785
1786 # HTML 5 section 4.10.13, 4.10.14
1787 # 'progress' => $merge( $common, [ 'value', 'max' ] ),
1788 # 'meter' => $merge( $common, [ 'value', 'min', 'max', 'low', 'high', 'optimum' ] ),
1789
1790 # HTML 5 section 4.10.15, 4.10.14
1791 # 'fieldset'
1792 # 'legend'
1793
1794 # HTML 5 section 4.11 Interactive elements
1795 # https://html.spec.whatwg.org/multipage/interactive-elements.html
1796 # 4.11.1, 4.11.2
1797 # 'details' => $merge( $common, [ 'name', 'open' ] ),
1798 # 'summary' => $common,
1799
1800 # HTML 5 section 16 Obsolete features
1801 # https://html.spec.whatwg.org/multipage/obsolete.html#rb
1802
1803 # HTML 5 section 16.2 Non-conforming features
1804 # Elements that are entirely obsolete, and must not be used by authors
1805
1806 # HTML 4.01 section 9.2.1
1807 # Use 'abbr' instead.
1808 # 'acronym'
1809
1810 # HTML Ruby annotation text module, simple ruby only.
1811 # https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-ruby-element
1812 # Providing the ruby base directly inside the ruby element or using nested ruby elements
1813 # is sufficient.
1814 # 'rbc'
1815 'rb' => $common,
1816 'rtc' => $common,
1817
1818 # HTML 4.01 section 15.2.1
1819 # Use del instead if the element is marking an edit, otherwise use s instead.
1820 'strike' => $common,
1821
1822 # HTML 4.01 section 15.2.2
1823 # basefont
1824
1825 # HTML 4.01 section 15.2.1
1826 'big' => $common,
1827
1828 # HTML 4.01 section 7.5.4
1829 'center' => $common, # deprecated
1830
1831 # HTML 4.01 section 15.2.2
1832 'font' => $merge( $common, [ 'size', 'color', 'face' ] ),
1833
1834 # HTML 4.01 section 15.2.1
1835 'tt' => $common,
1836 ];
1837
1838 return $allowed;
1839 }
1840
1852 public static function stripAllTags( string $html ): string {
1853 // Use RemexHtml to tokenize $html and extract the text
1854 $handler = new RemexStripTagHandler;
1855 $tokenizer = new RemexTokenizer( $handler, $html, [
1856 'ignoreErrors' => true,
1857 // don't ignore char refs, we want them to be decoded
1858 'ignoreNulls' => true,
1859 'skipPreprocess' => true,
1860 // We ignore all attributes, don't bother to parse them
1861 'lazyAttributes' => true,
1862 ] );
1863 $tokenizer->execute();
1864 return self::normalizeWhitespace( $handler->getResult() );
1865 }
1866
1877 public static function hackDocType(): string {
1878 $out = "<!DOCTYPE html [\n";
1879 foreach ( HTMLData::NAMED_ENTITY_TRANSLATION as $entity => $translation ) {
1880 if ( substr( $entity, -1 ) !== ';' ) {
1881 // Some HTML entities omit the trailing semicolon;
1882 // wikitext does not permit these.
1883 continue;
1884 }
1885 $name = substr( $entity, 0, -1 );
1886 $expansion = self::normalizeEntity( $entity );
1887 if ( $entity === $expansion ) {
1888 // Skip &lt; &gt; etc
1889 continue;
1890 }
1891 $out .= "<!ENTITY $name \"$expansion\">";
1892 }
1893 $out .= "]>\n";
1894 return $out;
1895 }
1896
1901 private static function stripIDNs( string $host ): string {
1902 return preg_replace( self::IDN_RE_G, '', $host );
1903 }
1904
1905 public static function cleanUrl( string $url ): string {
1906 # Normalize any HTML entities in input. They will be
1907 # re-escaped by makeExternalLink().
1908 $url = self::decodeCharReferences( $url );
1909
1910 # Escape any control characters introduced by the above step
1911 $url = preg_replace_callback( '/[\][<>"\\x00-\\x20\\x7F\|]+/',
1912 static fn ( $m ) => urlencode( $m[0] ), $url );
1913
1914 # Validate hostname portion
1915 $matches = [];
1916 if ( preg_match( '!^([^:]+:)(//[^/]+)?(.*)$!iD', $url, $matches ) ) {
1917 [ /* $whole */, $protocol, $host, $rest ] = $matches;
1918
1919 // Characters that will be ignored in IDNs.
1920 // https://datatracker.ietf.org/doc/html/rfc8264#section-9.13
1921 // https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
1922 // Strip them before further processing so deny lists and such work.
1923 $host = self::stripIDNs( $host );
1924
1925 // IPv6 host names are bracketed with []. Url-decode these.
1926 if ( str_starts_with( $host, "//%5B" ) &&
1927 preg_match( '!^//%5B([0-9A-Fa-f:.]+)%5D((:\d+)?)$!', $host, $matches )
1928 ) {
1929 $host = '//[' . $matches[1] . ']' . $matches[2];
1930 }
1931
1932 // @todo FIXME: Validate hostnames here
1933
1934 return $protocol . $host . $rest;
1935 } else {
1936 return $url;
1937 }
1938 }
1939
1968 public static function validateEmail( string $addr ): bool {
1969 $result = null;
1970 // TODO This method should be non-static, and have a HookRunner injected
1971 $hookRunner = new HookRunner( MediaWikiServices::getInstance()->getHookContainer() );
1972 if ( !$hookRunner->onIsValidEmailAddr( $addr, $result ) ) {
1973 return $result;
1974 }
1975
1976 // Please note strings below are enclosed in brackets [], this make the
1977 // hyphen "-" a range indicator. Hence it is double backslashed below.
1978 // See T28948
1979 $rfc5322_atext = "a-z0-9!#$%&'*+\\-\/=?^_`{|}~";
1980 $rfc1034_ldh_str = "a-z0-9\\-";
1981
1982 $html5_email_regexp = "/
1983 ^ # start of string
1984 [$rfc5322_atext\\.]+ # user part which is liberal :p
1985 @ # 'apostrophe'
1986 [$rfc1034_ldh_str]+ # First domain part
1987 (\\.[$rfc1034_ldh_str]+)* # Following part prefixed with a dot
1988 $ # End of string
1989 /ix"; // case Insensitive, eXtended
1990
1991 return (bool)preg_match( $html5_email_regexp, $addr );
1992 }
1993}
1994
1996class_alias( Sanitizer::class, 'Sanitizer' );
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Service locator for MediaWiki core services.
Helper class for Sanitizer::removeSomeTags().
Helper class for Sanitizer::stripAllTags().
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:34
static validateTagAttributes(array $attribs, string $element)
Take an array of attribute names and values and normalize or discard illegal values for the given ele...
static stripAllTags(string $html)
Take a fragment of (potentially invalid) HTML and return a version with any tags removed,...
const ID_FALLBACK
Tells escapeUrlForHtml() to encode the ID using the fallback encoding, or return false if no fallback...
Definition Sanitizer.php:90
static normalizeCss(string $value)
Normalize CSS into a format we can easily search for hostile input.
static validateAttributes(array $attribs, array $allowed)
Take an array of attribute names and values and normalize or discard illegal values.
static escapeIdForAttribute(string $id, int $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
static normalizeCharReferences(string $text)
Ensure that any entities and character references are legal for XML and XHTML specifically.
static mergeAttributes(array $a, array $b)
Merge two sets of HTML attributes.
static checkCss( $value)
Pick apart some CSS and check it for forbidden or unsafe structures.
static escapeClass(string $class)
Given a value, escape it so that it can be used as a CSS class and return it.
static removeHTMLcomments(string $text)
Remove '', and everything between.
static getRecognizedTagData(array $extratags=[], array $removetags=[])
Return the various lists of recognized tags.
const ID_PRIMARY
Tells escapeUrlForHtml() to encode the ID using the wiki's primary encoding.
Definition Sanitizer.php:82
static safeEncodeAttribute(string $text)
Encode an attribute value for HTML tags, with extra armoring against further wiki processing.
static escapeCombiningChar(string $html)
static hackDocType()
Hack up a private DOCTYPE with HTML's standard entity declarations.
static decodeCharReferencesAndNormalize(string $text)
Decode any character references, numeric or named entities, in the next and normalize the resulting s...
static cleanUrl(string $url)
static internalRemoveHtmlTags(string $text, ?callable $processCallback=null, $args=[], array $extratags=[], array $removetags=[])
Cleans up HTML, removes dangerous tags and attributes, and removes HTML comments; BEWARE there may be...
static fixTagAttributes(string $text, string $element, bool $sorted=false)
Take a tag soup fragment listing an HTML element's attributes and normalize it to well-formed XML,...
static escapeIdForLink(string $id)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid URL...
static normalizeSectionNameWhitespace(string $section)
Normalizes whitespace in a section name, such as might be returned by Parser::stripSectionName(),...
static armorFrenchSpaces(string $text, string $space='&#160;')
Armor French spaces with a replacement character.
static validateEmail(string $addr)
Does a string look like an e-mail address?
static escapeIdForExternalInterwiki(string $id)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid URL...
static isReservedDataAttribute(string $attr)
Given an attribute name, checks whether it is a reserved data attribute (such as data-mw-foo) which i...
static encodeAttribute(string $text)
Encode an attribute value for HTML output.
static removeSomeTags(string $text, array $options=[])
Cleans up HTML, removes dangerous tags and attributes, and removes HTML comments; the result will alw...
static decodeCharReferences(string $text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
static escapeHtmlAllowEntities(string $html)
Given HTML input, escape with htmlspecialchars but un-escape entities.
A collection of static methods to play with strings.
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'CodeHighlighter',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'autocreateaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, 'logout' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], 'managesessions' => [ 'logout' => 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', 'managesessions' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: 'https: 'git@github\\.com:(.*?)(\\.git)?' => 'https: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => true, 'mw-edited-other-users-css' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchstarPopover' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\RecentChanges\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'RestModuleOverrides' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'RestModuleOverrides' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'RestModuleOverrides' => 'array_replace_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'mode' => [ 'type' => 'string', ], ], 'required' => [ 'mode', ], ], ], '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.', ],]
$wgFragmentMode
Config variable stub for the FragmentMode setting, for use by phpdoc and IDEs.
$wgExternalInterwikiFragmentMode
Config variable stub for the ExternalInterwikiFragmentMode setting, for use by phpdoc and IDEs.