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