Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
20.90% covered (danger)
20.90%
14 / 67
0.00% covered (danger)
0.00%
0 / 27
CRAP
0.00% covered (danger)
0.00%
0 / 1
MainConfigSchema
20.90% covered (danger)
20.90%
14 / 67
0.00% covered (danger)
0.00%
0 / 27
1140.45
0.00% covered (danger)
0.00%
0 / 1
 listDefaultValues
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
5.15
 getDefaultValue
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 getDefaultUsePathInfo
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 getDefaultScript
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultLoadScript
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultRestPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultStylePath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultLocalStylePath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultExtensionAssetsPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultArticlePath
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultUploadPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultUploadDirectory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultFileCacheDirectory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultLogo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultDeletedDirectory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultLocalFileRepo
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 getDefaultShowEXIF
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultSharedPrefix
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultSharedSchema
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultDBerrorLogTZ
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultLocaltimezone
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultLocalTZoffset
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultResourceBasePath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultMetaNamespace
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultCookieSecure
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultCookiePrefix
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
30
 getDefaultReadOnlyFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * This file contains schema declarations for all configuration variables
4 * known to MediaWiki core.
5 *
6 * @file
7 * @ingroup Config
8 */
9
10// phpcs:disable Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase
11// phpcs:disable Generic.Files.LineLength.TooLong
12namespace MediaWiki;
13
14use AssembleUploadChunksJob;
15use BlockLogFormatter;
16use CategoryMembershipChangeJob;
17use CdnPurgeJob;
18use ContentModelLogFormatter;
19use DateTime;
20use DateTimeZone;
21use DeleteLinksJob;
22use DeleteLogFormatter;
23use DeletePageJob;
24use DoubleRedirectJob;
25use EmaillingJob;
26use EnotifNotifyJob;
27use Generator;
28use HTMLCacheUpdateJob;
29use ImportLogFormatter;
30use InvalidArgumentException;
31use JobQueueDB;
32use LocalisationCache;
33use LocalRepo;
34use LogFormatter;
35use MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider;
36use MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider;
37use MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider;
38use MediaWiki\Auth\PasswordAuthenticationRequest;
39use MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider;
40use MediaWiki\Auth\TemporaryPasswordAuthenticationRequest;
41use MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider;
42use MediaWiki\Auth\ThrottlePreAuthenticationProvider;
43use MediaWiki\Content\CssContentHandler;
44use MediaWiki\Content\FallbackContentHandler;
45use MediaWiki\Content\JavaScriptContentHandler;
46use MediaWiki\Content\JsonContentHandler;
47use MediaWiki\Content\TextContentHandler;
48use MediaWiki\Content\WikitextContentHandler;
49use MediaWiki\Deferred\SiteStatsUpdate;
50use MediaWiki\Password\Argon2Password;
51use MediaWiki\Password\BcryptPassword;
52use MediaWiki\Password\LayeredParameterizedPassword;
53use MediaWiki\Password\MWOldPassword;
54use MediaWiki\Password\MWSaltedPassword;
55use MediaWiki\Password\PasswordPolicyChecks;
56use MediaWiki\Password\Pbkdf2PasswordUsingOpenSSL;
57use MediaWiki\Permissions\GrantsInfo;
58use MediaWiki\RCFeed\RedisPubSubFeedEngine;
59use MediaWiki\RCFeed\UDPRCFeedEngine;
60use MediaWiki\RenameUser\RenameUserJob;
61use MediaWiki\Request\WebRequest;
62use MediaWiki\Settings\Source\JsonSchemaTrait;
63use MediaWiki\Site\MediaWikiSite;
64use MediaWiki\Storage\SqlBlobStore;
65use MediaWiki\Title\NamespaceInfo;
66use MediaWiki\User\CentralId\LocalIdLookup;
67use MediaWiki\User\Registration\LocalUserRegistrationProvider;
68use MediaWiki\Watchlist\ActivityUpdateJob;
69use MediaWiki\Watchlist\ClearUserWatchlistJob;
70use MediaWiki\Watchlist\ClearWatchlistNotificationsJob;
71use MediaWiki\Watchlist\WatchlistExpiryJob;
72use MergeLogFormatter;
73use MoveLogFormatter;
74use NullJob;
75use ParsoidCachePrewarmJob;
76use PatrolLogFormatter;
77use ProtectLogFormatter;
78use PublishStashedFileJob;
79use RecentChangesUpdateJob;
80use ReflectionClass;
81use RefreshLinksJob;
82use RenameuserLogFormatter;
83use RevertedTagUpdateJob;
84use RightsLogFormatter;
85use SqlBagOStuff;
86use TagLogFormatter;
87use ThumbnailRenderJob;
88use UploadFromUrlJob;
89use UploadLogFormatter;
90use UserEditCountInitJob;
91use UserGroupExpiryJob;
92use UserOptionsUpdateJob;
93use Wikimedia\EventRelayer\EventRelayerNull;
94use Wikimedia\ObjectCache\APCUBagOStuff;
95use Wikimedia\ObjectCache\BagOStuff;
96use Wikimedia\ObjectCache\EmptyBagOStuff;
97use Wikimedia\ObjectCache\HashBagOStuff;
98use Wikimedia\ObjectCache\MemcachedPeclBagOStuff;
99use Wikimedia\ObjectCache\MemcachedPhpBagOStuff;
100
101/**
102 * This class contains schema declarations for all configuration variables
103 * known to MediaWiki core. The schema definitions follow the JSON Schema
104 * specification.
105 *
106 * @see https://json-schema.org/learn/getting-started-step-by-step.html
107 * @see https://json-schema.org/understanding-json-schema/
108 *
109 * The following JSON schema keys are used by MediaWiki:
110 * - default: the configuration variable's default value.
111 * - type: identifies the allowed value type or types. In addition to JSON Schema types,
112 *         PHPDoc style type definitions are supported for convenience.
113 *         Note that 'array' must not be used for associative arrays.
114 *         To avoid confusion, use 'list' for sequential arrays and 'map' for associative arrays
115 *         with uniform values. The 'object' type should be used for structures that have a known
116 *         set of meaningful properties, especially if each property may have a different kind
117 *         of value.
118 *         See {@link \MediaWiki\Settings\Source\JsonTypeHelper} for details.
119 *
120 * The following additional keys are used by MediaWiki:
121 * - mergeStrategy: see the {@link \MediaWiki\Settings\Config\MergeStrategy}.
122 * - dynamicDefault: Specified a callback that computes the effective default at runtime, based
123 *   on the value of other config variables or on the system environment.
124 *   See {@link \MediaWiki\Settings\Source\ReflectionSchemaSource}
125 *   and {@link \MediaWiki\Settings\DynamicDefaultValues} for details.
126 *
127 * @note After changing this file, run maintenance/generateConfigSchema.php to update
128 *       all the files derived from the information in MainConfigSchema.
129 *
130 * @since 1.39
131 */
132class MainConfigSchema {
133    use JsonSchemaTrait;
134
135    /**
136     * Returns a generator for iterating over all config settings and their default values.
137     * The primary use of this method is to import default values into local scope.
138     * @code
139     *   foreach ( MainConfigSchema::listDefaultValues( 'wg' ) as $var => $value ) {
140     *       $$var = $value;
141     *   }
142     * @endcode
143     *
144     * There should be no reason for application logic to do this.
145     *
146     * @note This method is relatively slow, it should not be used by
147     *       performance critical code. Application logic should generally
148     *       use ConfigSchema instead
149     *
150     * @param string $prefix A prefix to prepend to each setting name.
151     *        Typically, this will be "wg" when constructing global
152     *        variable names.
153     *
154     * @return Generator<string,mixed> $settingName => $defaultValue
155     */
156    public static function listDefaultValues( string $prefix = '' ): Generator {
157        $class = new ReflectionClass( self::class );
158        foreach ( $class->getReflectionConstants() as $const ) {
159            if ( !$const->isPublic() ) {
160                continue;
161            }
162
163            $value = $const->getValue();
164
165            if ( !is_array( $value ) ) {
166                // Just in case we end up having some other kind of constant on this class.
167                continue;
168            }
169
170            if ( isset( $value['obsolete'] ) ) {
171                continue;
172            }
173
174            $name = $const->getName();
175            yield "$prefix$name" => self::getDefaultFromJsonSchema( $value );
176        }
177    }
178
179    /**
180     * Returns the default value of the given config setting.
181     *
182     * @note This method is relatively slow, it should not be used by
183     *       performance critical code. Application logic should generally
184     *       use ConfigSchema instead
185     *
186     * @param string $name The config setting name.
187     *
188     * @return mixed The given config setting's default value, or null
189     *         if no default value is specified in the schema.
190     */
191    public static function getDefaultValue( string $name ) {
192        $class = new ReflectionClass( self::class );
193        if ( !$class->hasConstant( $name ) ) {
194            throw new InvalidArgumentException( "Unknown setting: $name" );
195        }
196        $value = $class->getConstant( $name );
197
198        if ( !is_array( $value ) ) {
199            // Might happen if we end up having other kinds of constants on this class.
200            throw new InvalidArgumentException( "Unknown setting: $name" );
201        }
202
203        return self::getDefaultFromJsonSchema( $value );
204    }
205
206    /***************************************************************************/
207    /**
208     * Registry of factory functions to create config objects:
209     * The 'main' key must be set, and the value should be a valid
210     * callable.
211     *
212     * @since 1.23
213     */
214    public const ConfigRegistry = [
215        'default' => [
216            'main' => 'GlobalVarConfig::newInstance',
217        ],
218        'type' => 'map',
219    ];
220
221    /**
222     * Name of the site. It must be changed in LocalSettings.php
223     */
224    public const Sitename = [
225        'default' => 'MediaWiki',
226    ];
227
228    /***************************************************************************/
229    // region   Server URLs and file paths
230    /** @name   Server URLs and file paths
231     *
232     * In this section, a "path" is usually a host-relative URL, i.e. a URL without
233     * the host part, that starts with a slash. In most cases a full URL is also
234     * acceptable. A "directory" is a local file path.
235     *
236     * In both paths and directories, trailing slashes should not be included.
237     */
238
239    /**
240     * URL of the server.
241     *
242     * **Example:**
243     * ```
244     * $wgServer = 'http://example.com';
245     * ```
246     *
247     * This must be set in LocalSettings.php. The MediaWiki installer does this
248     * automatically since 1.18.
249     *
250     * If you want to use protocol-relative URLs on your wiki, set this to a
251     * protocol-relative URL like '//example.com' and set $wgCanonicalServer
252     * to a fully qualified URL.
253     */
254    public const Server = [
255        'default' => false,
256    ];
257
258    /**
259     * Canonical URL of the server, to use in IRC feeds and notification e-mails.
260     *
261     * Must be fully qualified, even if $wgServer is protocol-relative.
262     *
263     * Defaults to $wgServer, expanded to a fully qualified http:// URL if needed.
264     *
265     * @since 1.18
266     */
267    public const CanonicalServer = [
268        'default' => false,
269    ];
270
271    /**
272     * Server name. This is automatically computed by parsing the bare
273     * hostname out of $wgCanonicalServer. It should not be customized.
274     *
275     * @since 1.24
276     */
277    public const ServerName = [
278        'default' => false,
279    ];
280
281    /**
282     * When the wiki is running behind a proxy and this is set to true, assumes that the proxy
283     * exposes the wiki on the standard ports (443 for https and 80 for http).
284     *
285     * @since 1.26
286     */
287    public const AssumeProxiesUseDefaultProtocolPorts = [
288        'default' => true,
289        'type' => 'boolean',
290    ];
291
292    /**
293     * For installations where the canonical server is HTTP but HTTPS is optionally
294     * supported, you can specify a non-standard HTTPS port here. $wgServer should
295     * be a protocol-relative URL.
296     *
297     * If HTTPS is always used, just specify the port number in $wgServer.
298     *
299     * @see https://phabricator.wikimedia.org/T67184
300     * @since 1.24
301     */
302    public const HttpsPort = [
303        'default' => 443,
304    ];
305
306    /**
307     * If this is true, when an insecure HTTP request is received, always redirect
308     * to HTTPS. This overrides and disables the preferhttps user preference, and it
309     * overrides $wgSecureLogin.
310     *
311     * $wgServer may be either https or protocol-relative. If $wgServer starts with
312     * "http://", an exception will be thrown.
313     *
314     * If a reverse proxy or CDN is used to forward requests from HTTPS to HTTP,
315     * the request header "X-Forwarded-Proto: https" should be sent to suppress
316     * the redirect.
317     *
318     * In addition to setting this to true, for optimal security, the web server
319     * should also be configured to send Strict-Transport-Security response headers.
320     *
321     * @since 1.35
322     */
323    public const ForceHTTPS = [
324        'default' => false,
325        'type' => 'boolean',
326    ];
327
328    /**
329     * The path we should point to.
330     *
331     * It might be a virtual path in case with use apache mod_rewrite for example.
332     *
333     * This *needs* to be set correctly.
334     *
335     * Other paths will be set to defaults based on it unless they are directly
336     * set in LocalSettings.php
337     */
338    public const ScriptPath = [
339        'default' => '/wiki',
340    ];
341
342    /**
343     * Whether to support URLs like index.php/Page_title.
344     * The effective default value is determined at runtime:
345     * it will be enabled in environments where it is expected to be safe.
346     *
347     * Override this to false if $_SERVER['PATH_INFO'] contains unexpectedly
348     * incorrect garbage, or to true if it is really correct.
349     *
350     * The default $wgArticlePath will be set based on this value at runtime, but if
351     * you have customized it, having this incorrectly set to true can cause
352     * redirect loops when "pretty URLs" are used.
353     *
354     * @since 1.2.1
355     */
356    public const UsePathInfo = [
357        'dynamicDefault' => true,
358    ];
359
360    /**
361     * @return bool
362     */
363    public static function getDefaultUsePathInfo(): bool {
364        // These often break when PHP is set up in CGI mode.
365        // PATH_INFO *may* be correct if cgi.fix_pathinfo is set, but then again it may not;
366        // lighttpd converts incoming path data to lowercase on systems
367        // with case-insensitive filesystems, and there have been reports of
368        // problems on Apache as well.
369        return !str_contains( PHP_SAPI, 'cgi' ) && !str_contains( PHP_SAPI, 'apache2filter' ) &&
370            !str_contains( PHP_SAPI, 'isapi' );
371    }
372
373    /**
374     * The URL path to index.php.
375     *
376     * Defaults to "{$wgScriptPath}/index.php".
377     */
378    public const Script = [
379        'default' => false,
380        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
381    ];
382
383    /**
384     * @param mixed $scriptPath Value of ScriptPath
385     * @return string
386     */
387    public static function getDefaultScript( $scriptPath ): string {
388        return "$scriptPath/index.php";
389    }
390
391    /**
392     * The URL path to load.php.
393     *
394     * Defaults to "{$wgScriptPath}/load.php".
395     *
396     * @since 1.17
397     */
398    public const LoadScript = [
399        'default' => false,
400        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
401    ];
402
403    /**
404     * @param mixed $scriptPath Value of ScriptPath
405     * @return string
406     */
407    public static function getDefaultLoadScript( $scriptPath ): string {
408        return "$scriptPath/load.php";
409    }
410
411    /**
412     * The URL path to the REST API.
413     * Defaults to "{$wgScriptPath}/rest.php"
414     *
415     * @since 1.34
416     */
417    public const RestPath = [
418        'default' => false,
419        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
420    ];
421
422    /**
423     * @param mixed $scriptPath Value of ScriptPath
424     * @return string
425     */
426    public static function getDefaultRestPath( $scriptPath ): string {
427        return "$scriptPath/rest.php";
428    }
429
430    /**
431     * The URL path of the skins directory.
432     *
433     * Defaults to "{$wgResourceBasePath}/skins".
434     *
435     * @since 1.3
436     */
437    public const StylePath = [
438        'default' => false,
439        'dynamicDefault' => [ 'use' => [ 'ResourceBasePath' ] ]
440    ];
441
442    /**
443     * @param mixed $resourceBasePath Value of ResourceBasePath
444     * @return string
445     */
446    public static function getDefaultStylePath( $resourceBasePath ): string {
447        return "$resourceBasePath/skins";
448    }
449
450    /**
451     * The URL path of the skins directory. Should not point to an external domain.
452     *
453     * Defaults to "{$wgScriptPath}/skins".
454     *
455     * @since 1.17
456     */
457    public const LocalStylePath = [
458        'default' => false,
459        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
460    ];
461
462    /**
463     * @param mixed $scriptPath Value of ScriptPath
464     * @return string
465     */
466    public static function getDefaultLocalStylePath( $scriptPath ): string {
467        // Avoid ResourceBasePath here since that may point to a different domain (e.g. CDN)
468        return "$scriptPath/skins";
469    }
470
471    /**
472     * The URL path of the extensions directory.
473     *
474     * Defaults to "{$wgResourceBasePath}/extensions".
475     *
476     * @since 1.16
477     */
478    public const ExtensionAssetsPath = [
479        'default' => false,
480        'dynamicDefault' => [ 'use' => [ 'ResourceBasePath' ] ]
481    ];
482
483    /**
484     * @param mixed $resourceBasePath Value of ResourceBasePath
485     * @return string
486     */
487    public static function getDefaultExtensionAssetsPath( $resourceBasePath ): string {
488        return "$resourceBasePath/extensions";
489    }
490
491    /**
492     * Extensions directory in the file system.
493     *
494     * @note Set to "{$IP}/extensions" by Setup.php before loading local settings.
495     * @note this configuration variable is used to locate extensions while loading settings.
496     * @since 1.25
497     */
498    public const ExtensionDirectory = [
499        'default' => null,
500        'type' => '?string',
501    ];
502
503    /**
504     * Skins directory in the file system.
505     *
506     * @note Set to "{$IP}/skins" by Setup.php before loading local settings.
507     * @note this configuration variable is used to locate skins while loading settings.
508     * @since 1.3
509     */
510    public const StyleDirectory = [
511        'default' => null,
512        'type' => '?string',
513    ];
514
515    /**
516     * Absolute filesystem path of the root directory of the MediaWiki installation.
517     * The MW_INSTALL_PATH environment variable can be used to set this.
518     *
519     * @note Automatically set in Setup.php before loading local settings.
520     * @note Do not modify in settings files! Must remain equal to the MW_INSTALL_PATH constant
521     *       defined in Setup.php.
522     * @since 1.38
523     */
524    public const BaseDirectory = [
525        'default' => null,
526    ];
527
528    /**
529     * The URL path for primary article page views. This path should contain $1,
530     * which is replaced by the article title.
531     *
532     * Defaults to "{$wgScript}/$1" or "{$wgScript}?title=$1",
533     * depending on $wgUsePathInfo.
534     */
535    public const ArticlePath = [
536        'default' => false,
537        'dynamicDefault' => [ 'use' => [ 'Script', 'UsePathInfo' ] ]
538    ];
539
540    /**
541     * @param string $script Value of Script
542     * @param mixed $usePathInfo Value of UsePathInfo
543     * @return string
544     */
545    public static function getDefaultArticlePath( string $script, $usePathInfo ): string {
546        if ( $usePathInfo ) {
547            return "$script/$1";
548        }
549        return "$script?title=$1";
550    }
551
552    /**
553     * The URL path for the images directory.
554     *
555     * Defaults to "{$wgScriptPath}/images".
556     */
557    public const UploadPath = [
558        'default' => false,
559        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
560    ];
561
562    /**
563     * @param mixed $scriptPath Value of ScriptPath
564     * @return string
565     */
566    public static function getDefaultUploadPath( $scriptPath ): string {
567        return "$scriptPath/images";
568    }
569
570    /**
571     * The base path for img_auth.php. This is used to interpret the request URL
572     * for requests to img_auth.php that do not match the base upload path. If
573     * false, "{$wgScriptPath}/img_auth.php" is used.
574     *
575     * Normally, requests to img_auth.php have a REQUEST_URI which matches
576     * $wgUploadPath, and in that case, setting this should not be necessary.
577     * This variable is used in case img_auth.php is accessed via a different path
578     * than $wgUploadPath.
579     *
580     * @since 1.35
581     */
582    public const ImgAuthPath = [
583        'default' => false,
584    ];
585
586    /**
587     * The base path for thumb_handler.php. This is used to interpret the request URL
588     * for requests to thumb_handler.php that do not match the base upload path.
589     *
590     * @since 1.36
591     */
592    public const ThumbPath = [
593        'default' => false,
594    ];
595
596    /**
597     * The filesystem path of the images directory. Defaults to "{$IP}/images".
598     */
599    public const UploadDirectory = [
600        'default' => false,
601        'dynamicDefault' => [ 'use' => [ 'BaseDirectory' ] ]
602    ];
603
604    /**
605     * @param mixed $baseDirectory Value of BaseDirectory
606     * @return string
607     */
608    public static function getDefaultUploadDirectory( $baseDirectory ): string {
609        return "$baseDirectory/images";
610    }
611
612    /**
613     * Directory where the cached page will be saved.
614     *
615     * Defaults to "{$wgUploadDirectory}/cache".
616     */
617    public const FileCacheDirectory = [
618        'default' => false,
619        'dynamicDefault' => [ 'use' => [ 'UploadDirectory' ] ]
620    ];
621
622    /**
623     * @param mixed $uploadDirectory Value of UploadDirectory
624     * @return string
625     */
626    public static function getDefaultFileCacheDirectory( $uploadDirectory ): string {
627        return "$uploadDirectory/cache";
628    }
629
630    /**
631     * The URL path of the wiki logo. The logo size should be 135x135 pixels.
632     *
633     * Defaults to "$wgResourceBasePath/resources/assets/change-your-logo.svg".
634     * Developers should retrieve this logo (and other variants) using
635     * the static function MediaWiki\ResourceLoader\SkinModule::getAvailableLogos
636     * Ignored if $wgLogos is set.
637     */
638    public const Logo = [
639        'default' => false,
640        'dynamicDefault' => [ 'use' => [ 'ResourceBasePath' ] ]
641    ];
642
643    /**
644     * @param mixed $resourceBasePath Value of ResourceBasePath
645     * @return string
646     */
647    public static function getDefaultLogo( $resourceBasePath ): string {
648        return "$resourceBasePath/resources/assets/change-your-logo.svg";
649    }
650
651    /**
652     * Specification for different versions of the wiki logo.
653     *
654     * This is an array which should have the following k/v pairs:
655     * All path values can be either absolute or relative URIs
656     *
657     * The `1x` key is a path to the 1x version of square logo (should be 135x135 pixels)
658     * The `1.5x` key is a path to the 1.5x version of square logo
659     * The `2x` key is a path to the 2x version of square logo
660     * The `svg` key is a path to the svg version of square logo
661     * The `icon` key is a path to the version of the logo without wordmark and tagline
662     * The `wordmark` key may be null or an array with the following fields
663     *  - `src` path to wordmark version
664     *  - `1x` path to svg wordmark version (if you want to
665     *     support browsers with SVG support with an SVG logo)
666     *  - `width` width of the logo in pixels
667     *  - `height` height of the logo in pixels
668     * The `tagline` key may be null or array with the following fields
669     *  - `src` path to tagline image
670     *  - `width` width of the tagline in pixels
671     *  - `height` height of the tagline in pixels
672     *
673     *
674     * @par Example:
675     * @code
676     * $wgLogos = [
677     *    '1x' => 'path/to/1x_version.png',
678     *    '1.5x' => 'path/to/1.5x_version.png',
679     *    '2x' => 'path/to/2x_version.png',
680     *    'svg' => 'path/to/svg_version.svg',
681     *    'icon' => 'path/to/icon.png',
682     *    'wordmark' => [
683     *      'src' => 'path/to/wordmark_version.png',
684     *      '1x' => 'path/to/wordmark_version.svg',
685     *      'width' => 135,
686     *      'height' => 20,
687     *    ],
688     *    'tagline' => [
689     *      'src' => 'path/to/tagline_version.png',
690     *      'width' => 135,
691     *      'height' => 15,
692     *    ]
693     * ];
694     * @endcode
695     *
696     * Defaults to [ "1x" => $wgLogo ],
697     *   or [ "1x" => "$wgResourceBasePath/resources/assets/change-your-logo.svg" ] if $wgLogo is not set.
698     * @since 1.35
699     */
700    public const Logos = [
701        'default' => false,
702        'type' => 'map|false',
703    ];
704
705    /**
706     * The URL path of the icon.
707     *
708     * @since 1.6
709     */
710    public const Favicon = [
711        'default' => '/favicon.ico',
712    ];
713
714    /**
715     * The URL path of the icon for iPhone and iPod Touch web app bookmarks.
716     *
717     * Defaults to no icon.
718     *
719     * @since 1.12
720     */
721    public const AppleTouchIcon = [
722        'default' => false,
723    ];
724
725    /**
726     * Value for the referrer policy meta tag.
727     *
728     * One or more of the values defined in the Referrer Policy specification:
729     * https://w3c.github.io/webappsec-referrer-policy/
730     * ('no-referrer', 'no-referrer-when-downgrade', 'same-origin',
731     * 'origin', 'strict-origin', 'origin-when-cross-origin',
732     * 'strict-origin-when-cross-origin', or 'unsafe-url')
733     * Setting it to false prevents the meta tag from being output
734     * (which results in falling back to the Referrer-Policy header,
735     * or 'no-referrer-when-downgrade' if that's not set either.)
736     * Setting it to an array (supported since 1.31) will create a meta tag for
737     * each value, in the reverse of the order (meaning that the first array element
738     * will be the default and the others used as fallbacks for browsers which do not
739     * understand it).
740     *
741     * @since 1.25
742     */
743    public const ReferrerPolicy = [
744        'default' => false,
745        'type' => 'list|string|false',
746    ];
747
748    /**
749     * The local filesystem path to a temporary directory. This must not be web-accessible.
750     *
751     * When this setting is set to false, its value will automatically be decided
752     * through the first call to wfTempDir(). See that method's implementation for
753     * the actual detection logic.
754     *
755     * To find the temporary path for the current wiki, developers must not use
756     * this variable directly. Use the global function wfTempDir() instead.
757     *
758     * The temporary directory is expected to be shared with other applications,
759     * including other MediaWiki instances (which might not run the same version
760     * or configuration). When storing files here, take care to avoid conflicts
761     * with other instances of MediaWiki. For example, when caching the result
762     * of a computation, the file name should incorporate the input of the
763     * computation so that it cannot be confused for the result of a similar
764     * computation by another MediaWiki instance.
765     *
766     * @see \wfTempDir()
767     * @note Default changed to false in MediaWiki 1.20.
768     */
769    public const TmpDirectory = [
770        'default' => false,
771    ];
772
773    /**
774     * If set, this URL is added to the start of $wgUploadPath to form a complete
775     * upload URL.
776     *
777     * @since 1.4
778     */
779    public const UploadBaseUrl = [
780        'default' => '',
781    ];
782
783    /**
784     * To enable remote on-demand scaling, set this to the thumbnail base URL.
785     *
786     * Full thumbnail URL will be like $wgUploadStashScalerBaseUrl/e/e6/Foo.jpg/123px-Foo.jpg
787     * where 'e6' are the first two characters of the MD5 hash of the file name.
788     *
789     * @deprecated since 1.36 Use thumbProxyUrl in $wgLocalFileRepo
790     *
791     * If $wgUploadStashScalerBaseUrl and thumbProxyUrl are both false, thumbs are
792     * rendered locally as needed.
793     * @since 1.17
794     */
795    public const UploadStashScalerBaseUrl = [
796        'default' => false,
797        'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo',
798    ];
799
800    /**
801     * To set 'pretty' URL paths for actions other than
802     * plain page views, add to this array.
803     *
804     * **Example:**
805     * Set pretty URL for the edit action:
806     *
807     * ```
808     *   'edit' => "$wgScriptPath/edit/$1"
809     * ```
810     * There must be an appropriate script or rewrite rule in place to handle these URLs.
811     *
812     * @since 1.5
813     */
814    public const ActionPaths = [
815        'default' => [],
816        'type' => 'map',
817    ];
818
819    /**
820     * When enabled, the domain root will show the wiki's main page,
821     * instead of redirecting to the main page.
822     *
823     * @since 1.34
824     */
825    public const MainPageIsDomainRoot = [
826        'default' => false,
827        'type' => 'boolean',
828    ];
829
830    // endregion -- end of server URLs and file paths
831
832    /***************************************************************************/
833    // region   Files and file uploads
834    /** @name   Files and file uploads */
835
836    /**
837     * Allow users to upload files.
838     *
839     * Use $wgLocalFileRepo to control how and where uploads are stored.
840     * Disabled by default as for security reasons.
841     * See <https://www.mediawiki.org/wiki/Manual:Configuring_file_uploads>.
842     *
843     * @since 1.5
844     */
845    public const EnableUploads = [
846        'default' => false,
847    ];
848
849    /**
850     * The maximum age of temporary (incomplete) uploaded files
851     */
852    public const UploadStashMaxAge = [
853        'default' => 6 * 3600, // 6 hours
854    ];
855
856    /**
857     * Enable deferred upload tasks that use the job queue.
858     *
859     * Only enable this if job runners are set up for both the
860     * 'AssembleUploadChunks','PublishStashedFile' and 'UploadFromUrl' job types.
861     */
862    public const EnableAsyncUploads = [
863        'default' => false,
864    ];
865
866    /**
867     * Enable the async processing of upload by url in Special:Upload.
868     *
869     * Only works if EnableAsyncUploads is also enabled
870     */
871    public const EnableAsyncUploadsByURL = [
872        'default' => false,
873    ];
874
875    /**
876     * To disable file delete/restore temporarily
877     */
878    public const UploadMaintenance = [
879        'default' => false,
880    ];
881
882    /**
883     * Additional characters that are not allowed in filenames. They are replaced with '-' when
884     * uploading. Like $wgLegalTitleChars, this is a regexp character class.
885     *
886     * Slashes and backslashes are disallowed regardless of this setting, but included here for
887     * completeness.
888     *
889     * @deprecated since 1.41; no longer customizable
890     */
891    public const IllegalFileChars = [
892        'default' => ':\\/\\\\',
893        'deprecated' => 'since 1.41; no longer customizable',
894    ];
895
896    /**
897     * What directory to place deleted uploads in.
898     *
899     * Defaults to "{$wgUploadDirectory}/deleted".
900     */
901    public const DeletedDirectory = [
902        'default' => false,
903        'dynamicDefault' => [ 'use' => [ 'UploadDirectory' ] ]
904    ];
905
906    /**
907     * @param mixed $uploadDirectory Value of UploadDirectory
908     * @return string
909     */
910    public static function getDefaultDeletedDirectory( $uploadDirectory ): string {
911        return "$uploadDirectory/deleted";
912    }
913
914    /**
915     * Set this to true if you use img_auth and want the user to see details on why access failed.
916     */
917    public const ImgAuthDetails = [
918        'default' => false,
919    ];
920
921    /**
922     * Map of relative URL directories to match to internal mwstore:// base storage paths.
923     *
924     * For img_auth.php requests, everything after "img_auth.php/" is checked to see
925     * if starts with any of the prefixes defined here. The prefixes should not overlap.
926     * The prefix that matches has a corresponding storage path, which the rest of the URL
927     * is assumed to be relative to. The file at that path (or a 404) is send to the client.
928     *
929     * Example:
930     * $wgImgAuthUrlPathMap['/timeline/'] = 'mwstore://local-fs/timeline-render/';
931     * The above maps ".../img_auth.php/timeline/X" to "mwstore://local-fs/timeline-render/".
932     * The name "local-fs" should correspond by name to an entry in $wgFileBackends.
933     *
934     * @see self::FileBackends
935     */
936    public const ImgAuthUrlPathMap = [
937        'default' => [],
938        'type' => 'map',
939    ];
940
941    /**
942     * File repository structures
943     *
944     * $wgLocalFileRepo is a single repository structure, and $wgForeignFileRepos is
945     * an array of such structures. Each repository structure is an associative
946     * array of properties configuring the repository.
947     *
948     * Properties required for all repos:
949     *   - class            The class name for the repository. May come from the core or an extension.
950     *                      The core repository classes are FileRepo, LocalRepo, ForeignDBRepo.
951     *
952     *   - name             A unique name for the repository (but $wgLocalFileRepo should be 'local').
953     *                      The name should consist of alpha-numeric characters.
954     *
955     * Optional common properties:
956     *   - backend          A file backend name (see $wgFileBackends). If not specified, or
957     *                      if the name is not present in $wgFileBackends, an FSFileBackend
958     *                      will automatically be configured.
959     *   - lockManager      If a file backend is automatically configured, this will be lock
960     *                      manager name used. A lock manager named in $wgLockManagers, or one of
961     *                      the default lock managers "fsLockManager" or "nullLockManager". Default
962     *                      "fsLockManager".
963     *   - favicon          URL to a favicon. This is exposed via FileRepo::getInfo and
964     *                      ApiQueryFileRepoInfo. Originally for use by MediaViewer (T77093).
965     *
966     * For most core repos:
967     *   - zones            Associative array of zone names that each map to an array with:
968     *                          container  : backend container name the zone is in
969     *                          directory  : root path within container for the zone
970     *                          url        : base URL to the root of the zone
971     *                          urlsByExt  : map of file extension types to base URLs
972     *                                       (useful for using a different cache for videos)
973     *                      Zones default to using "<repo name>-<zone name>" as the container name
974     *                      and default to using the container root as the zone's root directory.
975     *                      Nesting of zone locations within other zones should be avoided.
976     *   - url              Public zone URL. The 'zones' settings take precedence.
977     *   - hashLevels       The number of directory levels for hash-based division of files.
978     *
979     *                      Set this to 0 if you do not want MediaWiki to divide your images
980     *                      directory into many subdirectories.
981     *
982     *                      It is recommended to leave this enabled. In previous versions of
983     *                      MediaWiki, some users set this to false to allow images to be added to
984     *                      the wiki by copying them into $wgUploadDirectory and then running
985     *                      maintenance/rebuildImages.php to register them in the database.
986     *                      This is no longer supported, use maintenance/importImages.php instead.
987     *
988     *                      Default: 2.
989     *   - deletedHashLevels
990     *                      Optional 'hashLevels' override for the 'deleted' zone.
991     *   - thumbScriptUrl   The URL for thumb.php (optional, not recommended)
992     *   - transformVia404  Whether to skip media file transformation on parse and rely on a 404
993     *                      handler instead.
994     *   - thumbProxyUrl    Optional. URL of where to proxy thumb.php requests to. This is
995     *                      also used internally for remote thumbnailing of upload stash files.
996     *                      Example: http://127.0.0.1:8888/wiki/dev/thumb/
997     *   - thumbProxySecret Optional value of the X-Swift-Secret header to use in requests to
998     *                      thumbProxyUrl
999     *   - disableLocalTransform
1000     *                      If present and true, local image scaling will be disabled. If attempted,
1001     *                      it will show an error to the user and log an error message. To avoid an
1002     *                      error, thumbProxyUrl must be set, as well as either transformVia404
1003     *                      (preferred) or thumbScriptUrl.
1004     *   - initialCapital   Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE],
1005     *                      determines whether filenames implicitly start with a capital letter.
1006     *                      The current implementation may give incorrect description page links
1007     *                      when the local $wgCapitalLinks and initialCapital are mismatched.
1008     *   - pathDisclosureProtection
1009     *                      May be 'paranoid' to remove all parameters from error messages, 'none' to
1010     *                      leave the paths in unchanged, or 'simple' to replace paths with
1011     *                      placeholders. Default for LocalRepo is 'simple'.
1012     *   - fileMode         This allows wikis to set the file mode when uploading/moving files. Default
1013     *                      is 0644.
1014     *   - directory        The local filesystem directory where public files are stored. Not used for
1015     *                      some remote repos.
1016     *   - thumbDir         The base thumbnail directory. Defaults to "<directory>/thumb".
1017     *   - thumbUrl         The base thumbnail URL. Defaults to "<url>/thumb".
1018     *   - isPrivate        Set this if measures should always be taken to keep the files private.
1019     *                      One should not trust this to assure that the files are not web readable;
1020     *                      the server configuration should be done manually depending on the backend.
1021     *   - useJsonMetadata  Whether handler metadata should be stored in JSON format. Default: true.
1022     *   - useSplitMetadata Whether handler metadata should be split up and stored in the text table.
1023     *                      Default: false.
1024     *   - splitMetadataThreshold
1025     *                      If the media handler opts in, large metadata items will be split into a
1026     *                      separate blob in the database if the item is larger than this threshold.
1027     *                      Default: 1000
1028     *   - updateCompatibleMetadata
1029     *                      When true, image metadata will be upgraded by reloading it from the original
1030     *                      file, if the handler indicates that it is out of date.
1031     *
1032     *                      By default, when purging a file or otherwise refreshing file metadata, it
1033     *                      is only reloaded when the metadata is invalid. Valid data originally loaded
1034     *                      by a current or older compatible version is left unchanged. Enable this
1035     *                      to also reload and upgrade metadata that was stored by an older compatible
1036     *                      version. See also MediaHandler::isMetadataValid, and RefreshImageMetadata.
1037     *
1038     *                      Default: false.
1039     *
1040     *   - reserializeMetadata
1041     *                      If true, image metadata will be automatically rewritten to the database
1042     *                      if its serialization format is out of date. Default: false
1043     *
1044     * These settings describe a foreign MediaWiki installation. They are optional, and will be ignored
1045     * for local repositories:
1046     *   - descBaseUrl       URL of image description pages, e.g. https://en.wikipedia.org/wiki/File:
1047     *   - scriptDirUrl      URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g.
1048     *                       https://en.wikipedia.org/w
1049     *   - articleUrl        Equivalent to $wgArticlePath, e.g. https://en.wikipedia.org/wiki/$1
1050     *   - fetchDescription  Fetch the text of the remote file description page and display them
1051     *                       on the local wiki.
1052     *   - abbrvThreshold    File names over this size will use the short form of thumbnail names.
1053     *                       Short thumbnail names only have the width, parameters, and the extension.
1054     *
1055     * ForeignDBRepo:
1056     *   - dbType, dbServer, dbUser, dbPassword, dbName, dbFlags
1057     *                       equivalent to the corresponding member of $wgDBservers
1058     *   - tablePrefix       Table prefix, the foreign wiki's $wgDBprefix
1059     *   - hasSharedCache    Set to true if the foreign wiki's $wgMainCacheType is identical to,
1060     *                       and accessible from, this wiki.
1061     *
1062     * ForeignAPIRepo:
1063     *   - apibase              Use for the foreign API's URL
1064     *   - apiThumbCacheExpiry  How long to locally cache thumbs for
1065     *
1066     * If you leave $wgLocalFileRepo set to false, Setup will fill in appropriate values.
1067     * Otherwise, set $wgLocalFileRepo to a repository structure as described above.
1068     * If you set $wgUseInstantCommons to true, it will add an entry for Commons.
1069     * If you set $wgForeignFileRepos to an array of repository structures, those will
1070     * be searched after the local file repo.
1071     * Otherwise, you will only have access to local media files.
1072     *
1073     * @see \FileRepo::__construct for the default options.
1074     * @see Setup.php for an example usage and default initialization.
1075     */
1076    public const LocalFileRepo = [
1077        'default' => false,
1078        'type' => 'map|false',
1079        'dynamicDefault' => [ 'use' => [ 'UploadDirectory', 'ScriptPath', 'Favicon', 'UploadBaseUrl',
1080            'UploadPath', 'HashedUploadDirectory', 'ThumbnailScriptPath',
1081            'GenerateThumbnailOnParse', 'DeletedDirectory', 'UpdateCompatibleMetadata' ] ],
1082    ];
1083
1084    public static function getDefaultLocalFileRepo(
1085        $uploadDirectory, $scriptPath, $favicon, $uploadBaseUrl, $uploadPath,
1086        $hashedUploadDirectory, $thumbnailScriptPath, $generateThumbnailOnParse, $deletedDirectory,
1087        $updateCompatibleMetadata
1088    ) {
1089        return [
1090            'class' => LocalRepo::class,
1091            'name' => 'local',
1092            'directory' => $uploadDirectory,
1093            'scriptDirUrl' => $scriptPath,
1094            'favicon' => $favicon,
1095            'url' => $uploadBaseUrl ? $uploadBaseUrl . $uploadPath : $uploadPath,
1096            'hashLevels' => $hashedUploadDirectory ? 2 : 0,
1097            'thumbScriptUrl' => $thumbnailScriptPath,
1098            'transformVia404' => !$generateThumbnailOnParse,
1099            'deletedDir' => $deletedDirectory,
1100            'deletedHashLevels' => $hashedUploadDirectory ? 3 : 0,
1101            'updateCompatibleMetadata' => $updateCompatibleMetadata,
1102            'reserializeMetadata' => $updateCompatibleMetadata,
1103        ];
1104    }
1105
1106    /**
1107     * Enable the use of files from one or more other wikis.
1108     *
1109     * If you operate multiple wikis, you can declare a shared upload path here.
1110     * Uploads to the local wiki will NOT be stored here - See $wgLocalFileRepo
1111     * and $wgUploadDirectory for that.
1112     *
1113     * The wiki will only consider the foreign repository if no file of the given name
1114     * is found in the local repository (e.g. via `[[File:..]]` syntax).
1115     *
1116     * @since 1.11
1117     * @see self::LocalFileRepo
1118     */
1119    public const ForeignFileRepos = [
1120        'default' => [],
1121        'type' => 'list',
1122    ];
1123
1124    /**
1125     * Use Wikimedia Commons as a foreign file repository.
1126     *
1127     * This is a shortcut for adding an entry to $wgForeignFileRepos
1128     * for https://commons.wikimedia.org, using ForeignAPIRepo with the
1129     * default settings.
1130     *
1131     * @since 1.16
1132     */
1133    public const UseInstantCommons = [
1134        'default' => false,
1135    ];
1136
1137    /**
1138     * Shortcut for adding an entry to $wgForeignFileRepos.
1139     *
1140     * Uses the following variables:
1141     *
1142     * - directory: $wgSharedUploadDirectory.
1143     * - url: $wgSharedUploadPath.
1144     * - hashLevels: Based on $wgHashedSharedUploadDirectory.
1145     * - thumbScriptUrl: $wgSharedThumbnailScriptPath.
1146     * - transformVia404: Based on $wgGenerateThumbnailOnParse.
1147     * - descBaseUrl: $wgRepositoryBaseUrl.
1148     * - fetchDescription: $wgFetchCommonsDescriptions.
1149     *
1150     * If $wgSharedUploadDBname is set, it uses the ForeignDBRepo
1151     * class, with also the following variables:
1152     *
1153     * - dbName: $wgSharedUploadDBname.
1154     * - dbType: $wgDBtype.
1155     * - dbServer: $wgDBserver.
1156     * - dbUser: $wgDBuser.
1157     * - dbPassword: $wgDBpassword.
1158     * - dbFlags: Based on $wgDebugDumpSql.
1159     * - tablePrefix: $wgSharedUploadDBprefix,
1160     * - hasSharedCache: $wgCacheSharedUploads.
1161     *
1162     * @since 1.3
1163     */
1164    public const UseSharedUploads = [
1165        'default' => false,
1166        'type' => 'boolean',
1167    ];
1168
1169    /**
1170     * Shortcut for the 'directory' setting of $wgForeignFileRepos.
1171     *
1172     * Only used if $wgUseSharedUploads is enabled.
1173     *
1174     * @since 1.3
1175     */
1176    public const SharedUploadDirectory = [
1177        'default' => null,
1178        'type' => '?string',
1179    ];
1180
1181    /**
1182     * Shortcut for the 'url' setting of $wgForeignFileRepos.
1183     *
1184     * Only used if $wgUseSharedUploads is enabled.
1185     *
1186     * @since 1.3
1187     */
1188    public const SharedUploadPath = [
1189        'default' => null,
1190        'type' => '?string',
1191    ];
1192
1193    /**
1194     * Shortcut for the 'hashLevels' setting of $wgForeignFileRepos.
1195     *
1196     * Only used if $wgUseSharedUploads is enabled.
1197     *
1198     * @since 1.3
1199     */
1200    public const HashedSharedUploadDirectory = [
1201        'default' => true,
1202        'type' => 'boolean',
1203    ];
1204
1205    /**
1206     * Shortcut for the 'descBaseUrl' setting of $wgForeignFileRepos.
1207     *
1208     * Only used if $wgUseSharedUploads is enabled.
1209     *
1210     * @since 1.5
1211     */
1212    public const RepositoryBaseUrl = [
1213        'default' => 'https://commons.wikimedia.org/wiki/File:',
1214    ];
1215
1216    /**
1217     * Shortcut for the 'fetchDescription' setting of $wgForeignFileRepos.
1218     *
1219     * Only used if $wgUseSharedUploads is enabled.
1220     *
1221     * @since 1.5
1222     */
1223    public const FetchCommonsDescriptions = [
1224        'default' => false,
1225        'type' => 'boolean',
1226    ];
1227
1228    /**
1229     * Shortcut for the ForeignDBRepo 'dbName' setting in $wgForeignFileRepos.
1230     *
1231     * Set this to false if the uploads do not come from a wiki.
1232     * Only used if $wgUseSharedUploads is enabled.
1233     *
1234     * @since 1.4
1235     */
1236    public const SharedUploadDBname = [
1237        'default' => false,
1238        'type' => 'false|string',
1239    ];
1240
1241    /**
1242     * Shortcut for the ForeignDBRepo 'tablePrefix' setting in $wgForeignFileRepos.
1243     *
1244     * Only used if $wgUseSharedUploads is enabled.
1245     *
1246     * @since 1.5
1247     */
1248    public const SharedUploadDBprefix = [
1249        'default' => '',
1250        'type' => 'string',
1251    ];
1252
1253    /**
1254     * Shortcut for the ForeignDBRepo 'hasSharedCache' setting in $wgForeignFileRepos.
1255     *
1256     * Only used if $wgUseSharedUploads is enabled.
1257     *
1258     * @since 1.5
1259     */
1260    public const CacheSharedUploads = [
1261        'default' => true,
1262        'type' => 'boolean',
1263    ];
1264
1265    /**
1266     * Array of foreign file repo names (set in $wgForeignFileRepos above) that
1267     * are allowable upload targets. These wikis must have some method of
1268     * authentication (i.e. CentralAuth), and be CORS-enabled for this wiki.
1269     *
1270     * The string 'local' signifies the default local file repository.
1271     *
1272     * Example:
1273     * $wgForeignUploadTargets = [ 'shared' ];
1274     */
1275    public const ForeignUploadTargets = [
1276        'default' => [ 'local', ],
1277        'type' => 'list',
1278    ];
1279
1280    /**
1281     * Configuration for file uploads using the embeddable upload dialog
1282     * (https://www.mediawiki.org/wiki/Upload_dialog).
1283     *
1284     * This applies also to foreign uploads to this wiki (the configuration is loaded by remote
1285     * wikis using the action=query&meta=siteinfo API).
1286     *
1287     * See below for documentation of each property. None of the properties may be omitted.
1288     */
1289    public const UploadDialog = [
1290        'default' =>
1291            [
1292                'fields' =>
1293                    [
1294                        'description' => true,
1295                        'date' => false,
1296                        'categories' => false,
1297                    ],
1298                'licensemessages' =>
1299                    [
1300                        'local' => 'generic-local',
1301                        'foreign' => 'generic-foreign',
1302                    ],
1303                'comment' =>
1304                    [
1305                        'local' => '',
1306                        'foreign' => '',
1307                    ],
1308                'format' =>
1309                    [
1310                        'filepage' => '$DESCRIPTION',
1311                        'description' => '$TEXT',
1312                        'ownwork' => '',
1313                        'license' => '',
1314                        'uncategorized' => '',
1315                    ],
1316            ],
1317        'type' => 'map',
1318    ];
1319
1320    /**
1321     * File backend structure configuration.
1322     *
1323     * This is an array of file backend configuration arrays.
1324     * Each backend configuration has the following parameters:
1325     *  - name        : A unique name for the backend
1326     *  - class       : The file backend class to use
1327     *  - wikiId      : A unique string that identifies the wiki (container prefix)
1328     *  - lockManager : The name of a lock manager (see $wgLockManagers) [optional]
1329     *
1330     * See FileBackend::__construct() for more details.
1331     * Additional parameters are specific to the file backend class used.
1332     * These settings should be global to all wikis when possible.
1333     *
1334     * FileBackendMultiWrite::__construct() is augmented with a 'template' option that
1335     * can be used in any of the values of the 'backends' array. Its value is the name of
1336     * another backend in $wgFileBackends. When set, it pre-fills the array with all of the
1337     * configuration of the named backend. Explicitly set values in the array take precedence.
1338     *
1339     * There are two particularly important aspects about each backend:
1340     *   - a) Whether it is fully qualified or wiki-relative.
1341     *        By default, the paths of files are relative to the current wiki,
1342     *        which works via prefixing them with the current wiki ID when accessed.
1343     *        Setting 'domainId' forces the backend to be fully qualified by prefixing
1344     *        all paths with the specified value instead. This can be useful if
1345     *        multiple wikis need to share the same data. Note that 'name' is *not*
1346     *        part of any prefix and thus should not be relied upon for namespacing.
1347     *   - b) Whether it is only defined for some wikis or is defined on all
1348     *        wikis in the wiki farm. Defining a backend globally is useful
1349     *        if multiple wikis need to share the same data.
1350     * One should be aware of these aspects when configuring a backend for use with
1351     * any basic feature or plugin. For example, suppose an extension stores data for
1352     * different wikis in different directories and sometimes needs to access data from
1353     * a foreign wiki's directory in order to render a page on given wiki. The extension
1354     * would need a fully qualified backend that is defined on all wikis in the wiki farm.
1355     */
1356    public const FileBackends = [
1357        'default' => [],
1358        'type' => 'map',
1359    ];
1360
1361    /**
1362     * List of lock manager backend configurations.
1363     *
1364     * Each backend configuration has the following parameters:
1365     *  - name  : A unique name for the lock manager
1366     *  - class : The lock manager class to use
1367     *
1368     * See LockManager::__construct() for more details.
1369     * Additional parameters are specific to the lock manager class used.
1370     * These settings should be global to all wikis.
1371     */
1372    public const LockManagers = [
1373        'default' => [],
1374        'type' => 'list',
1375    ];
1376
1377    /**
1378     * Whether to show Exif data.
1379     * The effective default value is determined at runtime:
1380     * enabled if PHP's EXIF extension module is loaded.
1381     *
1382     * Requires PHP's Exif extension: https://www.php.net/manual/en/ref.exif.php
1383     *
1384     * @note FOR WINDOWS USERS:
1385     * To enable Exif functions, add the following line to the "Windows
1386     * extensions" section of php.ini:
1387     *
1388     * ```{.ini}
1389     * extension=extensions/php_exif.dll
1390     * ```
1391     */
1392    public const ShowEXIF = [
1393        'dynamicDefault' => [ 'callback' => [ self::class, 'getDefaultShowEXIF' ] ],
1394    ];
1395
1396    /**
1397     * @return bool
1398     */
1399    public static function getDefaultShowEXIF(): bool {
1400        return function_exists( 'exif_read_data' );
1401    }
1402
1403    /**
1404     * Shortcut for the 'updateCompatibleMetadata' setting of $wgLocalFileRepo.
1405     */
1406    public const UpdateCompatibleMetadata = [
1407        'default' => false,
1408    ];
1409
1410    /**
1411     * Allow for upload to be copied from an URL.
1412     *
1413     * The timeout for copy uploads is set by $wgCopyUploadTimeout.
1414     * You have to assign the user right 'upload_by_url' to a user group, to use this.
1415     */
1416    public const AllowCopyUploads = [
1417        'default' => false,
1418    ];
1419
1420    /**
1421     * A list of domains copy uploads can come from
1422     *
1423     * @since 1.20
1424     */
1425    public const CopyUploadsDomains = [
1426        'default' => [],
1427        'type' => 'list',
1428    ];
1429
1430    /**
1431     * Enable copy uploads from Special:Upload. $wgAllowCopyUploads must also be
1432     * true. If $wgAllowCopyUploads is true, but this is false, you will only be
1433     * able to perform copy uploads from the API or extensions (e.g. UploadWizard).
1434     */
1435    public const CopyUploadsFromSpecialUpload = [
1436        'default' => false,
1437    ];
1438
1439    /**
1440     * Proxy to use for copy upload requests.
1441     *
1442     * @since 1.20
1443     */
1444    public const CopyUploadProxy = [
1445        'default' => false,
1446    ];
1447
1448    /**
1449     * Different timeout for upload by url
1450     * This could be useful since when fetching large files, you may want a
1451     * timeout longer than the default $wgHTTPTimeout. False means fallback
1452     * to default.
1453     *
1454     * @since 1.22
1455     */
1456    public const CopyUploadTimeout = [
1457        'default' => false,
1458        'type' => 'false|integer',
1459    ];
1460
1461    /**
1462     * If true, the value of $wgCopyUploadsDomains will be merged with the
1463     * contents of MediaWiki:Copyupload-allowed-domains.
1464     *
1465     * @since 1.39
1466     */
1467    public const CopyUploadAllowOnWikiDomainConfig = [
1468        'default' => false,
1469    ];
1470
1471    /**
1472     * Max size for uploads, in bytes.
1473     *
1474     * If not set to an array, applies to all uploads. If set to an array, per upload
1475     * type maximums can be set, using the file and url keys. If the `*` key is set
1476     * this value will be used as maximum for non-specified types.
1477     *
1478     * The below example would set the maximum for all uploads to 250 KiB except,
1479     * for upload-by-url, which would have a maximum of 500 KiB.
1480     *
1481     * **Example:**
1482     *
1483     * ```
1484     * $wgMaxUploadSize = [
1485     *     '*' => 250 * 1024,
1486     *     'url' => 500 * 1024,
1487     * ];
1488     * ```
1489     * Default: 100 MiB.
1490     */
1491    public const MaxUploadSize = [
1492        'default' => 1024 * 1024 * 100,
1493    ];
1494
1495    /**
1496     * Minimum upload chunk size, in bytes.
1497     *
1498     * When using chunked upload, non-final chunks smaller than this will be rejected.
1499     *
1500     * Note that this may be further reduced by the `upload_max_filesize` and
1501     * `post_max_size` PHP settings. Use ApiUpload::getMinUploadChunkSize to
1502     * get the effective minimum chunk size used by MediaWiki.
1503     *
1504     * Default: 1 KiB.
1505     *
1506     * @since 1.26
1507     * @see \ApiUpload::getMinUploadChunkSize
1508     */
1509    public const MinUploadChunkSize = [
1510        'default' => 1024,
1511    ];
1512
1513    /**
1514     * Point the upload navigation link to an external URL
1515     * Useful if you want to use a shared repository by default
1516     * without disabling local uploads (use $wgEnableUploads = false for that).
1517     *
1518     * **Example:**
1519     *
1520     * ```
1521     * $wgUploadNavigationUrl = 'https://commons.wikimedia.org/wiki/Special:Upload';
1522     * ```
1523     */
1524    public const UploadNavigationUrl = [
1525        'default' => false,
1526    ];
1527
1528    /**
1529     * Point the upload link for missing files to an external URL, as with
1530     * $wgUploadNavigationUrl. The URL will get "(?|&)wpDestFile=<filename>"
1531     * appended to it as appropriate.
1532     */
1533    public const UploadMissingFileUrl = [
1534        'default' => false,
1535    ];
1536
1537    /**
1538     * Give a path here to use thumb.php for thumbnail generation on client
1539     * request, instead of generating them on render and outputting a static URL.
1540     *
1541     * This is necessary if some of your apache servers don't have read/write
1542     * access to the thumbnail path.
1543     *
1544     * **Example:**
1545     *
1546     * ```
1547     * $wgThumbnailScriptPath = "{$wgScriptPath}/thumb.php";
1548     * ```
1549     */
1550    public const ThumbnailScriptPath = [
1551        'default' => false,
1552    ];
1553
1554    /**
1555     * Shortcut for the 'thumbScriptUrl' setting of $wgForeignFileRepos.
1556     *
1557     * Only used if $wgUseSharedUploads is enabled.
1558     *
1559     * @since 1.3
1560     */
1561    public const SharedThumbnailScriptPath = [
1562        'default' => false,
1563        'type' => 'string|false',
1564    ];
1565
1566    /**
1567     * Shortcut for setting `hashLevels=2` in $wgLocalFileRepo.
1568     *
1569     * @note Only used if $wgLocalFileRepo is not set.
1570     */
1571    public const HashedUploadDirectory = [
1572        'default' => true,
1573        'type' => 'boolean',
1574    ];
1575
1576    /**
1577     * This is the list of preferred extensions for uploading files. Uploading files
1578     * with extensions not in this list will trigger a warning.
1579     *
1580     * @warning If you add any OpenOffice or Microsoft Office file formats here,
1581     * such as odt or doc, and untrusted users are allowed to upload files, then
1582     * your wiki will be vulnerable to cross-site request forgery (CSRF).
1583     */
1584    public const FileExtensions = [
1585        'default' => [ 'png', 'gif', 'jpg', 'jpeg', 'webp', ],
1586        'type' => 'list',
1587    ];
1588
1589    /**
1590     * Files with these extensions will never be allowed as uploads.
1591     *
1592     * An array of file extensions to prevent being uploaded. You should
1593     * append to this array if you want to prevent additional file extensions.
1594     *
1595     * @since 1.37; previously $wgFileBlacklist
1596     */
1597    public const ProhibitedFileExtensions = [
1598        'default' => [
1599            # HTML may contain cookie-stealing JavaScript and web bugs
1600            'html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht',
1601            # PHP scripts may execute arbitrary code on the server
1602            'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar',
1603            # Other types that may be interpreted by some servers
1604            'shtml', 'jhtml', 'pl', 'py', 'cgi',
1605            # May contain harmful executables for Windows victims
1606            'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl',
1607            # T341565
1608            'xml',
1609        ],
1610        'type' => 'list',
1611    ];
1612
1613    /**
1614     * Files with these MIME types will never be allowed as uploads
1615     * if $wgVerifyMimeType is enabled.
1616     *
1617     * @since 1.37; previously $wgMimeTypeBlacklist
1618     */
1619    public const MimeTypeExclusions = [
1620        'default' => [
1621            # HTML may contain cookie-stealing JavaScript and web bugs
1622            'text/html',
1623            # Similarly with JavaScript itself
1624            'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript',
1625            # PHP scripts may execute arbitrary code on the server
1626            'application/x-php', 'text/x-php',
1627            # Other types that may be interpreted by some servers
1628            'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh',
1629            # Client-side hazards on Internet Explorer
1630            'text/scriptlet', 'application/x-msdownload',
1631            # Windows metafile, client-side vulnerability on some systems
1632            'application/x-msmetafile',
1633            # Files that look like java files
1634            'application/java',
1635            # XML files generally - T341565
1636            'application/xml', 'text/xml',
1637        ],
1638        'type' => 'list',
1639    ];
1640
1641    /**
1642     * This is a flag to determine whether or not to check file extensions on upload.
1643     *
1644     * @warning Setting this to false is insecure for public wikis.
1645     */
1646    public const CheckFileExtensions = [
1647        'default' => true,
1648    ];
1649
1650    /**
1651     * If this is turned off, users may override the warning for files not covered
1652     * by $wgFileExtensions.
1653     *
1654     * @warning Setting this to false is insecure for public wikis.
1655     */
1656    public const StrictFileExtensions = [
1657        'default' => true,
1658    ];
1659
1660    /**
1661     * Setting this to true will disable the upload system's checks for HTML/JavaScript.
1662     *
1663     * @warning THIS IS VERY DANGEROUS on a publicly editable site, so USE
1664     * $wgGroupPermissions TO RESTRICT UPLOADING to only those that you trust
1665     */
1666    public const DisableUploadScriptChecks = [
1667        'default' => false,
1668    ];
1669
1670    /**
1671     * Warn if uploaded files are larger than this (in bytes), or false to disable
1672     */
1673    public const UploadSizeWarning = [
1674        'default' => false,
1675    ];
1676
1677    /**
1678     * list of trusted media-types and MIME types.
1679     *
1680     * Use the MEDIATYPE_xxx constants to represent media types.
1681     * This list is used by File::isSafeFile
1682     *
1683     * Types not listed here will have a warning about unsafe content
1684     * displayed on the images description page. It would also be possible
1685     * to use this for further restrictions, like disabling direct
1686     * [[media:...]] links for non-trusted formats.
1687     */
1688    public const TrustedMediaFormats = [
1689        'default' => [
1690            MEDIATYPE_BITMAP, // all bitmap formats
1691            MEDIATYPE_AUDIO, // all audio formats
1692            MEDIATYPE_VIDEO, // all plain video formats
1693            "image/svg+xml", // svg (only needed if inline rendering of svg is not supported)
1694            "application/pdf", // PDF files
1695            # "application/x-shockwave-flash", //flash/shockwave movie
1696        ],
1697        'type' => 'list',
1698    ];
1699
1700    /**
1701     * Plugins for media file type handling.
1702     *
1703     * Each entry in the array maps a MIME type to a class name
1704     *
1705     * Core media handlers are listed in MediaHandlerFactory,
1706     * and extensions should use extension.json.
1707     */
1708    public const MediaHandlers = [
1709        'default' => [],
1710        'type' => 'map',
1711    ];
1712
1713    /**
1714     * Toggles native image lazy loading, via the "loading" attribute.
1715     *
1716     * @unstable EXPERIMENTAL
1717     * @since 1.34
1718     */
1719    public const NativeImageLazyLoading = [
1720        'default' => false,
1721        'type' => 'boolean',
1722    ];
1723
1724    /**
1725     * Media handler overrides for parser tests (they don't need to generate actual
1726     * thumbnails, so a mock will do)
1727     */
1728    public const ParserTestMediaHandlers = [
1729        'default' => [
1730            'image/jpeg' => 'MockBitmapHandler',
1731            'image/png' => 'MockBitmapHandler',
1732            'image/gif' => 'MockBitmapHandler',
1733            'image/tiff' => 'MockBitmapHandler',
1734            'image/webp' => 'MockBitmapHandler',
1735            'image/x-ms-bmp' => 'MockBitmapHandler',
1736            'image/x-bmp' => 'MockBitmapHandler',
1737            'image/x-xcf' => 'MockBitmapHandler',
1738            'image/svg+xml' => 'MockSvgHandler',
1739            'image/vnd.djvu' => 'MockDjVuHandler',
1740        ],
1741        'type' => 'map',
1742    ];
1743
1744    /**
1745     * Whether to enable server-side image thumbnailing. If false, images will
1746     * always be sent to the client in full resolution, with appropriate width= and
1747     * height= attributes on the <img> tag for the client to do its own scaling.
1748     */
1749    public const UseImageResize = [
1750        'default' => true,
1751    ];
1752
1753    /**
1754     * Resizing can be done using PHP's internal image libraries or using
1755     * ImageMagick or another third-party converter, e.g. GraphicMagick.
1756     *
1757     * These support more file formats than PHP, which only supports PNG,
1758     * GIF, JPG, XBM and WBMP.
1759     *
1760     * Use Image Magick instead of PHP builtin functions.
1761     */
1762    public const UseImageMagick = [
1763        'default' => false,
1764    ];
1765
1766    /**
1767     * The convert command shipped with ImageMagick
1768     */
1769    public const ImageMagickConvertCommand = [
1770        'default' => '/usr/bin/convert',
1771    ];
1772
1773    /**
1774     * Array of max pixel areas for interlacing per MIME type
1775     *
1776     * @since 1.27
1777     */
1778    public const MaxInterlacingAreas = [
1779        'default' => [],
1780        'type' => 'map',
1781    ];
1782
1783    /**
1784     * Sharpening parameter to ImageMagick
1785     */
1786    public const SharpenParameter = [
1787        'default' => '0x0.4',
1788    ];
1789
1790    /**
1791     * Reduction in linear dimensions below which sharpening will be enabled
1792     */
1793    public const SharpenReductionThreshold = [
1794        'default' => 0.85,
1795    ];
1796
1797    /**
1798     * Temporary directory used for ImageMagick. The directory must exist. Leave
1799     * this set to false to let ImageMagick decide for itself.
1800     */
1801    public const ImageMagickTempDir = [
1802        'default' => false,
1803    ];
1804
1805    /**
1806     * Use another resizing converter, e.g. GraphicMagick
1807     * %s will be replaced with the source path, %d with the destination
1808     * %w and %h will be replaced with the width and height.
1809     *
1810     * **Example for GraphicMagick:**
1811     *
1812     * ```
1813     * $wgCustomConvertCommand = "gm convert %s -resize %wx%h %d"
1814     * ```
1815     * Leave as false to skip this.
1816     */
1817    public const CustomConvertCommand = [
1818        'default' => false,
1819    ];
1820
1821    /**
1822     * used for lossless jpeg rotation
1823     *
1824     * @since 1.21
1825     */
1826    public const JpegTran = [
1827        'default' => '/usr/bin/jpegtran',
1828    ];
1829
1830    /**
1831     * At default setting of 'yuv420', JPEG thumbnails will use 4:2:0 chroma
1832     * subsampling to reduce file size, at the cost of possible color fringing
1833     * at sharp edges.
1834     *
1835     * See https://en.wikipedia.org/wiki/Chroma_subsampling
1836     *
1837     * Supported values:
1838     *   false - use scaling system's default (same as pre-1.27 behavior)
1839     *   'yuv444' - luma and chroma at same resolution
1840     *   'yuv422' - chroma at 1/2 resolution horizontally, full vertically
1841     *   'yuv420' - chroma at 1/2 resolution in both dimensions
1842     *
1843     * This setting is currently supported only for the ImageMagick backend;
1844     * others may default to 4:2:0 or 4:4:4 or maintaining the source file's
1845     * sampling in the thumbnail.
1846     *
1847     * @since 1.27
1848     */
1849    public const JpegPixelFormat = [
1850        'default' => 'yuv420',
1851    ];
1852
1853    /**
1854     * When scaling a JPEG thumbnail, this is the quality we request
1855     * from the backend. It should be an integer between 1 and 100,
1856     * with 100 indicating 100% quality.
1857     *
1858     * @since 1.32
1859     */
1860    public const JpegQuality = [
1861        'default' => 80,
1862    ];
1863
1864    /**
1865     * Some tests and extensions use exiv2 to manipulate the Exif metadata in some
1866     * image formats.
1867     */
1868    public const Exiv2Command = [
1869        'default' => '/usr/bin/exiv2',
1870    ];
1871
1872    /**
1873     * Path to exiftool binary. Used for lossless ICC profile swapping.
1874     *
1875     * @since 1.26
1876     */
1877    public const Exiftool = [
1878        'default' => '/usr/bin/exiftool',
1879    ];
1880
1881    /**
1882     * Scalable Vector Graphics (SVG) may be uploaded as images.
1883     *
1884     * Since SVG support is not yet standard in browsers, it is
1885     * necessary to rasterize SVGs to PNG as a fallback format.
1886     *
1887     * An external program is required to perform this conversion.
1888     * If set to an array, the first item is a PHP callable and any further items
1889     * are passed as parameters after $srcPath, $dstPath, $width, $height
1890     */
1891    public const SVGConverters = [
1892        'default' => [
1893            'ImageMagick' => '$path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output',
1894            'sodipodi' => '$path/sodipodi -z -w $width -f $input -e $output',
1895            'inkscape' => '$path/inkscape -z -w $width -f $input -e $output',
1896            'batik' => 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input',
1897            'rsvg' => '$path/rsvg-convert -w $width -h $height -o $output $input',
1898            'imgserv' => '$path/imgserv-wrapper -i svg -o png -w$width $input $output',
1899            'ImagickExt' => [ 'SvgHandler::rasterizeImagickExt', ],
1900        ],
1901        'type' => 'map',
1902    ];
1903
1904    /**
1905     * Pick a converter defined in $wgSVGConverters
1906     */
1907    public const SVGConverter = [
1908        'default' => 'ImageMagick',
1909    ];
1910
1911    /**
1912     * If not in the executable PATH, specify the SVG converter path.
1913     */
1914    public const SVGConverterPath = [
1915        'default' => '',
1916    ];
1917
1918    /**
1919     * Don't scale a SVG larger than this
1920     */
1921    public const SVGMaxSize = [
1922        'default' => 5120,
1923    ];
1924
1925    /**
1926     * Don't read SVG metadata beyond this point.
1927     *
1928     * Default is 5 MiB
1929     */
1930    public const SVGMetadataCutoff = [
1931        'default' => 1024 * 1024 * 5,
1932    ];
1933
1934    /**
1935     * Whether native rendering by the browser agent is allowed
1936     *
1937     * Default is false. Setting it to true disables all SVG conversion.
1938     * Setting to the string 'partial' will only allow native rendering
1939     * when the filesize is below SVGNativeRenderingSizeLimit and if the
1940     * file contains at most 1 language.
1941     *
1942     * @since 1.41
1943     */
1944    public const SVGNativeRendering = [
1945        'default' => false,
1946        'type' => 'string|boolean',
1947    ];
1948
1949    /**
1950     * Filesize limit for allowing SVGs to render natively by the browser agent
1951     *
1952     * Default is 50kB.
1953     *
1954     * @since 1.41
1955     */
1956    public const SVGNativeRenderingSizeLimit = [
1957        'default' => 50 * 1024,
1958    ];
1959
1960    /**
1961     * Whether thumbnails should be generated in target language (usually, same as
1962     * page language), if available.
1963     *
1964     * Currently, applies only to SVG images that use the systemLanguage attribute
1965     * to specify text language.
1966     *
1967     * @since 1.33
1968     */
1969    public const MediaInTargetLanguage = [
1970        'default' => true,
1971    ];
1972
1973    /**
1974     * The maximum number of pixels a source image can have if it is to be scaled
1975     * down by a scaler that requires the full source image to be decompressed
1976     * and stored in decompressed form, before the thumbnail is generated.
1977     *
1978     * This provides a limit on memory usage for the decompression side of the
1979     * image scaler. The limit is used when scaling PNGs with any of the
1980     * built-in image scalers, such as ImageMagick or GD. It is ignored for
1981     * JPEGs with ImageMagick, and when using the VipsScaler extension.
1982     *
1983     * If set to false, MediaWiki will not check the size of the image before
1984     * attempting to scale it. Extensions may still override this setting by
1985     * using the BitmapHandlerCheckImageArea hook.
1986     *
1987     * The default is 50 MB if decompressed to RGBA form, which corresponds to
1988     * 12.5 million pixels or 3500x3500.
1989     */
1990    public const MaxImageArea = [
1991        'default' => 12_500_000,
1992        'type' => 'string|integer|false',
1993    ];
1994
1995    /**
1996     * Force thumbnailing of animated GIFs above this size to a single
1997     * frame instead of an animated thumbnail.  As of MW 1.17 this limit
1998     * is checked against the total size of all frames in the animation.
1999     *
2000     *
2001     * It probably makes sense to keep this equal to $wgMaxImageArea.
2002     */
2003    public const MaxAnimatedGifArea = [
2004        'default' => 12_500_000,
2005    ];
2006
2007    /**
2008     * Browsers don't support TIFF inline generally...
2009     * For inline display, we need to convert to PNG or JPEG.
2010     *
2011     * Note scaling should work with ImageMagick, but may not with GD scaling.
2012     *
2013     * **Example:**
2014     *
2015     * ```
2016     * // PNG is lossless, but inefficient for photos
2017     * $wgTiffThumbnailType = [ 'png', 'image/png' ];
2018     * // JPEG is good for photos, but has no transparency support. Bad for diagrams.
2019     * $wgTiffThumbnailType = [ 'jpg', 'image/jpeg' ];
2020     * ```
2021     */
2022    public const TiffThumbnailType = [
2023        'default' => [],
2024        'type' => 'list',
2025        'mergeStrategy' => 'replace',
2026    ];
2027
2028    /**
2029     * If rendered thumbnail files are older than this timestamp, they
2030     * will be rerendered on demand as if the file didn't already exist.
2031     *
2032     * Update if there is some need to force thumbs and SVG rasterizations
2033     * to rerender, such as fixes to rendering bugs.
2034     */
2035    public const ThumbnailEpoch = [
2036        'default' => '20030516000000',
2037    ];
2038
2039    /**
2040     * Certain operations are avoided if there were too many recent failures,
2041     * for example, thumbnail generation. Bump this value to invalidate all
2042     * memory of failed operations and thus allow further attempts to resume.
2043     *
2044     * This is useful when a cause for the failures has been found and fixed.
2045     */
2046    public const AttemptFailureEpoch = [
2047        'default' => 1,
2048    ];
2049
2050    /**
2051     * If set, inline scaled images will still produce "<img>" tags ready for
2052     * output instead of showing an error message.
2053     *
2054     * This may be useful if errors are transitory, especially if the site
2055     * is configured to automatically render thumbnails on request.
2056     *
2057     * On the other hand, it may obscure error conditions from debugging.
2058     * Enable the debug log or the 'thumbnail' log group to make sure errors
2059     * are logged to a file for review.
2060     */
2061    public const IgnoreImageErrors = [
2062        'default' => false,
2063    ];
2064
2065    /**
2066     * Render thumbnails while parsing wikitext.
2067     *
2068     * If set to false, then the Parser will output valid thumbnail URLs without
2069     * generating or storing the thumbnail files. This can significantly speed up
2070     * processing on the web server. The site admin needs to configure a 404 handler
2071     * in order for the URLs in question to regenerate the thumbnails in question
2072     * on-demand. This can enable concurrency and also save computing resources
2073     * as not every resolution of every image on every page is accessed between
2074     * re-parses of the article. For example, re-parses triggered by bot edits,
2075     * or cascading updates from template edits.
2076     *
2077     * If you use $wgLocalFileRepo, then you will also need to set the following:
2078     *
2079     * ```
2080     * $wgLocalFileRepo['transformVia404'] = true;
2081     * ```
2082     *
2083     * @since 1.7.0
2084     */
2085    public const GenerateThumbnailOnParse = [
2086        'default' => true,
2087        'type' => 'boolean',
2088    ];
2089
2090    /**
2091     * Show thumbnails for old images on the image description page
2092     */
2093    public const ShowArchiveThumbnails = [
2094        'default' => true,
2095    ];
2096
2097    /**
2098     * If set to true, images that contain certain the exif orientation tag will
2099     * be rotated accordingly. If set to null, try to auto-detect whether a scaler
2100     * is available that can rotate.
2101     */
2102    public const EnableAutoRotation = [
2103        'default' => null,
2104        'type' => '?boolean',
2105    ];
2106
2107    /**
2108     * Internal name of virus scanner. This serves as a key to the
2109     * $wgAntivirusSetup array. Set this to NULL to disable virus scanning. If not
2110     * null, every file uploaded will be scanned for viruses.
2111     */
2112    public const Antivirus = [
2113        'default' => null,
2114        'type' => '?string',
2115    ];
2116
2117    /**
2118     * Configuration for different virus scanners. This an associative array of
2119     * associative arrays. It contains one setup array per known scanner type.
2120     *
2121     * The entry is selected by $wgAntivirus, i.e.
2122     * valid values for $wgAntivirus are the keys defined in this array.
2123     *
2124     * The configuration array for each scanner contains the following keys:
2125     * "command", "codemap", "messagepattern":
2126     *
2127     * "command" is the full command to call the virus scanner - %f will be
2128     * replaced with the name of the file to scan. If not present, the filename
2129     * will be appended to the command. Note that this must be overwritten if the
2130     * scanner is not in the system path; in that case, please set
2131     * $wgAntivirusSetup[$wgAntivirus]['command'] to the desired command with full
2132     * path.
2133     *
2134     * "codemap" is a mapping of exit code to return codes of the detectVirus
2135     * function in SpecialUpload.
2136     *   - An exit code mapped to AV_SCAN_FAILED causes the function to consider
2137     *     the scan to be failed. This will pass the file if $wgAntivirusRequired
2138     *     is not set.
2139     *   - An exit code mapped to AV_SCAN_ABORTED causes the function to consider
2140     *     the file to have an unsupported format, which is probably immune to
2141     *     viruses. This causes the file to pass.
2142     *   - An exit code mapped to AV_NO_VIRUS will cause the file to pass, meaning
2143     *     no virus was found.
2144     *   - All other codes (like AV_VIRUS_FOUND) will cause the function to report
2145     *     a virus.
2146     *   - You may use "*" as a key in the array to catch all exit codes not mapped otherwise.
2147     *
2148     * "messagepattern" is a perl regular expression to extract the meaningful part of the scanners
2149     * output. The relevant part should be matched as group one (\1).
2150     * If not defined or the pattern does not match, the full message is shown to the user.
2151     */
2152    public const AntivirusSetup = [
2153        'default' => [
2154            # setup for clamav
2155            'clamav' => [
2156                'command' => 'clamscan --no-summary ',
2157                'codemap' => [
2158                    "0" => AV_NO_VIRUS, # no virus
2159                    "1" => AV_VIRUS_FOUND, # virus found
2160                    "52" => AV_SCAN_ABORTED, # unsupported file format (probably immune)
2161                    "*" => AV_SCAN_FAILED, # else scan failed
2162                ],
2163                'messagepattern' => '/.*?:(.*)/sim',
2164            ],
2165        ],
2166        'type' => 'map',
2167    ];
2168
2169    /**
2170     * Determines if a failed virus scan (AV_SCAN_FAILED) will cause the file to be rejected.
2171     */
2172    public const AntivirusRequired = [
2173        'default' => true,
2174    ];
2175
2176    /**
2177     * Determines if the MIME type of uploaded files should be checked
2178     */
2179    public const VerifyMimeType = [
2180        'default' => true,
2181    ];
2182
2183    /**
2184     * Sets the MIME type definition file to use by includes/libs/mime/MimeAnalyzer.php.
2185     *
2186     * When this is set to the path of a mime.types file, MediaWiki will use this
2187     * file to map MIME types to file extensions and vice versa, in lieu of its
2188     * internal MIME map. Note that some MIME mappings are considered "baked in"
2189     * and cannot be overridden. See includes/libs/mime/MimeMapMinimal.php for a
2190     * full list.
2191     * example: $wgMimeTypeFile = '/etc/mime.types';
2192     */
2193    public const MimeTypeFile = [
2194        'default' => 'internal',
2195    ];
2196
2197    /**
2198     * Sets the MIME type info file to use by includes/libs/mime/MimeAnalyzer.php.
2199     *
2200     * Set to null to use the minimum set of built-in defaults only.
2201     */
2202    public const MimeInfoFile = [
2203        'default' => 'internal',
2204    ];
2205
2206    /**
2207     * Sets an external MIME detector program. The command must print only
2208     * the MIME type to standard output.
2209     *
2210     * The name of the file to process will be appended to the command given here.
2211     * If not set or NULL, PHP's mime_content_type function will be used.
2212     *
2213     * **Example:**
2214     *
2215     * ```
2216     * #$wgMimeDetectorCommand = "file -bi"; // use external MIME detector (Linux)
2217     * ```
2218     */
2219    public const MimeDetectorCommand = [
2220        'default' => null,
2221        'type' => '?string',
2222    ];
2223
2224    /**
2225     * Switch for trivial MIME detection. Used by thumb.php to disable all fancy
2226     * things, because only a few types of images are needed and file extensions
2227     * can be trusted.
2228     */
2229    public const TrivialMimeDetection = [
2230        'default' => false,
2231    ];
2232
2233    /**
2234     * Additional XML types we can allow via MIME-detection.
2235     *
2236     * array = [ 'rootElement' => 'associatedMimeType' ]
2237     */
2238    public const XMLMimeTypes = [
2239        'default' => [
2240            'http://www.w3.org/2000/svg:svg' => 'image/svg+xml',
2241            'svg' => 'image/svg+xml',
2242            'http://www.lysator.liu.se/~alla/dia/:diagram' => 'application/x-dia-diagram',
2243            'http://www.w3.org/1999/xhtml:html' => 'text/html',
2244            'html' => 'text/html',
2245        ],
2246        'type' => 'map',
2247    ];
2248
2249    /**
2250     * Limit images on image description pages to a user-selectable limit.
2251     *
2252     * In order to reduce disk usage, limits can only be selected from this list.
2253     * The user preference is saved as an array offset in the database, by default
2254     * the offset is set with $wgDefaultUserOptions['imagesize']. Make sure you
2255     * change it if you alter the array (see T10858).
2256     *
2257     * This list is also used by ImagePage for alternate size links.
2258     */
2259    public const ImageLimits = [
2260        'default' => [
2261            [ 320, 240 ],
2262            [ 640, 480 ],
2263            [ 800, 600 ],
2264            [ 1024, 768 ],
2265            [ 1280, 1024 ],
2266            [ 2560, 2048 ],
2267        ],
2268        'type' => 'list',
2269    ];
2270
2271    /**
2272     * Adjust thumbnails on image pages according to a user setting. In order to
2273     * reduce disk usage, the values can only be selected from a list. This is the
2274     * list of settings the user can choose from:
2275     */
2276    public const ThumbLimits = [
2277        'default' => [
2278            120,
2279            150,
2280            180,
2281            200,
2282            250,
2283            300
2284        ],
2285        'type' => 'list',
2286    ];
2287
2288    /**
2289     * Defines what namespaces thumbnails will be displayed for in Special:Search.
2290     * This is the list of namespaces for which thumbnails (or a placeholder in
2291     * the absence of a thumbnail) will be shown:
2292     */
2293    public const ThumbnailNamespaces = [
2294        'default' => [ NS_FILE ],
2295        'type' => 'list',
2296        'items' => [ 'type' => 'integer', ],
2297    ];
2298
2299    /**
2300     * When defined, is an array of image widths used as buckets for thumbnail generation.
2301     *
2302     * The goal is to save resources by generating thumbnails based on reference buckets instead of
2303     * always using the original. This will incur a speed gain but cause a quality loss.
2304     *
2305     * The buckets generation is chained, with each bucket generated based on the above bucket
2306     * when possible. File handlers have to opt into using that feature. For now only BitmapHandler
2307     * supports it.
2308     */
2309    public const ThumbnailBuckets = [
2310        'default' => null,
2311        'type' => '?list',
2312    ];
2313
2314    /**
2315     * When using thumbnail buckets as defined above, this sets the minimum distance to the bucket
2316     * above the requested size. The distance represents how many extra pixels of width the bucket
2317     * needs in order to be used as the reference for a given thumbnail. For example, with the
2318     * following buckets:
2319     *
2320     * $wgThumbnailBuckets = [ 128, 256, 512 ];
2321     *
2322     * and a distance of 50:
2323     *
2324     * $wgThumbnailMinimumBucketDistance = 50;
2325     *
2326     * If we want to render a thumbnail of width 220px, the 512px bucket will be used,
2327     * because 220 + 50 = 270 and the closest bucket bigger than 270px is 512.
2328     */
2329    public const ThumbnailMinimumBucketDistance = [
2330        'default' => 50,
2331    ];
2332
2333    /**
2334     * When defined, is an array of thumbnail widths to be rendered at upload time. The idea is to
2335     * prerender common thumbnail sizes, in order to avoid the necessity to render them on demand,
2336     * which has a performance impact for the first client to view a certain size.
2337     *
2338     * This obviously means that more disk space is needed per upload upfront.
2339     *
2340     * @since 1.25
2341     */
2342    public const UploadThumbnailRenderMap = [
2343        'default' => [],
2344        'type' => 'map',
2345    ];
2346
2347    /**
2348     * The method through which the thumbnails will be prerendered for the entries in
2349     * $wgUploadThumbnailRenderMap
2350     *
2351     * The method can be either "http" or "jobqueue". The former uses an http request to hit the
2352     * thumbnail's URL.
2353     * This method only works if thumbnails are configured to be rendered by a 404 handler. The
2354     * latter option uses the job queue to render the thumbnail.
2355     *
2356     * @since 1.25
2357     */
2358    public const UploadThumbnailRenderMethod = [
2359        'default' => 'jobqueue',
2360    ];
2361
2362    /**
2363     * When using the "http" $wgUploadThumbnailRenderMethod, lets one specify a custom Host HTTP
2364     * header.
2365     *
2366     * @since 1.25
2367     */
2368    public const UploadThumbnailRenderHttpCustomHost = [
2369        'default' => false,
2370    ];
2371
2372    /**
2373     * When using the "http" $wgUploadThumbnailRenderMethod, lets one specify a custom domain to
2374     * send the HTTP request to.
2375     *
2376     * @since 1.25
2377     */
2378    public const UploadThumbnailRenderHttpCustomDomain = [
2379        'default' => false,
2380    ];
2381
2382    /**
2383     * When this variable is true and JPGs use the sRGB ICC profile, swaps it for the more
2384     * lightweight
2385     * (and free) TinyRGB profile when generating thumbnails.
2386     *
2387     * @since 1.26
2388     */
2389    public const UseTinyRGBForJPGThumbnails = [
2390        'default' => false,
2391    ];
2392
2393    /**
2394     * Parameters for the "<gallery>" tag.
2395     *
2396     * Fields are:
2397     * - imagesPerRow:   Default number of images per-row in the gallery. 0 -> Adapt to screensize
2398     * - imageWidth:     Width of the cells containing images in galleries (in "px")
2399     * - imageHeight:    Height of the cells containing images in galleries (in "px")
2400     * - captionLength:  Length to truncate filename to in caption when using "showfilename".
2401     *                   A value of 'true' will truncate the filename to one line using CSS
2402     *                   and will be the behaviour after deprecation.
2403     *                   @deprecated since 1.28
2404     * - showBytes:      Show the filesize in bytes in categories
2405     * - showDimensions: Show the dimensions (width x height) in categories
2406     * - mode:           Gallery mode
2407     */
2408    public const GalleryOptions = [
2409        'default' => [],
2410        'type' => 'map',
2411    ];
2412
2413    /**
2414     * Adjust width of upright images when parameter 'upright' is used
2415     * This allows a nicer look for upright images without the need to fix the width
2416     * by hardcoded px in wiki sourcecode.
2417     */
2418    public const ThumbUpright = [
2419        'default' => 0.75,
2420    ];
2421
2422    /**
2423     * Default value for chmod-ing of new directories.
2424     */
2425    public const DirectoryMode = [
2426        'default' => 0777, // octal!
2427    ];
2428
2429    /**
2430     * Generate and use thumbnails suitable for screens with 1.5 and 2.0 pixel densities.
2431     *
2432     * This means a 320x240 use of an image on the wiki will also generate 480x360 and 640x480
2433     * thumbnails, output via the srcset attribute.
2434     */
2435    public const ResponsiveImages = [
2436        'default' => true,
2437    ];
2438
2439    /**
2440     * Add a preconnect link for browsers to a remote FileRepo host.
2441     *
2442     * This is an optional performance enhancement designed for wiki farm where
2443     * $wgForeignFileRepos or $wgLocalFileRepo is set to serve thumbnails from a
2444     * separate hostname (e.g. not local `/w/images`). The feature expects at most
2445     * a single remote hostname to be used.
2446     *
2447     * If multiple foreign repos are registered that serve images from different hostnames,
2448     * only the first will be preconnected.
2449     *
2450     * This may cause unneeded HTTP connections in browsers on wikis where a foreign repo is
2451     * enabled but where a local repo is more commonly used.
2452     *
2453     * @since 1.35
2454     */
2455    public const ImagePreconnect = [
2456        'default' => false,
2457    ];
2458
2459    /***************************************************************************/
2460    // region   DJVU settings
2461    /** @name   DJVU settings */
2462
2463    /**
2464     * Whether to use BoxedCommand or not.
2465     *
2466     * @unstable Temporary feature flag for T352515
2467     * @since 1.42
2468     */
2469    public const DjvuUseBoxedCommand = [
2470        'default' => false,
2471    ];
2472
2473    /**
2474     * Path of the djvudump executable
2475     * Enable this and $wgDjvuRenderer to enable djvu rendering
2476     * example: $wgDjvuDump = 'djvudump';
2477     *
2478     * If this is set, {@link self::ShellboxShell} must be set to the correct
2479     * shell path.
2480     */
2481    public const DjvuDump = [
2482        'default' => null,
2483        'type' => '?string',
2484    ];
2485
2486    /**
2487     * Path of the ddjvu DJVU renderer
2488     * Enable this and $wgDjvuDump to enable djvu rendering
2489     * example: $wgDjvuRenderer = 'ddjvu';
2490     */
2491    public const DjvuRenderer = [
2492        'default' => null,
2493        'type' => '?string',
2494    ];
2495
2496    /**
2497     * Path of the djvutxt DJVU text extraction utility
2498     * Enable this and $wgDjvuDump to enable text layer extraction from djvu files
2499     * example: $wgDjvuTxt = 'djvutxt';
2500     *
2501     * If this is set, {@link self::ShellboxShell} must be set to the correct
2502     *  shell path.
2503     */
2504    public const DjvuTxt = [
2505        'default' => null,
2506        'type' => '?string',
2507    ];
2508
2509    /**
2510     * Shell command for the DJVU post processor
2511     * Default: pnmtojpeg, since ddjvu generates ppm output
2512     * Set this to false to output the ppm file directly.
2513     */
2514    public const DjvuPostProcessor = [
2515        'default' => 'pnmtojpeg',
2516        'type' => '?string',
2517    ];
2518
2519    /**
2520     * File extension for the DJVU post processor output
2521     */
2522    public const DjvuOutputExtension = [
2523        'default' => 'jpg',
2524    ];
2525
2526    // endregion -- end of DJvu
2527
2528    // endregion -- end of file uploads
2529
2530    /***************************************************************************/
2531    // region   Email settings
2532    /** @name   Email settings */
2533
2534    /**
2535     * Site admin email address.
2536     *
2537     * Defaults to "wikiadmin@$wgServerName" (in Setup.php).
2538     */
2539    public const EmergencyContact = [
2540        'default' => false,
2541    ];
2542
2543    /**
2544     * Sender email address for e-mail notifications.
2545     *
2546     * The address we use as sender when a user requests a password reminder,
2547     * as well as other e-mail notifications.
2548     *
2549     * Defaults to "apache@$wgServerName" (in Setup.php).
2550     */
2551    public const PasswordSender = [
2552        'default' => false,
2553    ];
2554
2555    /**
2556     * Reply-To address for e-mail notifications.
2557     *
2558     * Defaults to $wgPasswordSender (in Setup.php).
2559     */
2560    public const NoReplyAddress = [
2561        'default' => false,
2562    ];
2563
2564    /**
2565     * Set to true to enable the e-mail basic features:
2566     * Password reminders, etc. If sending e-mail on your
2567     * server doesn't work, you might want to disable this.
2568     */
2569    public const EnableEmail = [
2570        'default' => true,
2571    ];
2572
2573    /**
2574     * Set to true to enable user-to-user e-mail.
2575     *
2576     * This can potentially be abused, as it's hard to track.
2577     */
2578    public const EnableUserEmail = [
2579        'default' => true,
2580    ];
2581
2582    /**
2583     * Set to true to enable the Special Mute page. This allows users
2584     * to mute unwanted communications from other users, and is linked
2585     * to from emails originating from Special:Email.
2586     *
2587     * @since 1.34
2588     */
2589    public const EnableSpecialMute = [
2590        'default' => false,
2591    ];
2592
2593    /**
2594     * Set to true to enable user-to-user e-mail mutelist.
2595     *
2596     * @since 1.37; previously $wgEnableUserEmailBlacklist
2597     */
2598    public const EnableUserEmailMuteList = [
2599        'default' => false,
2600    ];
2601
2602    /**
2603     * If true put the sending user's email in a Reply-To header
2604     * instead of From (false). ($wgPasswordSender will be used as From.)
2605     *
2606     * Some mailers (eg SMTP) set the SMTP envelope sender to the From value,
2607     * which can cause problems with SPF validation and leak recipient addresses
2608     * when bounces are sent to the sender. In addition, DMARC restrictions
2609     * can cause emails to fail to be received when false.
2610     */
2611    public const UserEmailUseReplyTo = [
2612        'default' => true,
2613    ];
2614
2615    /**
2616     * Minimum time, in hours, which must elapse between password reminder
2617     * emails for a given account. This is to prevent abuse by mail flooding.
2618     */
2619    public const PasswordReminderResendTime = [
2620        'default' => 24,
2621    ];
2622
2623    /**
2624     * The time, in seconds, when an emailed temporary password expires.
2625     */
2626    public const NewPasswordExpiry = [
2627        'default' => 3600 * 24 * 7,
2628    ];
2629
2630    /**
2631     * The time, in seconds, when an email confirmation email expires
2632     */
2633    public const UserEmailConfirmationTokenExpiry = [
2634        'default' => 7 * 24 * 60 * 60,
2635    ];
2636
2637    /**
2638     * The number of days that a user's password is good for. After this number of days, the
2639     * user will be asked to reset their password. Set to false to disable password expiration.
2640     */
2641    public const PasswordExpirationDays = [
2642        'default' => false,
2643    ];
2644
2645    /**
2646     * If a user's password is expired, the number of seconds when they can still login,
2647     * and cancel their password change, but are sent to the password change form on each login.
2648     */
2649    public const PasswordExpireGrace = [
2650        'default' => 3600 * 24 * 7,
2651    ];
2652
2653    /**
2654     * SMTP Mode.
2655     *
2656     * For using a direct (authenticated) SMTP server connection.
2657     * Default to false or fill an array :
2658     *
2659     * ```
2660     * $wgSMTP = [
2661     *     'host'     => 'SMTP domain',
2662     *     'IDHost'   => 'domain for MessageID',
2663     *     'port'     => '25',
2664     *     'auth'     => [true|false],
2665     *     'username' => [SMTP username],
2666     *     'password' => [SMTP password],
2667     * ];
2668     * ```
2669     */
2670    public const SMTP = [
2671        'default' => false,
2672        'type' => 'false|map',
2673    ];
2674
2675    /**
2676     * Additional email parameters, will be passed as the last argument to mail() call.
2677     */
2678    public const AdditionalMailParams = [
2679        'default' => null,
2680    ];
2681
2682    /**
2683     * For parts of the system that have been updated to provide HTML email content, send
2684     * both text and HTML parts as the body of the email
2685     */
2686    public const AllowHTMLEmail = [
2687        'default' => false,
2688    ];
2689
2690    /**
2691     * Allow sending of e-mail notifications with the editor's address as sender.
2692     *
2693     * This setting depends on $wgEnotifRevealEditorAddress also being enabled.
2694     * If both are enabled, notifications for actions from users that have opted-in,
2695     * will be sent to other users with their address as "From" instead of "Reply-To".
2696     *
2697     * If disabled, or not opted-in, notifications come from $wgPasswordSender.
2698     */
2699    public const EnotifFromEditor = [
2700        'default' => false,
2701        'type' => 'boolean',
2702    ];
2703
2704    /**
2705     * Require email authentication before sending mail to an email address.
2706     *
2707     * This is highly recommended. It prevents MediaWiki from being used as an open
2708     * spam relay.
2709     */
2710    public const EmailAuthentication = [
2711        'default' => true,
2712    ];
2713
2714    /**
2715     * Allow users to enable email notification ("enotif") on watchlist changes.
2716     */
2717    public const EnotifWatchlist = [
2718        'default' => false,
2719    ];
2720
2721    /**
2722     * Allow users to enable email notification ("enotif") when someone edits their
2723     * user talk page.
2724     *
2725     * The owner of the user talk page must also have the 'enotifusertalkpages' user
2726     * preference set to true.
2727     */
2728    public const EnotifUserTalk = [
2729        'default' => false,
2730    ];
2731
2732    /**
2733     * Allow sending of e-mail notifications with the editor's address in "Reply-To".
2734     *
2735     * Note, enabling this only actually uses it in notification e-mails if the user
2736     * opted-in to this feature. This feature flag also controls visibility of the
2737     * 'enotifrevealaddr' preference, which, if users opt into, will make e-mail
2738     * notifications about their actions use their address as "Reply-To".
2739     *
2740     * To set the address as "From" instead of "Reply-To", also enable $wgEnotifFromEditor.
2741     *
2742     * If disabled, or not opted-in, notifications come from $wgPasswordSender.
2743     */
2744    public const EnotifRevealEditorAddress = [
2745        'default' => false,
2746        'type' => 'boolean',
2747    ];
2748
2749    /**
2750     * Potentially send notification mails on minor edits to pages. This is enabled
2751     * by default.  If this is false, users will never be notified on minor edits.
2752     *
2753     * If it is true, editors with the 'nominornewtalk' right (typically bots) will still not
2754     * trigger notifications for minor edits they make (to any page, not just user talk).
2755     *
2756     * Finally, if the watcher/recipient has the 'enotifminoredits' user preference set to
2757     * false, they will not receive notifications for minor edits.
2758     *
2759     * User talk notifications are also affected by $wgEnotifMinorEdits, the above settings,
2760     * $wgEnotifUserTalk, and the preference described there.
2761     */
2762    public const EnotifMinorEdits = [
2763        'default' => true,
2764    ];
2765
2766    /**
2767     * Send a generic mail instead of a personalised mail for each user.  This
2768     * always uses UTC as the time zone, and doesn't include the username.
2769     *
2770     * For pages with many users watching, this can significantly reduce mail load.
2771     * Has no effect when using sendmail rather than SMTP.
2772     */
2773    public const EnotifImpersonal = [
2774        'default' => false,
2775    ];
2776
2777    /**
2778     * Maximum number of users to mail at once when using impersonal mail. Should
2779     * match the limit on your mail server.
2780     */
2781    public const EnotifMaxRecips = [
2782        'default' => 500,
2783    ];
2784
2785    /**
2786     * Use real name instead of username in e-mail "from" field.
2787     */
2788    public const EnotifUseRealName = [
2789        'default' => false,
2790    ];
2791
2792    /**
2793     * Array of usernames who will be sent a notification email for every change
2794     * which occurs on a wiki. Users will not be notified of their own changes.
2795     */
2796    public const UsersNotifiedOnAllChanges = [
2797        'default' => [],
2798        'type' => 'map',
2799    ];
2800
2801    // endregion -- end of email settings
2802
2803    /***************************************************************************/
2804    // region  Database settings
2805    /** @name   Database settings */
2806
2807    /**
2808     * Current wiki database name
2809     *
2810     * This should only contain alphanumeric and underscore characters ([A-Za-z0-9_]+).
2811     * Spaces, quotes, backticks, dots, and hyphens are likely to be problematic.
2812     *
2813     * This is used to determine the current/local wiki ID (WikiMap::getCurrentWikiDbDomain).
2814     *
2815     * This should still be set even if $wgLBFactoryConf is configured.
2816     */
2817    public const DBname = [
2818        'default' => 'my_wiki',
2819    ];
2820
2821    /**
2822     * Current wiki database schema name
2823     *
2824     * This should only contain alphanumeric and underscore characters ([A-Za-z0-9_]+).
2825     * Spaces, quotes, backticks, dots, and hyphens are likely to be problematic.
2826     *
2827     * This is used to determine the current/local wiki ID (WikiMap::getCurrentWikiDbDomain).
2828     *
2829     * This should still be set even if $wgLBFactoryConf is configured.
2830     */
2831    public const DBmwschema = [
2832        'default' => null,
2833        'type' => '?string',
2834    ];
2835
2836    /**
2837     * Current wiki database table name prefix
2838     *
2839     * This should only contain alphanumeric and underscore characters ([A-Za-z0-9_]+).
2840     * If it's a non-empty string, then it preferably should end with an underscore.
2841     * Spaces, quotes, backticks, dots, and hyphens are especially likely to be problematic.
2842     *
2843     * This is used to determine the current/local wiki ID (WikiMap::getCurrentWikiDbDomain).
2844     *
2845     * This should still be set even if $wgLBFactoryConf is configured.
2846     */
2847    public const DBprefix = [
2848        'default' => '',
2849    ];
2850
2851    /**
2852     * Database host name or IP address
2853     */
2854    public const DBserver = [
2855        'default' => 'localhost',
2856    ];
2857
2858    /**
2859     * Database port number
2860     */
2861    public const DBport = [
2862        'default' => 5432,
2863    ];
2864
2865    /**
2866     * Database username
2867     */
2868    public const DBuser = [
2869        'default' => 'wikiuser',
2870    ];
2871
2872    /**
2873     * Database user's password
2874     */
2875    public const DBpassword = [
2876        'default' => '',
2877    ];
2878
2879    /**
2880     * Database type
2881     */
2882    public const DBtype = [
2883        'default' => 'mysql',
2884    ];
2885
2886    /**
2887     * Whether to use SSL in DB connection.
2888     *
2889     * This setting is only used if $wgLBFactoryConf['class'] is set to
2890     * '\Wikimedia\Rdbms\LBFactorySimple' and $wgDBservers is an empty array; otherwise
2891     * the 'ssl' parameter of the server array must be set to achieve the same functionality.
2892     */
2893    public const DBssl = [
2894        'default' => false,
2895    ];
2896
2897    /**
2898     * Whether to use compression in DB connection.
2899     *
2900     * This setting is only used $wgLBFactoryConf['class'] is set to
2901     * '\Wikimedia\Rdbms\LBFactorySimple' and $wgDBservers is an empty array; otherwise
2902     * the DBO_COMPRESS flag must be set in the 'flags' option of the database
2903     * connection to achieve the same functionality.
2904     */
2905    public const DBcompress = [
2906        'default' => false,
2907    ];
2908
2909    /**
2910     * Check for warnings after DB queries and throw an exception if an
2911     * unacceptable warning is detected.
2912     *
2913     * This setting is only used if $wgLBFactoryConf['class'] is set to
2914     * '\Wikimedia\Rdbms\LBFactorySimple' and $wgDBservers is an empty array.
2915     * Otherwise, the 'strictWarnings' parameter of the server array must be set
2916     * to achieve the same functionality.
2917     *
2918     * @since 1.42
2919     */
2920    public const DBStrictWarnings = [
2921        'default' => false,
2922    ];
2923
2924    /**
2925     * Separate username for maintenance tasks. Leave as null to use the default.
2926     */
2927    public const DBadminuser = [
2928        'default' => null,
2929    ];
2930
2931    /**
2932     * Separate password for maintenance tasks. Leave as null to use the default.
2933     */
2934    public const DBadminpassword = [
2935        'default' => null,
2936    ];
2937
2938    /**
2939     * Search type.
2940     *
2941     * Leave as null to select the default search engine for the
2942     * selected database type (eg SearchMySQL), or set to a class
2943     * name to override to a custom search engine.
2944     *
2945     * If the canonical name for the search engine doesn't match the class name
2946     * (because it's namespaced for example), you can add a mapping for this in
2947     * SearchMappings in extension.json.
2948     */
2949    public const SearchType = [
2950        'default' => null,
2951    ];
2952
2953    /**
2954     * Alternative search types
2955     *
2956     * Sometimes you want to support multiple search engines for testing. This
2957     * allows users to select their search engine of choice via url parameters
2958     * to Special:Search and the action=search API. If using this, there's no
2959     * need to add $wgSearchType to it, that is handled automatically.
2960     *
2961     * If the canonical name for the search engine doesn't match the class name
2962     * (because it's namespaced for example), you can add a mapping for this in
2963     * SearchMappings in extension.json.
2964     */
2965    public const SearchTypeAlternatives = [
2966        'default' => null,
2967    ];
2968
2969    /**
2970     * MySQL table options to use during installation or update
2971     */
2972    public const DBTableOptions = [
2973        'default' => 'ENGINE=InnoDB, DEFAULT CHARSET=binary',
2974    ];
2975
2976    /**
2977     * SQL Mode - default is turning off all modes, including strict, if set.
2978     *
2979     * null can be used to skip the setting for performance reasons and assume
2980     * DBA has done his best job.
2981     * String override can be used for some additional fun :-)
2982     */
2983    public const SQLMode = [
2984        'default' => '',
2985    ];
2986
2987    /**
2988     * Default group to use when getting database connections.
2989     *
2990     * Will be used as default query group in ILoadBalancer::getConnection.
2991     *
2992     * @since 1.32
2993     */
2994    public const DBDefaultGroup = [
2995        'default' => null,
2996    ];
2997
2998    /**
2999     * To override default SQLite data directory ($docroot/../data)
3000     */
3001    public const SQLiteDataDir = [
3002        'default' => '',
3003    ];
3004
3005    /**
3006     * Shared database for multiple wikis. Commonly used for storing a user table
3007     * for single sign-on. The server for this database must be the same as for the
3008     * main database.
3009     *
3010     * For backwards compatibility the shared prefix is set to the same as the local
3011     * prefix, and the user table is listed in the default list of shared tables.
3012     * The user_properties table is also added so that users will continue to have their
3013     * preferences shared (preferences were stored in the user table prior to 1.16)
3014     *
3015     * $wgSharedTables may be customized with a list of tables to share in the shared
3016     * database. However it is advised to limit what tables you do share as many of
3017     * MediaWiki's tables may have side effects if you try to share them.
3018     *
3019     * $wgSharedPrefix is the table prefix for the shared database. It defaults to
3020     * $wgDBprefix.
3021     *
3022     * $wgSharedSchema is the table schema for the shared database. It defaults to
3023     * $wgDBmwschema.
3024     */
3025    public const SharedDB = [
3026        'default' => null,
3027    ];
3028
3029    /**
3030     * @see self::SharedDB
3031     */
3032    public const SharedPrefix = [
3033        'default' => false,
3034        'dynamicDefault' => [ 'use' => [ 'DBprefix' ] ]
3035    ];
3036
3037    /**
3038     * @param mixed $dbPrefix Value of DBprefix
3039     * @return mixed
3040     */
3041    public static function getDefaultSharedPrefix( $dbPrefix ) {
3042        return $dbPrefix;
3043    }
3044
3045    /**
3046     * @see self::SharedDB
3047     * The installer will add 'actor' to this list for all new wikis.
3048     */
3049    public const SharedTables = [
3050        'default' => [
3051            'user',
3052            'user_properties',
3053            'user_autocreate_serial',
3054        ],
3055        'type' => 'list',
3056    ];
3057
3058    /**
3059     * @see self::SharedDB
3060     * @since 1.23
3061     */
3062    public const SharedSchema = [
3063        'default' => false,
3064        'dynamicDefault' => [ 'use' => [ 'DBmwschema' ] ]
3065    ];
3066
3067    /**
3068     * @param mixed $dbMwschema Value of DBmwschema
3069     * @return mixed
3070     */
3071    public static function getDefaultSharedSchema( $dbMwschema ) {
3072        return $dbMwschema;
3073    }
3074
3075    /**
3076     * Database load balancer
3077     * This is a two-dimensional array, a list of server info structures
3078     * Fields are:
3079     *   - host:        Host name
3080     *   - dbname:      Default database name
3081     *   - user:        DB user
3082     *   - password:    DB password
3083     *   - type:        DB type
3084     *   - driver:      DB driver (when there are multiple drivers)
3085     *
3086     *   - load:        Ratio of DB_REPLICA load, must be >=0, the sum of all loads must be >0.
3087     *                  If this is zero for any given server, no normal query traffic will be
3088     *                  sent to it. It will be excluded from lag checks in maintenance scripts.
3089     *                  The only way it can receive traffic is if groupLoads is used.
3090     *
3091     *   - groupLoads:  (optional) Array of load ratios, the key is the query group name. A query
3092     *                  may belong to several groups, the most specific group defined here is used.
3093     *
3094     *   - flags:       (optional) Bit field of properties:
3095     *                  - DBO_DEFAULT:    Transactional-ize web requests and use autocommit otherwise
3096     *                  - DBO_DEBUG:      Equivalent of $wgDebugDumpSql
3097     *                  - DBO_SSL:        Use TLS connection encryption if available (deprecated)
3098     *                  - DBO_COMPRESS:   Use protocol compression with database connections
3099     *                  - DBO_PERSISTENT: Enables persistent database connections
3100     *
3101     *   - ssl:         (optional) Boolean, whether to use TLS encryption. Overrides DBO_SSL.
3102     *   - max lag:     (optional) Maximum replication lag before a replica DB goes out of rotation
3103     *   - is static:   (optional) Set to true if the dataset is static and no replication is used.
3104     *   - cliMode:     (optional) Connection handles will not assume that requests are short-lived
3105     *                  nor that INSERT..SELECT can be rewritten into a buffered SELECT and INSERT.
3106     *                  This is what DBO_DEFAULT uses to determine when a web request is present.
3107     *                  [Default: true if MW_ENTRY_POINT is 'cli', otherwise false]
3108     *
3109     *   These and any other user-defined properties will be assigned to the mLBInfo member
3110     *   variable of the Database object.
3111     *
3112     * Leave at false to use the single-server variables above. If you set this
3113     * variable, the single-server variables will generally be ignored (except
3114     * perhaps in some command-line scripts).
3115     *
3116     * The first server listed in this array (with key 0) will be the primary. The
3117     * rest of the servers will be replica DBs. To prevent writes to your replica DBs due to
3118     * accidental misconfiguration or MediaWiki bugs, set read_only=1 on all your
3119     * replica DBs in my.cnf. You can set read_only mode at runtime using:
3120     *
3121     * ```
3122     *     SET @@read_only=1;
3123     * ```
3124     *
3125     * Since the effect of writing to a replica DB is so damaging and difficult to clean
3126     * up, we at Wikimedia set read_only=1 in my.cnf on all our DB servers, even
3127     * our primaries, and then set read_only=0 on primaries at runtime.
3128     */
3129    public const DBservers = [
3130        'default' => false,
3131        'type' => 'false|list',
3132    ];
3133
3134    /**
3135     * Configuration for the ILBFactory service
3136     *
3137     * The "class" setting must point to a LBFactory subclass, which is also responsible
3138     * for reading $wgDBservers, $wgDBserver, etc.
3139     *
3140     * To set up a wiki farm with multiple database clusters, set the "class" to
3141     * LBFactoryMulti. See {@link Wikimedia::Rdbms::LBFactoryMulti LBFactoryMulti} docs for
3142     * information on how to configure the rest of the $wgLBFactoryConf array.
3143     */
3144    public const LBFactoryConf = [
3145        'default' => [
3146            'class' => 'Wikimedia\\Rdbms\\LBFactorySimple',
3147        ],
3148        'type' => 'map',
3149        'mergeStrategy' => 'replace',
3150    ];
3151
3152    /**
3153     * After a state-changing request is done by a client, this determines
3154     * how many seconds that client should keep using the primary datacenter.
3155     *
3156     * This avoids unexpected stale or 404 responses due to replication lag.
3157     *
3158     * This must be greater than or equal to
3159     * Wikimedia\Rdbms\ChronologyProtector::POSITION_COOKIE_TTL.
3160     *
3161     * @since 1.27
3162     */
3163    public const DataCenterUpdateStickTTL = [
3164        'default' => 10,
3165    ];
3166
3167    /**
3168     * File to log database errors to
3169     */
3170    public const DBerrorLog = [
3171        'default' => false,
3172    ];
3173
3174    /**
3175     * Timezone to use in the error log.
3176     *
3177     * Defaults to the wiki timezone ($wgLocaltimezone).
3178     *
3179     * A list of usable timezones can found at:
3180     * https://www.php.net/manual/en/timezones.php
3181     *
3182     * **Examples:**
3183     *
3184     * ```
3185     * $wgDBerrorLogTZ = 'UTC';
3186     * $wgDBerrorLogTZ = 'GMT';
3187     * $wgDBerrorLogTZ = 'PST8PDT';
3188     * $wgDBerrorLogTZ = 'Europe/Sweden';
3189     * $wgDBerrorLogTZ = 'CET';
3190     * ```
3191     *
3192     * @since 1.20
3193     */
3194    public const DBerrorLogTZ = [
3195        'default' => false,
3196        'dynamicDefault' => [ 'use' => [ 'Localtimezone' ] ]
3197    ];
3198
3199    public static function getDefaultDBerrorLogTZ( $localtimezone ) {
3200        // NOTE: Extra fallback, in case $localtimezone is ''.
3201        //       Many extsing LocalSettings files have $wgLocaltimezone = ''
3202        //       in them, erroneously generated by the installer.
3203        return $localtimezone ?: self::getDefaultLocaltimezone();
3204    }
3205
3206    /**
3207     * Other wikis on this site, can be administered from a single developer account.
3208     *
3209     * List of wiki DB domain IDs; the format of each ID consist of 1-3 hyphen
3210     *   delimited alphanumeric components (each with no hyphens nor spaces) of any of the forms:
3211     *   - "<DB NAME>-<DB SCHEMA>-<TABLE PREFIX>"
3212     *   - "<DB NAME>-<TABLE PREFIX>"
3213     *   - "<DB NAME>"
3214     * If hyphens appear in any of the components, then the domain ID parsing may not work
3215     * in all cases and site functionality might be affected. If the schema ($wgDBmwschema)
3216     * is left to the default "mediawiki" for all wikis, then the schema should be omitted
3217     * from these IDs.
3218     */
3219    public const LocalDatabases = [
3220        'default' => [],
3221        'type' => 'list',
3222        'items' => [ 'type' => 'string', ],
3223    ];
3224
3225    /**
3226     * If lag is higher than $wgDatabaseReplicaLagWarning, show a warning in some special
3227     * pages (like watchlist). If the lag is higher than $wgDatabaseReplicaLagCritical,
3228     * show a more obvious warning.
3229     *
3230     * @since 1.36
3231     */
3232    public const DatabaseReplicaLagWarning = [
3233        'default' => 10,
3234    ];
3235
3236    /**
3237     * @see self::DatabaseReplicaLagWarning
3238     * @since 1.36
3239     */
3240    public const DatabaseReplicaLagCritical = [
3241        'default' => 30,
3242    ];
3243
3244    /**
3245     * Max execution time for queries of several expensive special pages such as RecentChanges
3246     * in milliseconds.
3247     *
3248     * @since 1.38
3249     */
3250    public const MaxExecutionTimeForExpensiveQueries = [
3251        'default' => 0,
3252    ];
3253
3254    /**
3255     * Mapping of virtual domain to external cluster db.
3256     *
3257     * If no entry is set, the code assumes local database.
3258     * For example, for routing queries of virtual domain 'vdomain'
3259     * to 'wikishared' database in 'extension1' cluster. The config should be like this:
3260     *  [ 'vdomain' => [ 'cluster' => 'extension1', 'db' => 'wikishared' ] ]
3261     *
3262     * If the database needs to be the local domain, just set the 'db' to false.
3263     *
3264     * If you want to get another db in the main cluster, just omit 'cluster'. For example:
3265     *  [ 'centralauth' => [ 'db' => 'centralauth' ] ]
3266     *
3267     * @since 1.41
3268     */
3269    public const VirtualDomainsMapping = [
3270        'default' => [],
3271        'type' => 'map',
3272    ];
3273
3274    /**
3275     * Pagelinks table schema migration stage, for normalizing pl_namespace and pl_title fields.
3276     *
3277     * Use the SCHEMA_COMPAT_XXX flags. Supported values:
3278     *
3279     *   - SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_NEW (SCHEMA_COMPAT_NEW)
3280     *
3281     * History:
3282     *   - 1.41: Added
3283     *   - 1.43: Default has changed to SCHEMA_COMPAT_NEW.
3284     */
3285    public const PageLinksSchemaMigrationStage = [
3286        'default' => SCHEMA_COMPAT_NEW,
3287        'type' => 'integer',
3288    ];
3289
3290    /**
3291     * Gaps in the externallinks table for certain domains.
3292     *
3293     * If you have identified certain domains for which externallinks searches are slow,
3294     * you can use this setting to make MediaWiki skip large el_id ranges,
3295     * rather than having the database scan through them fruitlessly.
3296     *
3297     * Each key in the array is a domain name in el_to_domain_index form,
3298     * e.g. 'https://com.example.'.
3299     * The value is an array with integer keys and values,
3300     * where each entry is a range (from => to, both inclusive)
3301     * of el_id values where this domain is known to have no entries.
3302     * (Subdomains are included, i.e., configuring an entry here guarantees to MediaWiki
3303     * that there are no rows where the el_to_domain_index starts with this value.)
3304     *
3305     * History:
3306     *   - 1.41: Added
3307     */
3308    public const ExternalLinksDomainGaps = [
3309        'default' => [],
3310        'type' => 'map',
3311    ];
3312
3313    // endregion -- End of DB settings
3314
3315    /***************************************************************************/
3316    // region   Content handlers and storage
3317    /** @name   Content handlers and storage */
3318
3319    /**
3320     * Plugins for page content model handling.
3321     *
3322     * Each entry in the array maps a model id to an ObjectFactory specification
3323     * that creates an instance of the appropriate ContentHandler subclass.
3324     *
3325     * @since 1.21
3326     */
3327    public const ContentHandlers = [
3328        'default' =>
3329            [
3330                // the usual case
3331                CONTENT_MODEL_WIKITEXT => [
3332                    'class' => WikitextContentHandler::class,
3333                    'services' => [
3334                        'TitleFactory',
3335                        'ParserFactory',
3336                        'GlobalIdGenerator',
3337                        'LanguageNameUtils',
3338                        'LinkRenderer',
3339                        'MagicWordFactory',
3340                        'ParsoidParserFactory',
3341                    ],
3342                ],
3343                // dumb version, no syntax highlighting
3344                CONTENT_MODEL_JAVASCRIPT => JavaScriptContentHandler::class,
3345                // simple implementation, for use by extensions, etc.
3346                CONTENT_MODEL_JSON => JsonContentHandler::class,
3347                // dumb version, no syntax highlighting
3348                CONTENT_MODEL_CSS => CssContentHandler::class,
3349                // plain text, for use by extensions, etc.
3350                CONTENT_MODEL_TEXT => TextContentHandler::class,
3351                // fallback for unknown models, from imports or extensions that were removed
3352                CONTENT_MODEL_UNKNOWN => FallbackContentHandler::class,
3353            ],
3354        'type' => 'map',
3355    ];
3356
3357    /**
3358     * Associative array mapping namespace IDs to the name of the content model pages in that
3359     * namespace should have by default (use the CONTENT_MODEL_XXX constants). If no special
3360     * content type is defined for a given namespace, pages in that namespace will use the
3361     * CONTENT_MODEL_WIKITEXT
3362     * (except for the special case of JS and CS pages).
3363     *
3364     * @note To determine the default model for a new page's main slot, or any slot in general,
3365     * use SlotRoleHandler::getDefaultModel() together with SlotRoleRegistry::getRoleHandler().
3366     * @since 1.21
3367     */
3368    public const NamespaceContentModels = [
3369        'default' => [],
3370        'type' => 'map',
3371    ];
3372
3373    /**
3374     * Determines which types of text are parsed as wikitext. This does not imply that these kinds
3375     * of texts are also rendered as wikitext, it only means that links, magic words, etc will have
3376     * the effect on the database they would have on a wikitext page.
3377     *
3378     * Note that table of contents information will be *suppressed* for all
3379     * text models in this list other than wikitext.
3380     *
3381     * @todo Make the ToC suppression configurable by the content model
3382     * (T313455), not a side effect of inclusion here.
3383     *
3384     * @todo On the long run, it would be nice to put categories etc into a separate structure,
3385     * or at least parse only the contents of comments in the scripts.
3386     * @since 1.21
3387     */
3388    public const TextModelsToParse = [
3389        'default' => [
3390            CONTENT_MODEL_WIKITEXT, // Just for completeness, wikitext will always be parsed.
3391            CONTENT_MODEL_JAVASCRIPT, // Make categories etc work, people put them into comments.
3392            CONTENT_MODEL_CSS, // Make categories etc work, people put them into comments.
3393        ],
3394        'type' => 'list',
3395    ];
3396
3397    /**
3398     * We can also compress text stored in the 'text' table. If this is set on, new
3399     * revisions will be compressed on page save if zlib support is available. Any
3400     * compressed revisions will be decompressed on load regardless of this setting,
3401     * but will not be readable at all if zlib support is not available.
3402     */
3403    public const CompressRevisions = [
3404        'default' => false,
3405    ];
3406
3407    /**
3408     * List of enabled ExternalStore protocols.
3409     *
3410     * @see \ExternalStoreAccess
3411     *
3412     * ```
3413     * $wgExternalStores = [ "DB" ];
3414     * ```
3415     */
3416    public const ExternalStores = [
3417        'default' => [],
3418        'type' => 'list',
3419    ];
3420
3421    /**
3422     * Shortcut for setting `$wgLBFactoryConf["externalClusters"]`.
3423     *
3424     * This is only applicable when using the default LBFactory
3425     * of {@link Wikimedia::Rdbms::LBFactorySimple LBFactorySimple}.
3426     * It is ignored if a different LBFactory is set, or if `externalClusters`
3427     * is already set explicitly.
3428     *
3429     * @see \ExternalStoreAccess
3430     *
3431     * **Example:**
3432     * Create a cluster named 'blobs_cluster1':
3433     *
3434     * ```
3435     * $wgExternalServers = [
3436     *     'blobs_cluster1' => <array in the same format as $wgDBservers>
3437     * ];
3438     * ```
3439     */
3440    public const ExternalServers = [
3441        'default' => [],
3442        'type' => 'map',
3443    ];
3444
3445    /**
3446     * The place to put new text blobs or false to put them in the text table
3447     * of the local wiki database.
3448     *
3449     * @see \ExternalStoreAccess
3450     *
3451     * **Example:**
3452     *
3453     * ```
3454     * $wgDefaultExternalStore = [ 'DB://cluster1', 'DB://cluster2' ];
3455     * ```
3456     */
3457    public const DefaultExternalStore = [
3458        'default' => false,
3459        'type' => 'list|false',
3460    ];
3461
3462    /**
3463     * Revision text may be cached in the main WAN cache to reduce load on external
3464     * storage servers and object extraction overhead for frequently-loaded revisions.
3465     *
3466     * Set to 0 to disable, or number of seconds before cache expiry.
3467     */
3468    public const RevisionCacheExpiry = [
3469        'default' => SqlBlobStore::DEFAULT_TTL,
3470        'type' => 'integer',
3471    ];
3472
3473    /**
3474     * Revision slots may be cached in the main WAN cache and/or the local server cache
3475     * to reduce load on the database.
3476     *
3477     * Set to 0 to disable, or number of seconds before cache expiry.
3478     */
3479    public const RevisionSlotsCacheExpiry = [
3480        'default' => [
3481            'local' => BagOStuff::TTL_HOUR,
3482            'WAN' => BagOStuff::TTL_DAY,
3483        ],
3484        'type' => 'map',
3485    ];
3486
3487    /**
3488     * Enable page language feature
3489     * Allows setting page language in database
3490     *
3491     * @since 1.24
3492     */
3493    public const PageLanguageUseDB = [
3494        'default' => false,
3495        'type' => 'boolean',
3496    ];
3497
3498    /**
3499     * Specify the difference engine to use.
3500     *
3501     * Supported values:
3502     * - 'external': Use an external diff engine, which must be specified via $wgExternalDiffEngine
3503     * - 'wikidiff2': Use the wikidiff2 PHP extension
3504     * - 'php': PHP implementations included in MediaWiki
3505     *
3506     * The default (null) is to use the first engine that's available.
3507     *
3508     * @since 1.35
3509     */
3510    public const DiffEngine = [
3511        'default' => null,
3512        'type' => '?string',
3513    ];
3514
3515    /**
3516     * Name of the external diff engine to use.
3517     */
3518    public const ExternalDiffEngine = [
3519        'default' => false,
3520        'type' => 'string|false',
3521    ];
3522
3523    /**
3524     * Options for wikidiff2:
3525     *   - useMultiFormat: (bool) Whether to use wikidiff2_multi_format_diff()
3526     *     if it is available. This temporarily defaults to false, during
3527     *     migration to the new code. It is available in wikidiff2 1.14.0+.
3528     *
3529     * The following options are only effective if wikidiff2_multi_format_diff()
3530     * is enabled. See README.md in wikidiff2 for details:
3531     *
3532     *   - numContextLines
3533     *   - changeThreshold
3534     *   - movedLineThreshold
3535     *   - maxMovedLines
3536     *   - maxWordLevelDiffComplexity
3537     *   - maxSplitSize
3538     *   - initialSplitThreshold
3539     *   - finalSplitThreshold
3540     *
3541     * Also:
3542     *   - formatOptions: An array of format-specific overrides. The key may
3543     *     be "inline" or "table" and the value is an array with keys
3544     *     numContextLines, changeThreshold, etc.
3545     * @since 1.41
3546     */
3547    public const Wikidiff2Options = [
3548        'default' => [],
3549        'type' => 'map'
3550    ];
3551
3552    // endregion -- end of Content handlers and storage
3553
3554    /***************************************************************************/
3555    // region   Performance hacks and limits
3556    /** @name   Performance hacks and limits */
3557
3558    /**
3559     * Set a limit on server request wall clock time.
3560     *
3561     * If the Excimer extension is enabled, setting this will cause an exception
3562     * to be thrown after the specified number of seconds. If the extension is
3563     * not available, set_time_limit() will be called instead.
3564     *
3565     * @since 1.36
3566     */
3567    public const RequestTimeLimit = [
3568        'default' => null,
3569        'type' => '?integer',
3570    ];
3571
3572    /**
3573     * The request time limit for "slow" write requests that should not be
3574     * interrupted due to the risk of data corruption.
3575     *
3576     * The limit will only be raised. If the pre-existing time limit is larger,
3577     * then this will have no effect.
3578     *
3579     * @since 1.26
3580     */
3581    public const TransactionalTimeLimit = [
3582        'default' => 120,
3583    ];
3584
3585    /**
3586     * The maximum time critical sections are allowed to stay open. Critical
3587     * sections are used to defer Excimer request timeouts. If Excimer is available
3588     * and this time limit is exceeded, an exception will be thrown at the next
3589     * opportunity, typically after a long-running function like a DB query returns.
3590     *
3591     * Critical sections may wrap long-running queries, and it's generally better
3592     * for the timeout to be handled a few milliseconds later when the critical
3593     * section exits, so this should be a large number.
3594     *
3595     * This limit is ignored in command-line mode.
3596     *
3597     * @since 1.36
3598     */
3599    public const CriticalSectionTimeLimit = [
3600        'default' => 180.0,
3601        'type' => 'float',
3602    ];
3603
3604    /**
3605     * Disable database-intensive features
3606     */
3607    public const MiserMode = [
3608        'default' => false,
3609    ];
3610
3611    /**
3612     * Disable all query pages if miser mode is on, not just some
3613     */
3614    public const DisableQueryPages = [
3615        'default' => false,
3616    ];
3617
3618    /**
3619     * Number of rows to cache in 'querycache' table when miser mode is on
3620     */
3621    public const QueryCacheLimit = [
3622        'default' => 1000,
3623    ];
3624
3625    /**
3626     * Number of links to a page required before it is deemed "wanted"
3627     */
3628    public const WantedPagesThreshold = [
3629        'default' => 1,
3630    ];
3631
3632    /**
3633     * Enable slow parser functions
3634     */
3635    public const AllowSlowParserFunctions = [
3636        'default' => false,
3637    ];
3638
3639    /**
3640     * Allow schema updates
3641     */
3642    public const AllowSchemaUpdates = [
3643        'default' => true,
3644    ];
3645
3646    /**
3647     * Maximum article size in kibibytes
3648     */
3649    public const MaxArticleSize = [
3650        'default' => 2048,
3651    ];
3652
3653    /**
3654     * The minimum amount of memory that MediaWiki "needs"; MediaWiki will try to
3655     * raise PHP's memory limit if it's below this amount.
3656     */
3657    public const MemoryLimit = [
3658        'default' => '50M',
3659    ];
3660
3661    /**
3662     * Configuration for processing pool control, for use in high-traffic wikis.
3663     *
3664     * An implementation is provided in the PoolCounter extension.
3665     *
3666     * This configuration array maps pool types to an associative array. The only
3667     * defined key in the associative array is "class", which gives the class name.
3668     * The remaining elements are passed through to the class as constructor
3669     * parameters.
3670     *
3671     * **Example using local redis instance:**
3672     *
3673     * ```
3674     * $wgPoolCounterConf = [ 'ArticleView' => [
3675     *   'class' => PoolCounterRedis::class,
3676     *   'timeout' => 15, // wait timeout in seconds
3677     *   'workers' => 1, // maximum number of active threads in each pool
3678     *   'maxqueue' => 5, // maximum number of total threads in each pool
3679     *   'servers' => [ '127.0.0.1' ],
3680     *   'redisConfig' => []
3681     * ] ];
3682     * ```
3683     *
3684     * **Example using C daemon from <https://gerrit.wikimedia.org/g/mediawiki/services/poolcounter>**
3685     *
3686     * ```
3687     * $wgPoolCountClientConf = [
3688     *   'servers' => [ '127.0.0.1' ],
3689     *   'timeout' => 0.5,
3690     *   'connect_timeout' => 0.01,
3691     * ];
3692     *
3693     * $wgPoolCounterConf = [ 'ArticleView' => [
3694     *   'class' => 'PoolCounter_Client',
3695     *   'timeout' => 15, // wait timeout in seconds
3696     *   'workers' => 5, // maximum number of active threads in each pool
3697     *   'maxqueue' => 50, // maximum number of total threads in each pool
3698     *   ... any extension-specific options...
3699     * ] ];
3700     * ```
3701     *
3702     * @since 1.16
3703     */
3704    public const PoolCounterConf = [
3705        'default' => null,
3706        'type' => '?map',
3707    ];
3708
3709    /**
3710     * Configuration array for the PoolCounter client.
3711     *
3712     * - servers: Array of hostnames, or hostname:port. The default port is 7531.
3713     * - timeout: Connection timeout.
3714     * - connect_timeout: [Since 1.28] Alternative connection timeout. If set, it is used
3715     *   instead of `timeout` and will be retried once if a connection fails
3716     *   to be established. Background: https://phabricator.wikimedia.org/T105378.
3717     *
3718     * @see \MediaWiki\PoolCounter\PoolCounterClient
3719     * @since 1.16
3720     */
3721    public const PoolCountClientConf = [
3722        'default' => [
3723            'servers' => [
3724                '127.0.0.1'
3725            ],
3726            'timeout' => 0.1,
3727        ],
3728        'type' => 'map',
3729    ];
3730
3731    /**
3732     * Max time (in seconds) a user-generated transaction can spend in writes.
3733     *
3734     * If exceeded, the transaction is rolled back with an error instead of being committed.
3735     *
3736     * @since 1.27
3737     */
3738    public const MaxUserDBWriteDuration = [
3739        'default' => false,
3740        'type' => 'integer|false',
3741    ];
3742
3743    /**
3744     * Max time (in seconds) a job-generated transaction can spend in writes.
3745     *
3746     * If exceeded, the transaction is rolled back with an error instead of being committed.
3747     *
3748     * @since 1.30
3749     */
3750    public const MaxJobDBWriteDuration = [
3751        'default' => false,
3752        'type' => 'integer|false',
3753    ];
3754
3755    /**
3756     * LinkHolderArray batch size
3757     * For debugging
3758     */
3759    public const LinkHolderBatchSize = [
3760        'default' => 1000,
3761    ];
3762
3763    /**
3764     * Maximum number of pages to move at once when moving subpages with a page.
3765     */
3766    public const MaximumMovedPages = [
3767        'default' => 100,
3768    ];
3769
3770    /**
3771     * Force deferred updates to be run before sending a response to the client,
3772     * instead of attempting to run them after sending the response. Setting this
3773     * to true is useful for end-to-end testing, to ensure that the effects of a
3774     * request are visible to any subsequent requests, even if they are made
3775     * immediately after the first one. Note however that this does not ensure
3776     * that database replication is complete, nor does it execute any jobs
3777     * enqueued for later.
3778     * There should be no reason to set this in a normal production environment.
3779     *
3780     * @since 1.38
3781     */
3782    public const ForceDeferredUpdatesPreSend = [
3783        'default' => false,
3784    ];
3785
3786    /**
3787     * Whether site_stats table should have multiple rows. If set to true, in each update,
3788     * one of ten rows gets updated at random to reduce lock wait time in wikis
3789     * that have lots of concurrent edits.
3790     * It should be set to true in really large wikis with big flow of edits,
3791     * Otherwise it can cause inaccuracy in data.
3792     *
3793     * @since 1.39
3794     */
3795    public const MultiShardSiteStats = [
3796        'default' => false,
3797        'type' => 'boolean',
3798    ];
3799
3800    // endregion -- end performance hacks
3801
3802    /***************************************************************************/
3803    // region   Cache settings
3804    /** @name   Cache settings */
3805
3806    /**
3807     * Directory for caching data in the local filesystem. Should not be accessible
3808     * from the web.
3809     *
3810     * Note: if multiple wikis share the same localisation cache directory, they
3811     * must all have the same set of extensions. You can set a directory just for
3812     * the localisation cache using $wgLocalisationCacheConf['storeDirectory'].
3813     */
3814    public const CacheDirectory = [
3815        'default' => false,
3816    ];
3817
3818    /**
3819     * Main cache type. This should be a cache with fast access, but it may have
3820     * limited space. By default, it is disabled, since the stock database cache
3821     * is not fast enough to make it worthwhile.
3822     *
3823     * The options are:
3824     *
3825     * - CACHE_ANYTHING:   Use anything, as long as it works
3826     * - CACHE_NONE:       Do not cache
3827     * - CACHE_DB:         Store cache objects in the DB
3828     * - CACHE_MEMCACHED:  MemCached, must specify servers in $wgMemCachedServers
3829     * - CACHE_ACCEL:      APC or APCu
3830     * - (other):          A string may be used which identifies a cache
3831     *                     configuration in $wgObjectCaches.
3832     *
3833     * For a multi-datacenter setup, the underlying service should be configured
3834     * to broadcast operations by WANObjectCache using Mcrouter or Dynomite.
3835     * See @ref wanobjectcache-deployment "Deploying WANObjectCache".
3836     * To configure the `broadcastRoutingPrefix` WANObjectCache parameter,
3837     * use $wgWANObjectCache.
3838     *
3839     * @see self::MessageCacheType
3840     * @see self::ParserCacheType
3841     */
3842    public const MainCacheType = [
3843        'default' => CACHE_NONE,
3844    ];
3845
3846    /**
3847     * The cache type for storing the contents of the MediaWiki namespace. This
3848     * cache is used for a small amount of data which is expensive to regenerate.
3849     *
3850     * For available types see $wgMainCacheType.
3851     */
3852    public const MessageCacheType = [
3853        'default' => CACHE_ANYTHING,
3854    ];
3855
3856    /**
3857     * The cache type for storing page content HTML (e.g. parsed from wikitext).
3858     *
3859     * Parsing wikitext is considered an expensive operation. It is recommended
3860     * to give your parser cache plenty of storage space, such that long tail cache
3861     * hits are possible.
3862     *
3863     * The default parser cache backend (when MainCacheType is left to CACHE_NONE)
3864     * is effectively CACHE_DB (SqlBagOStuff). If you set up a main cache type
3865     * such as memcached, it is recommended to set this explicitly to CACHE_DB.
3866     *
3867     * Advice for large wiki farms:
3868     * - Consider allocating a dedicated database to ParserCache.
3869     *   Register it in $wgObjectCaches and point $wgParserCacheType to it.
3870     * - Consider using MultiWriteBagOStuff to add a higher tier with Memcached
3871     *   in front of the lower database tier.
3872     * - Consider setting `'purgePeriod' => 0` in the dedicated SqlBagOStuff
3873     *   entry in $wgObjectCaches. This disables the automatic purging of
3874     *   expired rows (which would normally happen in the background of
3875     *   write requests). You can then schedule the purgeParserCache.php script
3876     *   to e.g. once a day prune expired rows from the a dedicated maintenance
3877     *   server.
3878     *
3879     * For available types see $wgMainCacheType.
3880     */
3881    public const ParserCacheType = [
3882        'default' => CACHE_ANYTHING,
3883    ];
3884
3885    /**
3886     * The cache backend for storing session data.
3887     *
3888     * Used by MediaWiki\Session\SessionManager. See $wgMainCacheType for available types.
3889     *
3890     * See [SessionManager Storage expectations](@ref SessionManager-storage-expectations).
3891     */
3892    public const SessionCacheType = [
3893        'default' => CACHE_ANYTHING,
3894    ];
3895
3896    /**
3897     * The cache type for storing language conversion tables,
3898     * which are used when parsing certain text and interface messages.
3899     *
3900     * For available types see $wgMainCacheType.
3901     *
3902     * @since 1.20
3903     */
3904    public const LanguageConverterCacheType = [
3905        'default' => CACHE_ANYTHING,
3906    ];
3907
3908    /**
3909     * Advanced object cache configuration.
3910     *
3911     * Use this to define the class names and constructor parameters which are used
3912     * for the various cache types. Custom cache types may be defined here and
3913     * referenced from $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType,
3914     * or $wgLanguageConverterCacheType.
3915     *
3916     * The format is an associative array where the key is a cache identifier, and
3917     * the value is an associative array of parameters. One of the following
3918     * parameters specifying the class must be given:
3919     *
3920     *   - class: The class name which will be used.
3921     *   - factory: A callable function which will generate a suitable cache object.
3922     *
3923     * The following parameters are shared and understood by most classes:
3924     *
3925     *   - loggroup: The log channel to use.
3926     *
3927     * For SqlBagOStuff, the main configured database will be used, unless one of the following
3928     * three parameters is given:
3929     *
3930     *   - server: Server config map for Database::factory() that describes the database to
3931     *      use for all key operations in the current region. This is overridden by "servers".
3932     *   - servers: Map of tag strings to server config maps, each for Database::factory(),
3933     *      describing the set of database servers on which to distribute key operations in the
3934     *      current region. Data is distributed among the servers via key hashing based on the
3935     *      server tags. Therefore, each tag represents a shard of the dataset. Tags are useful
3936     *      for failover using cold-standby servers and for managing shards with replica servers
3937     *      in multiple regions (each having different hostnames).
3938     *   - cluster: The ExternalStore cluster name to use.
3939     *
3940     * SqlBagOStuff also accepts the following optional parameters:
3941     *
3942     *   - dbDomain: The database name to pass to the LoadBalancer.
3943     *   - multiPrimaryMode: Whether the portion of the dataset belonging to each tag/shard is
3944     *      replicated among one or more regions, with one "co-primary" server in each region.
3945     *      Queries are issued in a manner that provides Last-Write-Wins eventual consistency.
3946     *      This option requires the "server" or "servers" options. Only MySQL, with statement
3947     *      based replication (log_bin='ON' and binlog_format='STATEMENT') is supported. Also,
3948     *      the `modtoken` column must exist on the `objectcache` table(s).
3949     *   - purgePeriod: The average number of object cache writes in between garbage collection
3950     *      operations, where expired entries are removed from the database. Or in other words,
3951     *      the probability of performing a purge is one in every this number. If set to zero,
3952     *      purging will never be done at runtime (for use with PurgeParserCache).
3953     *   - purgeLimit: Maximum number of rows to purge at once.
3954     *   - tableName: The table name to use, default is "objectcache".
3955     *   - shards: The number of tables to use for data storage on each server. If greater than
3956     *      1, table names are formed in the style objectcacheNNN where NNN is the shard index,
3957     *      between 0 and shards-1. The number of digits used in the suffix is the minimum number
3958     *      required to hold the largest shard index. Data is distributed among the tables via
3959     *      key hashing. This helps mitigate MySQL bugs 61735 and 61736.
3960     *   - writeBatchSize: Default maximum number of rows to change in each query for write
3961     *      operations that can be chunked into a set of smaller writes.
3962     *
3963     * For MemcachedPhpBagOStuff parameters see {@link MemcachedPhpBagOStuff::__construct}
3964     *
3965     * For MemcachedPeclBagOStuff parameters see {@link MemcachedPeclBagOStuff::__construct}
3966     *
3967     * For RedisBagOStuff parameters see {@link Wikimedia\ObjectCache\RedisBagOStuff::__construct}
3968     */
3969    public const ObjectCaches = [
3970        'default' => [
3971            CACHE_NONE => [ 'class' => EmptyBagOStuff::class, 'reportDupes' => false ],
3972            CACHE_DB => [ 'class' => SqlBagOStuff::class, 'loggroup' => 'SQLBagOStuff' ],
3973
3974            'memcached-php' => [ 'class' => MemcachedPhpBagOStuff::class, 'loggroup' => 'memcached' ],
3975            'memcached-pecl' => [ 'class' => MemcachedPeclBagOStuff::class, 'loggroup' => 'memcached' ],
3976            'hash' => [ 'class' => HashBagOStuff::class, 'reportDupes' => false ],
3977
3978            // Deprecated since 1.35.
3979            // - To configure a wg*CacheType variable to use the local server cache,
3980            //   use CACHE_ACCEL instead, which will select these automatically.
3981            // - To access the object for the local server cache at run-time,
3982            //   use MediaWikiServices::getLocalServerObjectCache()
3983            //   instead of e.g. ObjectCache::getInstance( 'apcu' ).
3984            // - To instantiate a new one of these explicitly, do so directly
3985            //   by using `new APCUBagOStuff( [ … ] )`
3986            // - To instantiate a new one of these including auto-detection and fallback,
3987            //   use ObjectCache::makeLocalServerCache().
3988            'apc' => [ 'class' => APCUBagOStuff::class, 'reportDupes' => false ],
3989            'apcu' => [ 'class' => APCUBagOStuff::class, 'reportDupes' => false ],
3990        ],
3991        'type' => 'map',
3992    ];
3993
3994    /**
3995     * Extra parameters to the WANObjectCache constructor.
3996     *
3997     * See @ref wanobjectcache-deployment "Deploying WANObjectCache".
3998     *
3999     * @since 1.40
4000     */
4001    public const WANObjectCache = [
4002        'default' => [],
4003        'type' => 'map',
4004    ];
4005
4006    /**
4007     * The stash store backend for MicroStash.
4008     *
4009     * This store should be optimized for ephemeral data, and should be able to handle
4010     * a high volume of writes and reads. The dataset access scope should be across
4011     * all servers that serve the application.
4012     *
4013     * Note that the TTL of the data written to this store must be respected completely
4014     * before the data gets evicted from the store (whether the data is used or not).
4015     * The store must not evict data based on LRU or popularity before the TTL expires.
4016     *
4017     * Expectations for sysadmins:
4018     *
4019     * 1. The data written to this store is generally short-lived (seconds/minutes),
4020     * 2. This store must reliably persist and should not evict data until the TTL expires,
4021     * 3. The same store must be accessed by all application servers (i.e. no visible lag or
4022     *    split reality),
4023     * 4. This store should handle a high volume of both writes and reads,
4024     *    with reads completing with consistently low latencies.
4025     *
4026     * Examples users:
4027     *
4028     * - {@link MediaWiki::Permissions::RateLimiter RateLimiter} (via RStatsFactory)
4029     * - {@link Wikimedia::Rdbms::ChronologyProtector ChronologyProtector}
4030     *    See also [ChronologyProtector requirements](@ref ChronologyProtector-storage-requirements),
4031     *    for more detailed system administrator requirements for multi-DC operations.
4032     *
4033     * Valid options are the keys of {@link $wgObjectCaches}, e.g. CACHE_* constants.
4034     *
4035     * @see \Wikimedia\ObjectCache\BagOStuff
4036     * @since 1.42
4037     */
4038    public const MicroStashType = [
4039        'default' => CACHE_ANYTHING,
4040        'type' => 'string|int',
4041    ];
4042
4043    /**
4044     * The object store type of the main stash.
4045     *
4046     * This should be a fast storage system optimized for lightweight data, both ephemeral and
4047     * permanent, for things like counters, tokens, and blobs. The dataset access scope should
4048     * include all the application servers in all datacenters. Thus, the data must be replicated
4049     * among all datacenters. The store should have "Last Write Wins" eventual consistency. Per
4050     * https://en.wikipedia.org/wiki/PACELC_theorem, the store should act as a PA/EL distributed
4051     * system for these operations.
4052     *
4053     * The multi-datacenter strategy for MediaWiki is to have CDN route HTTP POST requests to the
4054     * primary datacenter and HTTP GET/HEAD/OPTIONS requests to the closest datacenter to the
4055     * client. The stash accepts write operations from any datacenter, but cross-datacenter
4056     * replication is asynchronous.
4057     *
4058     * Modules that use the main stash can expect race conditions to occur if a key can receive
4059     * write operations originating from multiple datacenters. To improve consistency, callers
4060     * should avoid main stash updates during non-POST requests. In any case, callers should
4061     * gracefully tolerate occasional key evictions, temporary inconsistencies among datacenters,
4062     * and violations of linearizability (e.g. during timeouts). Modules that can never handle
4063     * these kinds of anomalies should use other storage mediums.
4064     *
4065     * Valid options are the keys of {@link $wgObjectCaches}, e.g. CACHE_* constants.
4066     *
4067     * @see \Wikimedia\ObjectCache\BagOStuff
4068     * @since 1.26
4069     */
4070    public const MainStash = [
4071        'default' => CACHE_DB,
4072    ];
4073
4074    /**
4075     * Configuration for the caching related to parsoid output. The configuration contains the
4076     * following keys:
4077     *
4078     * - StashType: The type of object store to be used by the ParsoidOutputStash service,
4079     *       which stores the base state of HTML based edits.
4080     *       Valid options are the keys of {@link $wgObjectCaches}, e.g. CACHE_* constants.
4081     *       By default, the value of the MainStash setting will be used.
4082     *       This should be an object store that provides fairly solid persistence guarantees,
4083     *       since losing an entry from the stash may mean that the user can't save their edit.
4084     *       If null, the value of the MainStash configuration setting will be used.
4085     *
4086     * - StashDuration: The number of seconds for which an entry in the stash should be kept.
4087     *       Should be long enough for users to finish editing,
4088     *       since losing an entry from the stash may mean that the user can't save their edit.
4089     *       This is set to one day by default.
4090     *
4091     * - WarmParsoidParserCache: Setting this to true will pre-populate the parsoid parser cache
4092     *       with parsoid outputs on page edits. This speeds up loading HTML into Visual Editor.
4093     *
4094     * @since 1.39
4095     * @unstable Per MediaWiki 1.39, the structure of this configuration is still subject to
4096     *           change.
4097     */
4098    public const ParsoidCacheConfig = [
4099        'type' => 'object',
4100        'properties' => [
4101            'StashType' => [ 'type' => 'int|string|null', 'default' => null ],
4102            'StashDuration' => [ 'type' => 'int', 'default' => 24 * 60 * 60 ],
4103            'WarmParsoidParserCache' => [ 'type' => 'bool', 'default' => false ],
4104        ]
4105    ];
4106
4107    /**
4108     * Sample rate for collecting statistics on Parsoid selective update.
4109     *
4110     * Zero disables collection; 1000 means "1 in every 1000 parses will
4111     * be sampled".
4112     *
4113     * @warning This is EXPERIMENTAL and will disappear once analysis is
4114     * complete.
4115     */
4116    public const ParsoidSelectiveUpdateSampleRate = [
4117        'type' => 'integer',
4118        'default' => 0,
4119    ];
4120
4121    /**
4122     * Per-namespace configuration for the ParserCache filter.
4123     *
4124     * There is one top level key for each cache name supported in ParserCacheFactory.
4125     * The per-namespace configuration is given separately for each cache.
4126     *
4127     * For each namespace, this defines a set of filter options, which are represented
4128     * as an associative array. The following keys are supported in this array:
4129     *
4130     * - minCpuTime: causes the parser cache to not save any output that took fewer
4131     *   than the given number of seconds of CPU time to generate, according to
4132     *   ParserOutput::getTimeProfile(). Set to 0 to always cache, or to
4133     *   PHP_INT_MAX to disable caching for this namespace.
4134     *
4135     * If no filter options are defined for a given namespace, the filter options
4136     * under the "default" key will be used for pages in that namespace.
4137     *
4138     * @since 1.42
4139     */
4140    public const ParserCacheFilterConfig = [
4141        'type' => 'map',
4142        'default' => [ // default value
4143            'pcache' => [ // old parser cache
4144                'default' => [ // all namespaces
4145                    // 0 means no threshold.
4146                    // Use PHP_INT_MAX to disable cache.
4147                    'minCpuTime' => 0
4148                ],
4149            ],
4150            'parsoid-pcache' => [ // parsoid output cache
4151                'default' => [ // all namespaces
4152                    // 0 means no threshold.
4153                    // Use PHP_INT_MAX to disable cache.
4154                    'minCpuTime' => 0
4155                ],
4156            ],
4157        ],
4158        'additionalProperties' => [ // caches
4159            'type' => 'map',
4160            'description' => 'A map of namespace IDs to filter definitions.',
4161            'additionalProperties' => [ // namespaces
4162                'type' => 'map',
4163                'description' => 'A map of filter names to values.',
4164                'properties' => [ // filters
4165                    'minCpuTime' => [ 'type' => 'float' ]
4166                ]
4167            ],
4168        ],
4169    ];
4170
4171    /**
4172     * Secret string for HMAC hashing in ChronologyProtector [optional]
4173     *
4174     * @since 1.41
4175     */
4176    public const ChronologyProtectorSecret = [
4177        'default' => '',
4178        'type' => 'string',
4179    ];
4180
4181    /**
4182     * The expiry time for the parser cache, in seconds.
4183     *
4184     * The default is 86400 (one day).
4185     */
4186    public const ParserCacheExpireTime = [
4187        'default' => 60 * 60 * 24,
4188    ];
4189
4190    /**
4191     * Ratio for use of new parser cache key schema.
4192     *
4193     * For example, 100 means only 1% of entries will be using the new schema.
4194     * And 5 means 20% of entries and so on.
4195     *
4196     * @note this is temporary and will be removed soon.
4197     *
4198     * @unstable
4199     */
4200    public const ParserCacheNewKeySchemaRatio = [
4201        'default' => 0,
4202        'type' => 'integer',
4203    ];
4204
4205    /**
4206     * The expiry time for the parser cache for old revisions, in seconds.
4207     *
4208     * The default is 3600 (cache disabled).
4209     */
4210    public const OldRevisionParserCacheExpireTime = [
4211        'default' => 60 * 60,
4212    ];
4213
4214    /**
4215     * The expiry time to use for session storage, in seconds.
4216     */
4217    public const ObjectCacheSessionExpiry = [
4218        'default' => 60 * 60,
4219    ];
4220
4221    /**
4222     * Whether to use PHP session handling ($_SESSION and session_*() functions)
4223     *
4224     * If the constant MW_NO_SESSION is defined, this is forced to 'disable'.
4225     *
4226     * If the constant MW_NO_SESSION_HANDLER is defined, this is ignored and PHP
4227     * session handling will function independently of SessionHandler.
4228     * SessionHandler and PHP's session handling may attempt to override each
4229     * others' cookies.
4230     *
4231     * @since 1.27
4232     */
4233    public const PHPSessionHandling = [
4234        'default' => 'enable',
4235        'type' => 'string',
4236    ];
4237
4238    /**
4239     * Time in seconds to remember IPs for, for the purposes of logging IP changes within the
4240     * same session. This is meant more for debugging errors in the authentication system than
4241     * for detecting abuse.
4242     *
4243     * @since 1.36
4244     */
4245    public const SuspiciousIpExpiry = [
4246        'default' => false,
4247        'type' => 'integer|false',
4248    ];
4249
4250    /**
4251     * Number of internal PBKDF2 iterations to use when deriving session secrets.
4252     *
4253     * @since 1.28
4254     */
4255    public const SessionPbkdf2Iterations = [
4256        'default' => 10001,
4257    ];
4258
4259    /**
4260     * The list of MemCached servers and port numbers
4261     */
4262    public const MemCachedServers = [
4263        'default' => [ '127.0.0.1:11211', ],
4264        'type' => 'list',
4265    ];
4266
4267    /**
4268     * Use persistent connections to MemCached, which are shared across multiple
4269     * requests.
4270     */
4271    public const MemCachedPersistent = [
4272        'default' => false,
4273    ];
4274
4275    /**
4276     * Read/write timeout for MemCached server communication, in microseconds.
4277     */
4278    public const MemCachedTimeout = [
4279        'default' => 500_000,
4280    ];
4281
4282    /**
4283     * Set this to true to maintain a copy of the message cache on the local server.
4284     *
4285     * This layer of message cache is in addition to the one configured by $wgMessageCacheType.
4286     *
4287     * The local copy is put in APC. If APC is not installed, this setting does nothing.
4288     *
4289     * Note that this is about the message cache, which stores interface messages
4290     * maintained as wiki pages. This is separate from the localisation cache for interface
4291     * messages provided by the software, which is configured by $wgLocalisationCacheConf.
4292     */
4293    public const UseLocalMessageCache = [
4294        'default' => false,
4295    ];
4296
4297    /**
4298     * Instead of caching everything, only cache those messages which have
4299     * been customised in the site content language. This means that
4300     * MediaWiki:Foo/ja is ignored if MediaWiki:Foo doesn't exist.
4301     *
4302     * This option is probably only useful for translatewiki.net.
4303     */
4304    public const AdaptiveMessageCache = [
4305        'default' => false,
4306    ];
4307
4308    /**
4309     * Localisation cache configuration.
4310     *
4311     * Used by service wiring to decide how to construct the
4312     * LocalisationCache instance. Associative array with keys:
4313     *
4314     * class:       The class to use for constructing the LocalisationCache object.
4315     *              This may be overridden by extensions to a subclass of LocalisationCache.
4316     *              Sub classes are expected to still honor the 'storeClass', 'storeDirectory'
4317     *              and 'manualRecache' options where applicable.
4318     *
4319     * storeClass:  Which LCStore class implementation to use. This is optional.
4320     *              The default LocalisationCache class offers the 'store' option
4321     *              as abstraction for this.
4322     *
4323     * store:       How and where to store localisation cache data.
4324     *              This option is ignored if 'storeClass' is explicitly set to a class name.
4325     *              Must be one of:
4326     *              - 'detect' (default): Automatically select 'files' if 'storeDirectory'
4327     *                 or $wgCacheDirectory is set, and fall back to 'db' otherwise.
4328     *              - 'files': Store in $wgCacheDirectory as CDB files.
4329     *              - 'array': Store in $wgCacheDirectory as PHP static array files.
4330     *              - 'db': Store in the l10n_cache database table.
4331     *
4332     * storeDirectory: If the selected LCStore class puts its data in files, then it
4333     *                 will use this directory. If set to false (default), then
4334     *                 $wgCacheDirectory is used instead.
4335     *
4336     * manualRecache: Set this to true to disable cache updates on web requests.
4337     *                Use maintenance/rebuildLocalisationCache.php instead.
4338     */
4339    public const LocalisationCacheConf = [
4340        'properties' => [
4341            'class' => [ 'type' => 'string', 'default' => LocalisationCache::class ],
4342            'store' => [ 'type' => 'string', 'default' => 'detect' ],
4343            'storeClass' => [ 'type' => 'false|string', 'default' => false ],
4344            'storeDirectory' => [ 'type' => 'false|string', 'default' => false ],
4345            'storeServer' => [ 'type' => 'object', 'default' => [] ],
4346            'forceRecache' => [ 'type' => 'bool', 'default' => false ],
4347            'manualRecache' => [ 'type' => 'bool', 'default' => false ],
4348        ],
4349        'type' => 'object',
4350    ];
4351
4352    /**
4353     * Allow client-side caching of pages
4354     */
4355    public const CachePages = [
4356        'default' => true,
4357    ];
4358
4359    /**
4360     * Set this to current time to invalidate all prior cached pages. Affects both
4361     * client-side and server-side caching.
4362     *
4363     * You can get the current date on your server by using the command:
4364     *
4365     * @verbatim date +%Y%m%d%H%M%S
4366     * @endverbatim
4367     */
4368    public const CacheEpoch = [
4369        'default' => '20030516000000',
4370    ];
4371
4372    /**
4373     * Directory where GitInfo will look for pre-computed cache files. If false,
4374     * $wgCacheDirectory/gitinfo will be used.
4375     */
4376    public const GitInfoCacheDirectory = [
4377        'default' => false,
4378    ];
4379
4380    /**
4381     * This will cache static pages for non-logged-in users to reduce
4382     * database traffic on public sites. ResourceLoader requests to default
4383     * language and skins are cached as well as single module requests.
4384     */
4385    public const UseFileCache = [
4386        'default' => false,
4387    ];
4388
4389    /**
4390     * Depth of the subdirectory hierarchy to be created under
4391     * $wgFileCacheDirectory.  The subdirectories will be named based on
4392     * the MD5 hash of the title.  A value of 0 means all cache files will
4393     * be put directly into the main file cache directory.
4394     */
4395    public const FileCacheDepth = [
4396        'default' => 2,
4397    ];
4398
4399    /**
4400     * Append a configured value to the parser cache and the sitenotice key so
4401     * that they can be kept separate for some class of activity.
4402     */
4403    public const RenderHashAppend = [
4404        'default' => '',
4405    ];
4406
4407    /**
4408     * If on, the sidebar navigation links are cached for users with the
4409     * current language set. This can save a touch of load on a busy site
4410     * by shaving off extra message lookups.
4411     *
4412     * However it is also fragile: changing the site configuration, or
4413     * having a variable $wgArticlePath, can produce broken links that
4414     * don't update as expected.
4415     */
4416    public const EnableSidebarCache = [
4417        'default' => false,
4418    ];
4419
4420    /**
4421     * Expiry time for the sidebar cache, in seconds
4422     */
4423    public const SidebarCacheExpiry = [
4424        'default' => 86400,
4425    ];
4426
4427    /**
4428     * When using the file cache, we can store the cached HTML gzipped to save disk
4429     * space. Pages will then also be served compressed to clients that support it.
4430     *
4431     * Requires zlib support enabled in PHP.
4432     */
4433    public const UseGzip = [
4434        'default' => false,
4435    ];
4436
4437    /**
4438     * Invalidate various caches when LocalSettings.php changes. This is equivalent
4439     * to setting $wgCacheEpoch to the modification time of LocalSettings.php, as
4440     * was previously done in the default LocalSettings.php file.
4441     *
4442     * On high-traffic wikis, this should be set to false, to avoid the need to
4443     * check the file modification time, and to avoid the performance impact of
4444     * unnecessary cache invalidations.
4445     */
4446    public const InvalidateCacheOnLocalSettingsChange = [
4447        'default' => true,
4448    ];
4449
4450    /**
4451     * When loading extensions through the extension registration system, this
4452     * can be used to invalidate the cache. A good idea would be to set this to
4453     * one file, you can just `touch` that one to invalidate the cache
4454     *
4455     * **Example:**
4456     *
4457     * ```
4458     * $wgExtensionInfoMTime = filemtime( "$IP/LocalSettings.php" );
4459     * ```
4460     *
4461     * If set to false, the mtime for each individual JSON file will be checked,
4462     * which can be slow if a large number of extensions are being loaded.
4463     */
4464    public const ExtensionInfoMTime = [
4465        'default' => false,
4466        'type' => 'integer|false',
4467    ];
4468
4469    /**
4470     * If this is set to true, phpunit will run integration tests against remote
4471     * caches defined in $wgObjectCaches.
4472     *
4473     * @since 1.38
4474     */
4475    public const EnableRemoteBagOStuffTests = [
4476        'default' => false,
4477    ];
4478
4479    // endregion -- end of cache settings
4480
4481    /***************************************************************************/
4482    // region   HTTP proxy (CDN) settings
4483    /** @name   HTTP proxy (CDN) settings
4484     *
4485     * Many of these settings apply to any HTTP proxy used in front of MediaWiki,
4486     * although they are sometimes still referred to as Squid settings for
4487     * historical reasons.
4488     *
4489     * Achieving a high hit ratio with an HTTP proxy requires special configuration.
4490     * See https://www.mediawiki.org/wiki/Manual:Performance_tuning#Page_view_caching
4491     * for more details.
4492     */
4493
4494    /**
4495     * Enable/disable CDN.
4496     *
4497     * See https://www.mediawiki.org/wiki/Manual:Performance_tuning#Page_view_caching
4498     *
4499     * @since 1.34 Renamed from $wgUseSquid.
4500     */
4501    public const UseCdn = [
4502        'default' => false,
4503    ];
4504
4505    /**
4506     * Add X-Forwarded-Proto to the Vary and Key headers for API requests and
4507     * RSS/Atom feeds. Use this if you have an SSL termination setup
4508     * and need to split the cache between HTTP and HTTPS for API requests,
4509     * feed requests and HTTP redirect responses in order to prevent cache
4510     * pollution. This does not affect 'normal' requests to index.php other than
4511     * HTTP redirects.
4512     */
4513    public const VaryOnXFP = [
4514        'default' => false,
4515    ];
4516
4517    /**
4518     * Internal server name as known to CDN, if different.
4519     *
4520     * **Example:**
4521     *
4522     * ```
4523     * $wgInternalServer = 'http://yourinternal.tld:8000';
4524     * ```
4525     */
4526    public const InternalServer = [
4527        'default' => false,
4528    ];
4529
4530    /**
4531     * Cache TTL for the CDN sent as s-maxage (without ESI) or
4532     * Surrogate-Control (with ESI). Without ESI, you should strip
4533     * out s-maxage in the CDN config.
4534     *
4535     * 18000 seconds = 5 hours, more cache hits with 2678400 = 31 days.
4536     *
4537     * @since 1.34 Renamed from $wgSquidMaxage
4538     */
4539    public const CdnMaxAge = [
4540        'default' => 18000,
4541    ];
4542
4543    /**
4544     * Cache timeout for the CDN when DB replica DB lag is high
4545     *
4546     * @see self::CdnMaxAge
4547     * @since 1.27
4548     */
4549    public const CdnMaxageLagged = [
4550        'default' => 30,
4551    ];
4552
4553    /**
4554     * Cache timeout when delivering a stale ParserCache response due to PoolCounter
4555     * contention.
4556     *
4557     * @since 1.35
4558     */
4559    public const CdnMaxageStale = [
4560        'default' => 10,
4561    ];
4562
4563    /**
4564     * If set, any SquidPurge call on a URL or URLs will send a second purge no less than
4565     * this many seconds later via the job queue. This requires delayed job support.
4566     *
4567     * This should be safely higher than the 'max lag' value in $wgLBFactoryConf, so that
4568     * replica DB lag does not cause page to be stuck in stales states in CDN.
4569     *
4570     * This also fixes race conditions in two-tiered CDN setups (e.g. cdn2 => cdn1 => MediaWiki).
4571     * If a purge for a URL reaches cdn2 before cdn1 and a request reaches cdn2 for that URL,
4572     * it will populate the response from the stale cdn1 value. When cdn1 gets the purge, cdn2
4573     * will still be stale. If the rebound purge delay is safely higher than the time to relay
4574     * a purge to all nodes, then the rebound purge will clear cdn2 after cdn1 was cleared.
4575     *
4576     * @since 1.27
4577     */
4578    public const CdnReboundPurgeDelay = [
4579        'default' => 0,
4580    ];
4581
4582    /**
4583     * Cache timeout for the CDN when a response is known to be wrong or incomplete (due to load)
4584     *
4585     * @see self::CdnMaxAge
4586     * @since 1.27
4587     */
4588    public const CdnMaxageSubstitute = [
4589        'default' => 60,
4590    ];
4591
4592    /**
4593     * Default maximum age for raw CSS/JS accesses
4594     *
4595     * 300 seconds = 5 minutes.
4596     */
4597    public const ForcedRawSMaxage = [
4598        'default' => 300,
4599    ];
4600
4601    /**
4602     * List of proxy servers to purge on changes; default port is 80. Use IP addresses.
4603     *
4604     * When MediaWiki is running behind a proxy, it will trust X-Forwarded-For
4605     * headers sent/modified from these proxies when obtaining the remote IP address
4606     *
4607     * For a list of trusted servers which *aren't* purged, see $wgSquidServersNoPurge.
4608     *
4609     * @since 1.34 Renamed from $wgSquidServers.
4610     */
4611    public const CdnServers = [
4612        'default' => [],
4613        'type' => 'map',
4614    ];
4615
4616    /**
4617     * As with $wgCdnServers, except these servers aren't purged on page changes;
4618     * use to set a list of trusted proxies, etc. Supports both individual IP
4619     * addresses and CIDR blocks.
4620     *
4621     * @since 1.23 Supports CIDR ranges
4622     * @since 1.34 Renamed from $wgSquidServersNoPurge
4623     */
4624    public const CdnServersNoPurge = [
4625        'default' => [],
4626        'type' => 'map',
4627    ];
4628
4629    /**
4630     * Routing configuration for HTCP multicast purging. Add elements here to
4631     * enable HTCP and determine which purges are sent where. If set to an empty
4632     * array, HTCP is disabled.
4633     *
4634     * Each key in this array is a regular expression to match against the purged
4635     * URL, or an empty string to match all URLs. The purged URL is matched against
4636     * the regexes in the order specified, and the first rule whose regex matches
4637     * is used, all remaining rules will thus be ignored.
4638     *
4639     * **Example configuration to send purges for upload.wikimedia.org to one**
4640     * multicast group and all other purges to another:
4641     *
4642     * ```
4643     * $wgHTCPRouting = [
4644     *         '|^https?://upload\.wikimedia\.org|' => [
4645     *                 'host' => '239.128.0.113',
4646     *                 'port' => 4827,
4647     *         ],
4648     *         '' => [
4649     *                 'host' => '239.128.0.112',
4650     *                 'port' => 4827,
4651     *         ],
4652     * ];
4653     * ```
4654     *
4655     * You can also pass an array of hosts to send purges too. This is useful when
4656     * you have several multicast groups or unicast address that should receive a
4657     * given purge.  Multiple hosts support was introduced in MediaWiki 1.22.
4658     *
4659     * **Example of sending purges to multiple hosts:**
4660     *
4661     * ```
4662     * $wgHTCPRouting = [
4663     *     '' => [
4664     *         // Purges to text caches using multicast
4665     *         [ 'host' => '239.128.0.114', 'port' => '4827' ],
4666     *         // Purges to a hardcoded list of caches
4667     *         [ 'host' => '10.88.66.1', 'port' => '4827' ],
4668     *         [ 'host' => '10.88.66.2', 'port' => '4827' ],
4669     *         [ 'host' => '10.88.66.3', 'port' => '4827' ],
4670     *     ],
4671     * ];
4672     * ```
4673     *
4674     * @since 1.22
4675     * @see self::HTCPMulticastTTL
4676     */
4677    public const HTCPRouting = [
4678        'default' => [],
4679        'type' => 'map',
4680    ];
4681
4682    /**
4683     * HTCP multicast TTL.
4684     *
4685     * @see self::HTCPRouting
4686     */
4687    public const HTCPMulticastTTL = [
4688        'default' => 1,
4689    ];
4690
4691    /**
4692     * Should forwarded Private IPs be accepted?
4693     */
4694    public const UsePrivateIPs = [
4695        'default' => false,
4696    ];
4697
4698    /**
4699     * Set this to false if MediaWiki is behind a CDN that re-orders query
4700     * parameters on incoming requests.
4701     *
4702     * MediaWiki sets a large 'Cache-Control: s-maxage=' directive on page
4703     * views only if the request URL matches one of the normal CDN URL forms.
4704     * When 'CdnMatchParameterOrder' is false, the matching algorithm ignores
4705     * the order of URL parameters.
4706     *
4707     * @since 1.39
4708     */
4709    public const CdnMatchParameterOrder = [
4710        'default' => true,
4711    ];
4712
4713    // endregion -- end of HTTP proxy settings
4714
4715    /***************************************************************************/
4716    // region   Language, regional and character encoding settings
4717    /** @name   Language, regional and character encoding settings */
4718
4719    /**
4720     * Site language code. See includes/languages/data/Names.php for languages
4721     * supported by MediaWiki out of the box. Not all languages listed there have
4722     * translations, see languages/messages/ for the list of languages with some
4723     * localisation.
4724     *
4725     * Warning: Don't use any of MediaWiki's deprecated language codes listed in
4726     * LanguageCode::getDeprecatedCodeMapping or $wgDummyLanguageCodes, like "no"
4727     * for Norwegian (use "nb" instead). If you do, things will break unexpectedly.
4728     *
4729     * This defines the default interface language for all users, but users can
4730     * change it in their preferences.
4731     *
4732     * This also defines the language of pages in the wiki. The content is wrapped
4733     * in a html element with lang=XX attribute. This behavior can be overridden
4734     * via hooks, see Title::getPageLanguage.
4735     */
4736    public const LanguageCode = [
4737        'default' => 'en',
4738    ];
4739
4740    /**
4741     * Some languages need different word forms, usually for different cases.
4742     *
4743     * Used in Language::convertGrammar().
4744     *
4745     * **Example:**
4746     *
4747     * ```
4748     * $wgGrammarForms['en']['genitive']['car'] = 'car\'s';
4749     * ```
4750     */
4751    public const GrammarForms = [
4752        'default' => [],
4753        'type' => 'map',
4754    ];
4755
4756    /**
4757     * Treat language links as magic connectors, not inline links
4758     */
4759    public const InterwikiMagic = [
4760        'default' => true,
4761    ];
4762
4763    /**
4764     * Hide interlanguage links from the sidebar
4765     */
4766    public const HideInterlanguageLinks = [
4767        'default' => false,
4768    ];
4769
4770    /**
4771     * List of additional interwiki prefixes that should be treated as
4772     * interlanguage links (i.e. placed in the sidebar).
4773     *
4774     * Notes:
4775     * - This will not do anything unless the prefixes are defined in the interwiki
4776     *   map.
4777     * - The display text for these custom interlanguage links will be fetched from
4778     *   the system message "interlanguage-link-xyz" where xyz is the prefix in
4779     *   this array.
4780     * - A friendly name for each site, used for tooltip text, may optionally be
4781     *   placed in the system message "interlanguage-link-sitename-xyz" where xyz is
4782     *   the prefix in this array.
4783     * - This should be a list of "interwiki prefixes" (ie, what appears in
4784     *   wikitext), and you probably want to add an entry to
4785     *   InterlanguageLinkCodeMap as well to specify which mediawiki internal
4786     *   (or custom) language code this prefix corresponds to, and perhaps
4787     *   then map that custom language code to a language name in
4788     *   ExtraLanguageNames.
4789     */
4790    public const ExtraInterlanguageLinkPrefixes = [
4791        'default' => [],
4792        'type' => 'list',
4793    ];
4794
4795    /**
4796     * Map of interlanguage link codes to language codes. This is useful to override
4797     * what is shown as the language name when the interwiki code does not match it
4798     * exactly
4799     *
4800     * @since 1.35
4801     */
4802    public const InterlanguageLinkCodeMap = [
4803        'default' => [],
4804        'type' => 'map',
4805    ];
4806
4807    /**
4808     * List of language names or overrides for default names in Names.php
4809     */
4810    public const ExtraLanguageNames = [
4811        'default' => [],
4812        'type' => 'map',
4813    ];
4814
4815    /**
4816     * List of mappings from one language code to another.
4817     *
4818     * This array makes the codes not appear as a selectable language on the
4819     * installer.
4820     *
4821     * In Setup.php, the variable $wgDummyLanguageCodes is created by combining
4822     * these codes with a list of "deprecated" codes, which are mostly leftovers
4823     * from renames or other legacy things, and the internal codes 'qqq' and 'qqx'.
4824     * If a mapping in $wgExtraLanguageCodes collide with a built-in mapping, the
4825     * value in $wgExtraLanguageCodes will be used.
4826     *
4827     * @since 1.29
4828     */
4829    public const ExtraLanguageCodes = [
4830        'default' => [
4831            'bh' => 'bho',
4832            'no' => 'nb',
4833            'simple' => 'en',
4834        ],
4835        'type' => 'map',
4836    ];
4837
4838    /**
4839     * Functionally the same as $wgExtraLanguageCodes, but deprecated. Instead of
4840     * appending values to this array, append them to $wgExtraLanguageCodes.
4841     *
4842     * @note Since 1.29, this should not be set directly in LocalSettings,
4843     *       ExtraLanguageCodes should be set instead. However, DummyLanguageCodes
4844     *       will be initialized and can be read internally.
4845     */
4846    public const DummyLanguageCodes = [
4847        'default' => [],
4848        'type' => 'map',
4849    ];
4850
4851    /**
4852     * Set this to always convert certain Unicode sequences to modern ones
4853     * regardless of the content language. This has a small performance
4854     * impact.
4855     *
4856     * @since 1.17
4857     */
4858    public const AllUnicodeFixes = [
4859        'default' => false,
4860    ];
4861
4862    /**
4863     * Set this to eg 'ISO-8859-1' to perform character set conversion when
4864     * loading old revisions not marked with "utf-8" flag. Use this when
4865     * converting a wiki from MediaWiki 1.4 or earlier to UTF-8 without the
4866     * burdensome mass conversion of old text data.
4867     *
4868     * @note This DOES NOT touch any fields other than old_text. Titles, comments,
4869     * user names, etc still must be converted en masse in the database before
4870     * continuing as a UTF-8 wiki.
4871     */
4872    public const LegacyEncoding = [
4873        'default' => false,
4874    ];
4875
4876    /**
4877     * Enable dates like 'May 12' instead of '12 May', if the default date format
4878     * is 'dmy or mdy'.
4879     */
4880    public const AmericanDates = [
4881        'default' => false,
4882    ];
4883
4884    /**
4885     * For Hindi and Arabic use local numerals instead of Western style (0-9)
4886     * numerals in interface.
4887     */
4888    public const TranslateNumerals = [
4889        'default' => true,
4890    ];
4891
4892    /**
4893     * Translation using MediaWiki: namespace.
4894     *
4895     * Interface messages will be loaded from the database.
4896     */
4897    public const UseDatabaseMessages = [
4898        'default' => true,
4899    ];
4900
4901    /**
4902     * Maximum entry size in the message cache, in bytes
4903     */
4904    public const MaxMsgCacheEntrySize = [
4905        'default' => 10000,
4906    ];
4907
4908    /**
4909     * Whether to enable language variant conversion.
4910     */
4911    public const DisableLangConversion = [
4912        'default' => false,
4913    ];
4914
4915    /**
4916     * Whether to enable language variant conversion for links.
4917     * Note that this option is slightly misnamed.
4918     */
4919    public const DisableTitleConversion = [
4920        'default' => false,
4921    ];
4922
4923    /**
4924     * Default variant code. If false, the default will be the static default
4925     * variant of the language.
4926     */
4927    public const DefaultLanguageVariant = [
4928        'default' => false,
4929    ];
4930
4931    /**
4932     * Whether to enable the pig Latin variant of English (en-x-piglatin),
4933     * used to ease variant development work.
4934     */
4935    public const UsePigLatinVariant = [
4936        'default' => false,
4937    ];
4938
4939    /**
4940     * Disabled variants array of language variant conversion.
4941     *
4942     * **Example:**
4943     *
4944     * ```
4945     * $wgDisabledVariants[] = 'zh-mo';
4946     * $wgDisabledVariants[] = 'zh-my';
4947     * ```
4948     */
4949    public const DisabledVariants = [
4950        'default' => [],
4951        'type' => 'map',
4952    ];
4953
4954    /**
4955     * Like $wgArticlePath, but on multi-variant wikis, this provides a
4956     * path format that describes which parts of the URL contain the
4957     * language variant.
4958     *
4959     * **Example:**
4960     *
4961     * ```
4962     * $wgLanguageCode = 'sr';
4963     * $wgVariantArticlePath = '/$2/$1';
4964     * $wgArticlePath = '/wiki/$1';
4965     * ```
4966     *
4967     * A link to /wiki/ would be redirected to /sr/Главна_страна
4968     *
4969     * It is important that $wgArticlePath not overlap with possible values
4970     * of $wgVariantArticlePath.
4971     */
4972    public const VariantArticlePath = [
4973        'default' => false,
4974    ];
4975
4976    /**
4977     * Whether to enable the 'x-xss' language code, used for development.
4978     *
4979     * When enabled, the language code 'x-xss' (e.g. via ?uselang=x-xss) can
4980     * be used to test correct message escaping at scale, to prevent
4981     * cross-site scripting. In this "language", every message becomes an HTML
4982     * snippet which attempts to alert the message key. Well-written code will
4983     * correctly escape all of these messages. If any alerts are actually
4984     * fired in the browser, the message is not being escaped correctly;
4985     * either the offending code should be fixed, or the message should be
4986     * added to {@link self::RawHtmlMessages}.
4987     *
4988     * @see https://www.mediawiki.org/wiki/Special:MyLanguage/Cross-site_scripting
4989     * @since 1.41
4990     */
4991    public const UseXssLanguage = [
4992        'default' => false,
4993    ];
4994
4995    /**
4996     * Show a bar of language selection links in the user login and user
4997     * registration forms; edit the "loginlanguagelinks" message to
4998     * customise these.
4999     */
5000    public const LoginLanguageSelector = [
5001        'default' => false,
5002    ];
5003
5004    /**
5005     * When translating messages with wfMessage(), it is not always clear what
5006     * should be considered UI messages and what should be content messages.
5007     *
5008     * For example, for the English Wikipedia, there should be only one 'mainpage',
5009     * so when getting the link for 'mainpage', we should treat it as site content
5010     * and call ->inContentLanguage()->text(), but for rendering the text of the
5011     * link, we call ->text(). The code behaves this way by default. However,
5012     * sites like the Wikimedia Commons do offer different versions of 'mainpage'
5013     * and the like for different languages. This array provides a way to override
5014     * the default behavior.
5015     *
5016     * **Example:**
5017     * To allow language-specific main page and community
5018     * portal:
5019     *
5020     * ```
5021     * $wgForceUIMsgAsContentMsg = [ 'mainpage', 'portal-url' ];
5022     * ```
5023     */
5024    public const ForceUIMsgAsContentMsg = [
5025        'default' => [],
5026        'type' => 'map',
5027    ];
5028
5029    /**
5030     * List of messages which might contain raw HTML.
5031     *
5032     * Extensions should add their insecure raw HTML messages to extension.json.
5033     * The list is used for access control:
5034     * changing messages listed here will require editsitecss and editsitejs rights.
5035     *
5036     * Message names must be given with underscores rather than spaces and with lowercase first
5037     * letter.
5038     *
5039     * @since 1.32
5040     */
5041    public const RawHtmlMessages = [
5042        'default' => [
5043            'copyright',
5044            'history_copyright',
5045            'googlesearch',
5046        ],
5047        'type' => 'list',
5048        'items' => [ 'type' => 'string', ],
5049    ];
5050
5051    /**
5052     * Whether on-wiki overrides for the 'copyright' and 'history_copyright' messages, which allow raw
5053     * HTML, will be used.
5054     *
5055     * @since 1.43
5056     */
5057    public const AllowRawHtmlCopyrightMessages = [
5058        'default' => true,
5059        'type' => 'boolean',
5060    ];
5061
5062    /**
5063     * Fake out the timezone that the server thinks it's in. This will be used for
5064     * date display and not for what's stored in the DB. Leave to null to retain
5065     * your server's OS-based timezone value.
5066     *
5067     * This variable is currently used only for signature formatting and for local
5068     * time/date parser variables ({{LOCALTIME}} etc.)
5069     *
5070     * Timezones can be translated by editing MediaWiki messages of type
5071     * timezone-nameinlowercase like timezone-utc.
5072     *
5073     * A list of usable timezones can found at:
5074     * https://www.php.net/manual/en/timezones.php
5075     *
5076     * **Examples:**
5077     *
5078     * ```
5079     * $wgLocaltimezone = 'UTC';
5080     * $wgLocaltimezone = 'GMT';
5081     * $wgLocaltimezone = 'PST8PDT';
5082     * $wgLocaltimezone = 'Europe/Sweden';
5083     * $wgLocaltimezone = 'CET';
5084     * ```
5085     */
5086    public const Localtimezone = [
5087        'dynamicDefault' => true,
5088    ];
5089
5090    public static function getDefaultLocaltimezone(): string {
5091        // This defaults to the `date.timezone` value of the PHP INI option. If this option is not set,
5092        // it falls back to UTC.
5093        $localtimezone = date_default_timezone_get();
5094        if ( !$localtimezone ) {
5095            // Make doubly sure we have a valid time zone, even if date_default_timezone_get()
5096            // returned garbage.
5097            $localtimezone = 'UTC';
5098        }
5099
5100        return $localtimezone;
5101    }
5102
5103    /**
5104     * Set an offset from UTC in minutes to use for the default timezone setting
5105     * for anonymous users and new user accounts.
5106     *
5107     * This setting is used for most date/time displays in the software, and is
5108     * overridable in user preferences. It is *not* used for signature timestamps.
5109     *
5110     * By default, this will be set to match $wgLocaltimezone.
5111     */
5112    public const LocalTZoffset = [
5113        'dynamicDefault' => [ 'use' => [ 'Localtimezone' ] ]
5114    ];
5115
5116    public static function getDefaultLocalTZoffset( $localtimezone ): int {
5117        // NOTE: Extra fallback, in case $localtimezone is ''.
5118        //       Many extsing LocalSettings files have $wgLocaltimezone = ''
5119        //       in them, erroneously generated by the installer.
5120        $localtimezone = $localtimezone ?: self::getDefaultLocaltimezone();
5121
5122        $offset = ( new DateTimeZone( $localtimezone ) )->getOffset( new DateTime() );
5123        return (int)( $offset / 60 );
5124    }
5125
5126    /**
5127     * Map of Unicode characters for which capitalization is overridden in
5128     * Language::ucfirst. The characters should be
5129     * represented as char_to_convert => conversion_override. See T219279 for details
5130     * on why this is useful during php version transitions.
5131     *
5132     * @since 1.34
5133     */
5134    public const OverrideUcfirstCharacters = [
5135        'default' => [],
5136        'type' => 'map',
5137    ];
5138
5139    // endregion -- End of language/charset settings
5140
5141    /***************************************************************************/
5142    // region   Output format and skin settings
5143    /** @name   Output format and skin settings */
5144
5145    /**
5146     * The default Content-Type header.
5147     */
5148    public const MimeType = [
5149        'default' => 'text/html',
5150    ];
5151
5152    /**
5153     * Defines the value of the version attribute in the &lt;html&gt; tag, if any.
5154     *
5155     * If your wiki uses RDFa, set it to the correct value for RDFa+HTML5.
5156     * Correct current values are 'HTML+RDFa 1.0' or 'XHTML+RDFa 1.0'.
5157     * See also https://www.w3.org/TR/rdfa-in-html/#document-conformance
5158     *
5159     * @since 1.16
5160     */
5161    public const Html5Version = [
5162        'default' => null,
5163    ];
5164
5165    /**
5166     * Whether to label the store-to-database-and-show-to-others button in the editor
5167     * as "Save page"/"Save changes" if false (the default) or, if true, instead as
5168     * "Publish page"/"Publish changes".
5169     *
5170     * @since 1.28
5171     */
5172    public const EditSubmitButtonLabelPublish = [
5173        'default' => false,
5174    ];
5175
5176    /**
5177     * Permit other namespaces in addition to the w3.org default.
5178     *
5179     * Use the prefix for the key and the namespace for the value.
5180     *
5181     * **Example:**
5182     *
5183     * ```
5184     * $wgXhtmlNamespaces['svg'] = 'http://www.w3.org/2000/svg';
5185     * ```
5186     *
5187     * Normally we wouldn't have to define this in the root "<html>"
5188     * element, but IE needs it there in some circumstances.
5189     *
5190     * This is ignored if $wgMimeType is set to a non-XML MIME type.
5191     */
5192    public const XhtmlNamespaces = [
5193        'default' => [],
5194        'type' => 'map',
5195    ];
5196
5197    /**
5198     * Site notice shown at the top of each page
5199     *
5200     * MediaWiki:Sitenotice page, which will override this. You can also
5201     * provide a separate message for logged-out users using the
5202     * MediaWiki:Anonnotice page.
5203     */
5204    public const SiteNotice = [
5205        'default' => '',
5206    ];
5207
5208    /**
5209     * Override the ability of certain browsers to attempt to autodetect dataformats in pages.
5210     *
5211     * This is a default feature of many mobile browsers, but can have a lot of false positives,
5212     * where for instance, year ranges are confused with phone numbers.
5213     * The default of this setting is to disable telephone number data detection.
5214     * Set BrowserFormatDetection to false to fallback to the browser defaults.
5215     *
5216     * @since 1.37
5217     * @see https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html
5218     */
5219    public const BrowserFormatDetection = [
5220        'default' => 'telephone=no',
5221        'type' => 'string',
5222    ];
5223
5224    /**
5225     * An array of open graph tags which should be added by all skins.
5226     *
5227     * Accepted values are "og:site_name", "og:title", "og:type" and "twitter:card".
5228     * Since some of these fields can be provided by extensions it defaults to an empty array.
5229     *
5230     * @since 1.36
5231     */
5232    public const SkinMetaTags = [
5233        'default' => [],
5234        'type' => 'map',
5235    ];
5236
5237    /**
5238     * Default skin, for new users and anonymous visitors. Registered users may
5239     * change this to any one of the other available skins in their preferences.
5240     */
5241    public const DefaultSkin = [
5242        'default' => 'vector-2022',
5243    ];
5244
5245    /**
5246     * Fallback skin used when the skin defined by $wgDefaultSkin can't be found.
5247     *
5248     * @since 1.24
5249     */
5250    public const FallbackSkin = [
5251        'default' => 'fallback',
5252    ];
5253
5254    /**
5255     * Specify the names of skins that should not be presented in the list of
5256     * available skins in user preferences.
5257     *
5258     * NOTE: This does not uninstall the skin, and it will still be accessible
5259     * via the `useskin` query parameter. To uninstall a skin, remove its inclusion
5260     * from LocalSettings.php.
5261     *
5262     * @see \SkinFactory::getAllowedSkins
5263     */
5264    public const SkipSkins = [
5265        'default' => [],
5266        'type' => 'map',
5267    ];
5268
5269    /**
5270     * Disable output compression (enabled by default if zlib is available)
5271     */
5272    public const DisableOutputCompression = [
5273        'default' => false,
5274    ];
5275
5276    /**
5277     * How should section IDs be encoded?
5278     * This array can contain 1 or 2 elements, each of them can be one of:
5279     * - 'html5'  is modern HTML5 style encoding with minimal escaping. Displays Unicode
5280     *            characters in most browsers' address bars.
5281     *
5282     * - 'legacy' is old MediaWiki-style encoding, e.g. 啤酒 turns into .E5.95.A4.E9.85.92
5283     *
5284     * The first element of this array specifies the primary mode of escaping IDs. This
5285     * is what users will see when they e.g. follow an [[#internal link]] to a section of
5286     * a page.
5287     *
5288     * The optional second element defines a fallback mode, useful for migrations.
5289     * If present, it will direct MediaWiki to add empty <span>s to every section with its
5290     * id attribute set to fallback encoded title so that links using the previous encoding
5291     * would still work.
5292     *
5293     * Example: you want to migrate your wiki from 'legacy' to 'html5'
5294     *
5295     * On the first step, set this variable to [ 'legacy', 'html5' ]. After a while, when
5296     * all caches (parser, HTTP, etc.) contain only pages generated with this setting,
5297     * flip the value to [ 'html5', 'legacy' ]. This will result in all internal links being
5298     * generated in the new encoding while old links (both external and cached internal) will
5299     * still work. After a long time, you might want to ditch backwards compatibility and
5300     * set it to [ 'html5' ]. After all, pages get edited, breaking incoming links no matter which
5301     * fragment mode is used.
5302     *
5303     * @since 1.30
5304     */
5305    public const FragmentMode = [
5306        'default' => [ 'html5', 'legacy', ],
5307        'type' => 'list',
5308    ];
5309
5310    /**
5311     * Which ID escaping mode should be used for external interwiki links? See documentation
5312     * for $wgFragmentMode above for details of each mode. Because you can't control external sites,
5313     * this setting should probably always be 'legacy', unless every wiki you link to has converted
5314     * to 'html5'.
5315     *
5316     * @since 1.30
5317     */
5318    public const ExternalInterwikiFragmentMode = [
5319        'default' => 'legacy',
5320    ];
5321
5322    /**
5323     * Abstract list of footer icons for skins in place of old copyrightico and poweredbyico code
5324     * You can add new icons to the built in copyright or poweredby, or you can create
5325     * a new block. Though note that you may need to add some custom css to get good styling
5326     * of new blocks in monobook. vector and modern should work without any special css.
5327     *
5328     * $wgFooterIcons itself is a key/value array.
5329     * The key is the name of a block that the icons will be wrapped in. The final id varies
5330     * by skin; Monobook and Vector will turn poweredby into f-poweredbyico while Modern
5331     * turns it into mw_poweredby.
5332     * The value is either key/value array of icons or a string.
5333     * In the key/value array the key may or may not be used by the skin but it can
5334     * be used to find the icon and unset it or change the icon if needed.
5335     * This is useful for disabling icons that are set by extensions.
5336     * The value should be either a string or an array. If it is a string it will be output
5337     * directly as html, however some skins may choose to ignore it. An array is the preferred
5338     * format for the icon, the following keys are used:
5339     * - src: An absolute url to the image to use for the icon, this is recommended
5340     *        but not required, however some skins will ignore icons without an image
5341     * - srcset: optional additional-resolution images; see HTML5 specs
5342     * - url: The url to use in the a element around the text or icon, if not set an a element will
5343     *        not be outputted
5344     * - alt: This is the text form of the icon, it will be displayed without an image in
5345     *        skins like Modern or if src is not set, and will otherwise be used as
5346     *        the alt="" for the image. This key is required.
5347     * - width and height: If the icon specified by src is not of the standard size
5348     *                     you can specify the size of image to use with these keys.
5349     *                     Otherwise they will default to the standard 88x31.
5350     *
5351     * @todo Reformat documentation.
5352     */
5353    public const FooterIcons = [
5354        'default' => [
5355            "copyright" => [
5356                "copyright" => [], // placeholder for the built in copyright icon
5357            ],
5358            "poweredby" => [
5359                "mediawiki" => [
5360                    // Defaults to point at
5361                    // "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
5362                    // plus srcset for 1.5x, 2x resolution variants.
5363                    "src" => null,
5364                    "url" => "https://www.mediawiki.org/",
5365                    "alt" => "Powered by MediaWiki",
5366                ]
5367            ],
5368        ],
5369        'type' => 'map',
5370    ];
5371
5372    /**
5373     * Login / create account link behavior when it's possible for anonymous users
5374     * to create an account.
5375     *
5376     * - true = use a combined login / create account link
5377     * - false = split login and create account into two separate links
5378     */
5379    public const UseCombinedLoginLink = [
5380        'default' => false,
5381    ];
5382
5383    /**
5384     * Display user edit counts in various prominent places.
5385     */
5386    public const Edititis = [
5387        'default' => false,
5388    ];
5389
5390    /**
5391     * Some web hosts attempt to rewrite all responses with a 404 (not found)
5392     * status code, mangling or hiding MediaWiki's output. If you are using such a
5393     * host, you should start looking for a better one. While you're doing that,
5394     * set this to false to convert some of MediaWiki's 404 responses to 200 so
5395     * that the generated error pages can be seen.
5396     *
5397     * In cases where for technical reasons it is more important for MediaWiki to
5398     * send the correct status code than for the body to be transmitted intact,
5399     * this configuration variable is ignored.
5400     */
5401    public const Send404Code = [
5402        'default' => true,
5403    ];
5404
5405    /**
5406     * The $wgShowRollbackEditCount variable is used to show how many edits can be rolled back.
5407     *
5408     * The numeric value of the variable controls how many edits MediaWiki will look back to
5409     * determine whether a rollback is allowed (by checking that they are all from the same author).
5410     * If the value is false or 0, the edits are not counted. Disabling this will prevent MediaWiki
5411     * from hiding some useless rollback links.
5412     *
5413     * @since 1.20
5414     */
5415    public const ShowRollbackEditCount = [
5416        'default' => 10,
5417    ];
5418
5419    /**
5420     * Output a <link rel="canonical"> tag on every page indicating the canonical
5421     * server which should be used, i.e. $wgServer or $wgCanonicalServer. Since
5422     * detection of the current server is unreliable, the link is sent
5423     * unconditionally.
5424     */
5425    public const EnableCanonicalServerLink = [
5426        'default' => false,
5427    ];
5428
5429    /**
5430     * List of interwiki logos overrides.
5431     * This is used by the sister project sidebar. This list accept a key equal to the
5432     * interwiki ID (as defined in the interwiki links), and accept a Codex icon name
5433     * (https://doc.wikimedia.org/codex/latest/icons/all-icons.html) or a base URL for
5434     * the given interwiki.
5435     *
5436     * Example :
5437     * $wgInterwikiLogoOverride = [
5438     *     'c' => 'logoWikimediaCommons',
5439     *     'wikit' => 'https://mySpecialWiki.com'
5440     * ];
5441     */
5442    public const InterwikiLogoOverride = [
5443        'default' => [],
5444        'type' => 'list',
5445        'items' => [ 'type' => 'string', ],
5446    ];
5447
5448    // endregion -- End of output format settings
5449
5450    /***************************************************************************/
5451    // region   ResourceLoader settings
5452    /** @name   ResourceLoader settings */
5453
5454    /**
5455     * Formerly a workaround for a security vulnerability caused by installation
5456     * of Flash as a browser extension.
5457     *
5458     * @since 1.25
5459     * @deprecated since 1.39
5460     */
5461    public const MangleFlashPolicy = [
5462        'default' => true,
5463        'obsolete' => 'Since 1.39; no longer has any effect.',
5464        'description' => 'Has been emitting warnings since 1.39 (LTS). ' .
5465            'Can be removed completely in 1.44, assuming 1.43 is an LTS release.'
5466    ];
5467
5468    /**
5469     * Define extra client-side modules to be registered with ResourceLoader.
5470     *
5471     * @note It is recommended to define modules using the `ResourceModule` attribute
5472     * in `extension.json` or `skin.json` when possible (instead of via PHP global variables).
5473     *
5474     * Registration is internally handled by ResourceLoader::register.
5475     *
5476     * ## Available modules
5477     *
5478     * Modules that ship with %MediaWiki core are registered via
5479     * resources/Resources.php. For a full list with documentation, see:
5480     * [ResourceLoader/Core_modules](https://www.mediawiki.org/wiki/ResourceLoader/Core_modules).
5481     *
5482     * ## Options
5483     *
5484     * - class `{string}`:
5485     *   By default a module is assumed to bundle file resources
5486     *   as handled by the MediaWiki\ResourceLoader\FileModule class. Use this option
5487     *   to use a different implementation of MediaWiki\ResourceLoader\Module instead.
5488     *
5489     *   Default: `\MediaWiki\ResourceLoader\FileModule`
5490     *
5491     * - factory `{string}`:
5492     *   Override the instantiation of the MediaWiki\ResourceLoader\Module
5493     *   class using a PHP callback. This allows dependency injection to be used.
5494     *   This option cannot be combined with the `class` option.
5495     *
5496     *   Since: MW 1.30
5497     *
5498     * - dependencies `{string[]|string}`:
5499     *   Modules that must be executed before this module.
5500     *   Module name string or list of module name strings.
5501     *
5502     *   Default: `[]`
5503     *
5504     * - deprecated `{boolean|string}`:
5505     *   Whether the module is deprecated and usage is discouraged.
5506     *   Set to boolean true, or a string to include in the warning message.
5507     *
5508     *   Default: `false`
5509     *
5510     * - group `{string}`:
5511     *   Optional request group to override which modules may be downloaded
5512     *   together in an HTTP batch request. By default, any two modules may be
5513     *   loaded together in the same batch request. Set this option to a
5514     *   descriptive string to give the module its own HTTP request. To allow
5515     *   other modules to join this new request, give those the same request group.
5516     *
5517     *   Use this option with caution. The default behaviour is well-tuned already,
5518     *   and setting this often does more harm than good. For more about request
5519     *   balancing optimisations, see
5520     *   [ResourceLoader/Architecture#Balance](https://www.mediawiki.org/wiki/ResourceLoader/Architecture#Balance).
5521     *
5522     * - skipFunction `{string}`:
5523     *   Allow this module to be satisfied as dependency without actually loading
5524     *   or executing scripts from the server, if the specified JavaScript function
5525     *   returns true.
5526     *
5527     *   Use this to provide polyfills that are natively available in newer browsers.
5528     *   Specify the relative path to a JavaScript file containing a top-level return
5529     *   statement. The contents of the file should not contain any wrapping function,
5530     *   it will be wrapped by %ResourceLoader in an anonymous function and invoked
5531     *   when the module is considered for loading.
5532     *
5533     * ## FileModule options
5534     *
5535     * - localBasePath `{string}`:
5536     *   Base file path to prepend to relative file paths specified in other options.
5537     *
5538     *   Default: `$IP`
5539     *
5540     * - remoteBasePath `{string}`:
5541     *   Base URL path to prepend to relative file paths specified in other options.
5542     *   This is used to form URLs for files, such as when referencing images in
5543     *   stylesheets, or in debug mode to serve JavaScript files directly.
5544     *
5545     *   Default: @ref $wgResourceBasePath (which defaults to @ref $wgScriptPath)
5546     *
5547     * - remoteExtPath `{string}`:
5548     *   Shortcut for `remoteBasePath` that is relative to $wgExtensionAssetsPath.
5549     *   Use this when defining modules from an extension, so as to avoid hardcoding
5550     *   the script path of the %MediaWiki install or the location of the extensions
5551     *   directory.
5552     *
5553     *   This option is mutually exclusive with `remoteBasePath`.
5554     *
5555     * - styles `{string[]|string|array<string,array>}`:
5556     *   Styles to always include in the module.
5557     *   %File path or list of file paths, relative to `localBasePath`.
5558     *   The stylesheet can be automatically wrapped in a `@media` query by specifying
5559     *   the file path as the key in an object (instead of the value), with the value
5560     *   specifying a `media` query.
5561     *
5562     *   See @ref wgResourceModules-example-stylesheet "Stylesheet examples" below.
5563     *
5564     *   See also @ref $wgResourceModuleSkinStyles.
5565     *
5566     *   Extended options:
5567     *
5568     *   - skinStyles `{string[]|string}`: Styles to include in specific skin contexts.
5569     *     Array keyed is by skin name with file path or list of file paths as value,
5570     *     relative to `localBasePath`.
5571     *
5572     *   Default: `[]`
5573     *
5574     * - noflip `{boolean}`:
5575     *   By default, CSSJanus will be used automatically to perform LTR-to-RTL flipping
5576     *   when loaded in a right-to-left (RTL) interface language context.
5577     *   Use this option to skip CSSJanus LTR-to-RTL flipping for this module, for example
5578     *   when registering an external library that already handles RTL styles.
5579     *
5580     *   Default: `false`
5581     *
5582     * - packageFiles `{string[]|array[]}`
5583     *   Specify script files and (virtual) data files to include in the module.
5584     *   Each internal JavaScript file retains its own local module scope and its
5585     *   private exports can be accessed separately by other client-side code in the
5586     *   same module, via the local `require()` function.
5587     *
5588     *   Modules that use package files should export any public API methods using
5589     *   `module.exports`.
5590     *
5591     *   See examples at
5592     *     [ResourceLoader/Package_files](https://www.mediawiki.org/wiki/ResourceLoader/Package_files)
5593     *     on mediawiki.org.
5594     *
5595     *   The `packageFiles` feature cannot be combined with legacy scripts that use
5596     *   the `scripts` option, including its extended variants `languageScripts`,
5597     *   `skinScripts`, and `debugScripts`.
5598     *
5599     *   Since: MW 1.33
5600     *
5601     *   Default: `[]`
5602     *
5603     * - scripts `{string[]|string|array[]}`:
5604     *   Scripts to always include in the module.
5605     *   %File path or list of file paths, relative to `localBasePath`.
5606     *
5607     *   These files are concatenated blindly and executed as a single client-side script.
5608     *   Modules using this option are sometimes referred to as "legacy scripts" to
5609     *   distinguish them from those that use the `packageFiles` option.
5610     *
5611     *   Modules that use legacy scripts usually attach any public APIs they have
5612     *   to the `mw` global variable. If a module contains just one file, it is also
5613     *   supported to use the newer `module.exports` mechanism, though if the module
5614     *   contains more than one legacy script, it is considered unsafe and unsupported
5615     *   to use this mechanism (use `packageFiles` instead). See also
5616     *   [Coding
5617     *     conventions/JavaScript](https://www.mediawiki.org/wiki/Manual:Coding_conventions/JavaScript#Exporting).
5618     *
5619     *   Since MW 1.41, an element of `scripts` may be an array in the same format as
5620     *   packageFiles, giving a callback to call for content generation.
5621     *
5622     *   Default: `[]`
5623     *
5624     *   Extended options, concatenated in this order:
5625     *
5626     *   - languageScripts `{string[]|string|array[]}`: Scripts to include in specific
5627     *     language contexts. Array is keyed by language code with file path or list of
5628     *     file path.
5629     *   - skinScripts `{string[]|string|array[]}`: Scripts to include in specific skin contexts.
5630     *     Array keyed is by skin name with file path or list of file paths.
5631     *   - debugScripts `{string[]|string|array[]}`: Scripts to include in debug contexts.
5632     *     %File path or list of file paths.
5633     *
5634     * - messages `{string[]}`
5635     *   Localisation messages to bundle with this module, for client-side use
5636     *   via `mw.msg()` and `mw.message()`. List of message keys.
5637     *
5638     *   Default: `[]`
5639     *
5640     * - templates `{string[]}`
5641     *   List of template files to be loaded for client-side usage via `mw.templates`.
5642     *
5643     *   Default: `[]`
5644     *
5645     * - es6 `{boolean}`:
5646     *   Since: MW 1.36; ignored since MW 1.41.
5647     *
5648     *   Default: `true`
5649     *
5650     *  - skipStructureTest `{boolean}`:
5651     *   Whether to skip ResourcesTest::testRespond(). Since MW 1.42.
5652     *
5653     *   Default: `false`.
5654     *
5655     * ## Examples
5656     *
5657     * **Example: Using an alternate subclass**
5658     *
5659     * ```
5660     * $wgResourceModules['ext.myExtension'] = [
5661     *   'class' => \MediaWiki\ResourceLoader\WikiModule::class,
5662     * ];
5663     * ```
5664     *
5665     * **Example: Deprecated module**
5666     *
5667     * ```
5668     * $wgResourceModules['ext.myExtension'] = [
5669     *   'deprecated' => 'You should use ext.myExtension2 instead',
5670     * ];
5671     * ```
5672     *
5673     * **Example: Base paths in extension.json**
5674     *
5675     * ```
5676     * "ext.myExtension": {
5677     *   "localBasePath": "modules/ext.MyExtension",
5678     *   "remoteExtPath": "MyExtension/modules/ext.MyExtension"
5679     * }
5680     * ```
5681     *
5682     * **Example: Base paths in core with PHP**
5683     *
5684     * ```
5685     * $wgResourceModules['mediawiki.example'] = [
5686     *   'localBasePath' => "$IP/resources/src/mediawiki.example",
5687     *   'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.example",
5688     * ];
5689     * ```
5690     *
5691     * **Example: Define a skip function**
5692     *
5693     * ```
5694     * $wgResourceModules['ext.myExtension.SomeWebAPI'] = [
5695     *   'skipFunction' => 'skip-SomeWebAPI.js',
5696     * ];
5697     * ```
5698     *
5699     * **Example: Contents of skip function file**
5700     *
5701     * ```
5702     * return typeof SomeWebAPI === 'function' && SomeWebAPI.prototype.duckMethod;
5703     * ```
5704     * @anchor wgResourceModules-example-stylesheet
5705     *
5706     * **Example: Stylesheets**
5707     *
5708     * ```
5709     * $wgResourceModules['example'] = [
5710     *   'styles' => [
5711     *     'foo.css',
5712     *     'bar.css',
5713     *   ],
5714     * ];
5715     * $wgResourceModules['example.media'] = [
5716     *   'styles' => [
5717     *     'foo.css' => [ 'media' => 'print' ],
5718     * ];
5719     * $wgResourceModules['example.mixed'] = [
5720     *   'styles' => [
5721     *     'foo.css',
5722     *     'bar.css' => [ 'media' => 'print' ],
5723     *   ],
5724     * ];
5725     * ```
5726     *
5727     * **Example: Package files**
5728     *
5729     * ```
5730     * "ext.myExtension": {
5731     *     "localBasePath": "modules/ext.MyExtension",
5732     *     "remoteExtPath": "MyExtension/modules/ext.MyExtension",
5733     *     "packageFiles": [
5734     *       "index.js",
5735     *       "utils.js",
5736     *       "data.json"
5737     *     ]
5738     *   }
5739     * }
5740     * ```
5741     *
5742     * **Example: Legacy scripts**
5743     *
5744     * ```
5745     * $wgResourceModules['ext.myExtension'] = [
5746     *   'scripts' => [
5747     *     'modules/ext.myExtension/utils.js',
5748     *     'modules/ext.myExtension/myExtension.js',
5749     *   ],
5750     *   'languageScripts' => [
5751     *     'bs' => 'modules/ext.myExtension/languages/bs.js',
5752     *     'fi' => 'modules/ext.myExtension/languages/fi.js',
5753     *   ],
5754     *   'skinScripts' => [
5755     *     'default' => 'modules/ext.myExtension/skin-default.js',
5756     *   ],
5757     *   'debugScripts' => [
5758     *     'modules/ext.myExtension/debug.js',
5759     *   ],
5760     * ];
5761     * ```
5762     *
5763     * **Example: Template files**
5764     *
5765     * ```
5766     * $wgResourceModules['ext.myExtension'] = [
5767     *   'templates' => [
5768     *     'templates/template.html',
5769     *     'templates/template2.html',
5770     *   ],
5771     * ];
5772     * ```
5773     * @since 1.17
5774     */
5775    public const ResourceModules = [
5776        'default' => [],
5777        'type' => 'map',
5778    ];
5779
5780    /**
5781     * Add extra skin-specific styles to a resource module.
5782     *
5783     * These are automatically added by ResourceLoader to the 'skinStyles' list of
5784     * the existing module. The 'styles' list cannot be modified or disabled.
5785     *
5786     * For example, below a module "bar" is defined and skin Foo provides additional
5787     * styles for it:
5788     *
5789     * **Example:**
5790     *
5791     * ```
5792     * $wgResourceModules['bar'] = [
5793     *   'scripts' => 'resources/bar/bar.js',
5794     *   'styles' => 'resources/bar/main.css',
5795     * ];
5796     *
5797     * $wgResourceModuleSkinStyles['foo'] = [
5798     *   'bar' => 'skins/Foo/bar.css',
5799     * ];
5800     * ```
5801     *
5802     * This is effectively equivalent to:
5803     *
5804     * **Equivalent:**
5805     *
5806     * ```
5807     * $wgResourceModules['bar'] = [
5808     *   'scripts' => 'resources/bar/bar.js',
5809     *   'styles' => 'resources/bar/main.css',
5810     *   'skinStyles' => [
5811     *     'foo' => skins/Foo/bar.css',
5812     *   ],
5813     * ];
5814     * ```
5815     *
5816     * If the module already defines its own entry in `skinStyles` for a given skin, then
5817     * $wgResourceModuleSkinStyles is ignored.
5818     *
5819     * If a module defines a `skinStyles['default']` the skin may want to extend that instead
5820     * of replacing it. This can be done using the `+` prefix.
5821     *
5822     * **Example:**
5823     *
5824     * ```
5825     * $wgResourceModules['bar'] = [
5826     *   'scripts' => 'resources/bar/bar.js',
5827     *   'styles' => 'resources/bar/basic.css',
5828     *   'skinStyles' => [
5829     *    'default' => 'resources/bar/additional.css',
5830     *   ],
5831     * ];
5832     * // Note the '+' character:
5833     * $wgResourceModuleSkinStyles['foo'] = [
5834     *   '+bar' => 'skins/Foo/bar.css',
5835     * ];
5836     * ```
5837     *
5838     * This is effectively equivalent to:
5839     *
5840     * **Equivalent:**
5841     *
5842     * ```
5843     * $wgResourceModules['bar'] = [
5844     *   'scripts' => 'resources/bar/bar.js',
5845     *   'styles' => 'resources/bar/basic.css',
5846     *   'skinStyles' => [
5847     *     'default' => 'resources/bar/additional.css',
5848     *     'foo' => [
5849     *       'resources/bar/additional.css',
5850     *       'skins/Foo/bar.css',
5851     *     ],
5852     *   ],
5853     * ];
5854     * ```
5855     *
5856     * In other words, as a module author, use the `styles` list for stylesheets that may not be
5857     * disabled by a skin. To provide default styles that may be extended or replaced,
5858     * use `skinStyles['default']`.
5859     *
5860     * As with $wgResourceModules, always set the localBasePath and remoteBasePath
5861     * keys (or one of remoteExtPath/remoteSkinPath).
5862     *
5863     * **Example:**
5864     *
5865     * ```
5866     * $wgResourceModuleSkinStyles['foo'] = [
5867     *   'bar' => 'bar.css',
5868     *   'quux' => 'quux.css',
5869     *   'remoteSkinPath' => 'Foo',
5870     *   'localBasePath' => __DIR__,
5871     * ];
5872     * ```
5873     */
5874    public const ResourceModuleSkinStyles = [
5875        'default' => [],
5876        'type' => 'map',
5877    ];
5878
5879    /**
5880     * Extensions should register foreign module sources here. 'local' is a
5881     * built-in source that is not in this array, but defined by
5882     * ResourceLoader::__construct() so that it cannot be unset.
5883     *
5884     * **Example:**
5885     *
5886     * ```
5887     * $wgResourceLoaderSources['foo'] = 'http://example.org/w/load.php';
5888     * ```
5889     */
5890    public const ResourceLoaderSources = [
5891        'default' => [],
5892        'type' => 'map',
5893    ];
5894
5895    /**
5896     * The default 'remoteBasePath' value for instances of MediaWiki\ResourceLoader\FileModule.
5897     *
5898     * Defaults to $wgScriptPath.
5899     */
5900    public const ResourceBasePath = [
5901        'default' => null,
5902        'dynamicDefault' => [ 'use' => [ 'ScriptPath' ] ]
5903    ];
5904
5905    /**
5906     * @param mixed $scriptPath Value of ScriptPath
5907     * @return string
5908     */
5909    public static function getDefaultResourceBasePath( $scriptPath ): string {
5910        return $scriptPath;
5911    }
5912
5913    /**
5914     * Override how long a CDN or browser may cache a ResourceLoader HTTP response.
5915     *
5916     * Maximum time in seconds. Used for the `max-age` and `s-maxage` Cache-Control headers.
5917     *
5918     * Valid keys:
5919     *   - versioned
5920     *   - unversioned
5921     *
5922     * @see \MediaWiki\ResourceLoader\ResourceLoader::__construct
5923     * @since 1.35
5924     */
5925    public const ResourceLoaderMaxage = [
5926        'default' => [],
5927        'type' => 'map',
5928    ];
5929
5930    /**
5931     * The default debug mode (on/off) for of ResourceLoader requests.
5932     *
5933     * This will still be overridden when the debug URL parameter is used.
5934     */
5935    public const ResourceLoaderDebug = [
5936        'default' => false,
5937    ];
5938
5939    /**
5940     * ResourceLoader will not generate URLs whose query string is more than
5941     * this many characters long, and will instead use multiple requests with
5942     * shorter query strings. Using multiple requests may degrade performance,
5943     * but may be needed based on the query string limit supported by your web
5944     * server and/or your user's web browsers.
5945     *
5946     * Default: `2000`.
5947     *
5948     * @see \MediaWiki\ResourceLoader\StartUpModule::getMaxQueryLength
5949     * @since 1.17
5950     */
5951    public const ResourceLoaderMaxQueryLength = [
5952        'default' => false,
5953        'type' => 'integer|false',
5954    ];
5955
5956    /**
5957     * Validate JavaScript code loaded from wiki pages.
5958     *
5959     * If a syntax error is found, the script is replaced with a warning
5960     * logged to the browser console. This ensures errors are found early and
5961     * consistently (independent of the editor's own browser), and prevents
5962     * breaking other modules loaded in the same batch from load.php.
5963     *
5964     * @see \MediaWiki\ResourceLoader\Module::validateScriptFile
5965     */
5966    public const ResourceLoaderValidateJS = [
5967        'default' => true,
5968    ];
5969
5970    /**
5971     * When enabled, execution of JavaScript modules is profiled client-side.
5972     *
5973     * Instrumentation happens in mw.loader.profiler.
5974     * Use `mw.inspect('time')` from the browser console to display the data.
5975     *
5976     * @since 1.32
5977     */
5978    public const ResourceLoaderEnableJSProfiler = [
5979        'default' => false,
5980    ];
5981
5982    /**
5983     * Whether ResourceLoader should attempt to persist modules in localStorage on
5984     * browsers that support the Web Storage API.
5985     */
5986    public const ResourceLoaderStorageEnabled = [
5987        'default' => true,
5988    ];
5989
5990    /**
5991     * Cache version for client-side ResourceLoader module storage. You can trigger
5992     * invalidation of the contents of the module store by incrementing this value.
5993     *
5994     * @since 1.23
5995     */
5996    public const ResourceLoaderStorageVersion = [
5997        'default' => 1,
5998    ];
5999
6000    /**
6001     * Whether to include a SourceMap header in ResourceLoader responses
6002     * for JavaScript modules.
6003     *
6004     * @since 1.41
6005     */
6006    public const ResourceLoaderEnableSourceMapLinks = [
6007        'default' => true,
6008    ];
6009
6010    /**
6011     * Whether to allow site-wide CSS (MediaWiki:Common.css and friends) on
6012     * restricted pages like Special:UserLogin or Special:Preferences where
6013     * JavaScript is disabled for security reasons. As it is possible to
6014     * execute JavaScript through CSS, setting this to true opens up a
6015     * potential security hole. Some sites may "skin" their wiki by using
6016     * site-wide CSS, causing restricted pages to look unstyled and different
6017     * from the rest of the site.
6018     *
6019     * @since 1.25
6020     */
6021    public const AllowSiteCSSOnRestrictedPages = [
6022        'default' => false,
6023    ];
6024
6025    /**
6026     * Whether to use the development version of Vue.js. This should be disabled
6027     * for production installations. For development installations, enabling this
6028     * provides useful additional warnings and checks.
6029     *
6030     * Even when this is disabled, using ResourceLoader's debug mode (?debug=true)
6031     * will cause the development version to be loaded.
6032     *
6033     * @since 1.35
6034     */
6035    public const VueDevelopmentMode = [
6036        'default' => false,
6037    ];
6038
6039    /**
6040     * If this is set, MediaWiki will look for Codex files in this directory
6041     * instead of in resources/lib/codex/ and friends.
6042     *
6043     * To use a local development version of Codex, set this to the full file
6044     * path of the root directory of a local clone of the Codex repository, and
6045     * run `npm run build-all` in the Codex root directory. Rerun this command
6046     * after making any changes.
6047     *
6048     * This should be disabled for production installations.
6049     *
6050     * @since 1.43
6051     */
6052    public const CodexDevelopmentDir = [
6053        'default' => null,
6054    ];
6055
6056    // endregion -- End of ResourceLoader settings
6057
6058    /***************************************************************************/
6059    // region   Page titles and redirects
6060    /** @name   Page titles and redirects */
6061
6062    /**
6063     * Name of the project namespace. If left set to false, $wgSitename will be
6064     * used instead.
6065     */
6066    public const MetaNamespace = [
6067        'default' => false,
6068        'dynamicDefault' => [ 'use' => [ 'Sitename' ] ]
6069    ];
6070
6071    /**
6072     * @param mixed $sitename Value of Sitename
6073     * @return string
6074     */
6075    public static function getDefaultMetaNamespace( $sitename ): string {
6076        return str_replace( ' ', '_', $sitename );
6077    }
6078
6079    /**
6080     * Name of the project talk namespace.
6081     *
6082     * Normally you can ignore this and it will be something like
6083     * $wgMetaNamespace . "_talk". In some languages, you may want to set this
6084     * manually for grammatical reasons.
6085     */
6086    public const MetaNamespaceTalk = [
6087        'default' => false,
6088    ];
6089
6090    /**
6091     * Canonical namespace names.
6092     *
6093     * Must not be changed directly in configuration or by extensions, use $wgExtraNamespaces
6094     * instead.
6095     */
6096    public const CanonicalNamespaceNames = [
6097        'default' => NamespaceInfo::CANONICAL_NAMES,
6098        'type' => 'map',
6099    ];
6100
6101    /**
6102     * Additional namespaces. If the namespaces defined in Language.php and
6103     * Namespace.php are insufficient, you can create new ones here, for example,
6104     * to import Help files in other languages. You can also override the namespace
6105     * names of existing namespaces. Extensions should use the CanonicalNamespaces
6106     * hook or extension.json.
6107     *
6108     * @warning Once you delete a namespace, the pages in that namespace will
6109     * no longer be accessible. If you rename it, then you can access them through
6110     * the new namespace name.
6111     *
6112     * Custom namespaces should start at 100 to avoid conflicting with standard
6113     * namespaces, and should always follow the even/odd main/talk pattern.
6114     *
6115     * **Example:**
6116     *
6117     * ```
6118     * $wgExtraNamespaces = [
6119     *    100 => "Hilfe",
6120     *    101 => "Hilfe_Diskussion",
6121     *    102 => "Aide",
6122     *    103 => "Discussion_Aide"
6123     * ];
6124     * ```
6125     * @todo Add a note about maintenance/namespaceDupes.php
6126     */
6127    public const ExtraNamespaces = [
6128        'default' => [],
6129        'type' => 'map',
6130    ];
6131
6132    /**
6133     * Same as above, but for namespaces with gender distinction.
6134     *
6135     * Note: the default form for the namespace should also be set
6136     * using $wgExtraNamespaces for the same index.
6137     *
6138     * @since 1.18
6139     */
6140    public const ExtraGenderNamespaces = [
6141        'default' => [],
6142        'type' => 'map',
6143    ];
6144
6145    /**
6146     * Define extra namespace aliases.
6147     *
6148     * These are alternate names for the primary localised namespace names, which
6149     * are defined by $wgExtraNamespaces and the language file. If a page is
6150     * requested with such a prefix, the request will be redirected to the primary
6151     * name.
6152     *
6153     * Set this to a map from namespace names to IDs.
6154     *
6155     * **Example:**
6156     *
6157     * ```
6158     * $wgNamespaceAliases = [
6159     *     'Wikipedian' => NS_USER,
6160     *     'Help' => 100,
6161     * ];
6162     * ```
6163     *
6164     * @see \MediaWiki\Language\Language::getNamespaceAliases for accessing the full list of aliases,
6165     * including those defined by other means.
6166     */
6167    public const NamespaceAliases = [
6168        'default' => [],
6169        'type' => 'map',
6170    ];
6171
6172    /**
6173     * Allowed title characters -- regex character class
6174     * Don't change this unless you know what you're doing
6175     *
6176     * Problematic punctuation:
6177     *   -  []}|#     Are needed for link syntax, never enable these
6178     *   -  <>        Causes problems with HTML escaping, don't use
6179     *   -  %         Enabled by default, minor problems with path to query rewrite rules, see below
6180     *   -  +         Enabled by default, but doesn't work with path to query rewrite rules,
6181     *                corrupted by apache
6182     *   -  ?         Enabled by default, but doesn't work with path to PATH_INFO rewrites
6183     *
6184     * All three of these punctuation problems can be avoided by using an alias,
6185     * instead of a rewrite rule of either variety.
6186     *
6187     * The problem with % is that when using a path to query rewrite rule, URLs are
6188     * double-unescaped: once by Apache's path conversion code, and again by PHP. So
6189     * %253F, for example, becomes "?". Our code does not double-escape to compensate
6190     * for this, indeed double escaping would break if the double-escaped title was
6191     * passed in the query string rather than the path. This is a minor security issue
6192     * because articles can be created such that they are hard to view or edit.
6193     *
6194     * In some rare cases you may wish to remove + for compatibility with old links.
6195     * @deprecated since 1.41; use Extension:TitleBlacklist or (soon)
6196     * Extension:AbuseFilter to customize this set.
6197     */
6198    public const LegalTitleChars = [
6199        'default' => ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+',
6200        'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize',
6201    ];
6202
6203    /**
6204     * Set this to false to avoid forcing the first letter of links to capitals.
6205     *
6206     * @warning may break links! This makes links COMPLETELY case-sensitive. Links
6207     * appearing with a capital at the beginning of a sentence will *not* go to the
6208     * same place as links in the middle of a sentence using a lowercase initial.
6209     */
6210    public const CapitalLinks = [
6211        'default' => true,
6212    ];
6213
6214    /**
6215     * @since 1.16 - This can now be set per-namespace. Some special namespaces (such as Special,
6216     *     see NamespaceInfo::ALWAYS_CAPITALIZED_NAMESPACES for the full list) must be true by
6217     *     default (and setting them has no effect), due to various things that require them to be
6218     *     so. Also, since Talk namespaces need to directly mirror their associated content
6219     *     namespaces, the values for those are ignored in favor of the subject namespace's
6220     *     setting. Setting for NS_MEDIA is taken automatically from NS_FILE.
6221     *
6222     * **Example:**
6223     *
6224     * ```
6225     * $wgCapitalLinkOverrides[ NS_FILE ] = false;
6226     * ```
6227     */
6228    public const CapitalLinkOverrides = [
6229        'default' => [],
6230        'type' => 'map',
6231    ];
6232
6233    /**
6234     * Which namespaces should support subpages?
6235     * See Language.php for a list of namespaces.
6236     */
6237    public const NamespacesWithSubpages = [
6238        'default' => [
6239            NS_TALK => true,
6240            NS_USER => true,
6241            NS_USER_TALK => true,
6242            NS_PROJECT => true,
6243            NS_PROJECT_TALK => true,
6244            NS_FILE_TALK => true,
6245            NS_MEDIAWIKI => true,
6246            NS_MEDIAWIKI_TALK => true,
6247            NS_TEMPLATE => true,
6248            NS_TEMPLATE_TALK => true,
6249            NS_HELP => true,
6250            NS_HELP_TALK => true,
6251            NS_CATEGORY_TALK => true
6252        ],
6253        'type' => 'map',
6254    ];
6255
6256    /**
6257     * Array of namespaces which can be deemed to contain valid "content", as far
6258     * as the site statistics are concerned. Useful if additional namespaces also
6259     * contain "content" which should be considered when generating a count of the
6260     * number of articles in the wiki.
6261     */
6262    public const ContentNamespaces = [
6263        'default' => [ NS_MAIN ],
6264        'type' => 'list',
6265    ];
6266
6267    /**
6268     * Optional array of namespaces which should be excluded from Special:ShortPages.
6269     *
6270     * Only pages inside $wgContentNamespaces but not $wgShortPagesNamespaceExclusions will
6271     * be shown on that page.
6272     *
6273     * @since 1.37; previously $wgShortPagesNamespaceBlacklist
6274     */
6275    public const ShortPagesNamespaceExclusions = [
6276        'default' => [],
6277        'type' => 'list',
6278    ];
6279
6280    /**
6281     * Array of namespaces, in addition to the talk namespaces, where signatures
6282     * (~~~~) are likely to be used. This determines whether to display the
6283     * Signature button on the edit toolbar, and may also be used by extensions.
6284     *
6285     * For example, "traditional" style wikis, where content and discussion are
6286     * intermixed, could place NS_MAIN and NS_PROJECT namespaces in this array.
6287     */
6288    public const ExtraSignatureNamespaces = [
6289        'default' => [],
6290        'type' => 'list',
6291    ];
6292
6293    /**
6294     * Array of invalid page redirect targets.
6295     *
6296     * Attempting to create a redirect to any of the pages in this array
6297     * will make the redirect fail.
6298     * Userlogout is hard-coded, so it does not need to be listed here.
6299     * (T12569) Disallow Mypage and Mytalk as well.
6300     *
6301     * As of now, this only checks special pages. Redirects to pages in
6302     * other namespaces cannot be invalidated by this variable.
6303     */
6304    public const InvalidRedirectTargets = [
6305        'default' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog' ],
6306        'type' => 'list',
6307    ];
6308
6309    /**
6310     * Disable redirects to special pages and interwiki redirects, which use a 302
6311     * and have no "redirected from" link.
6312     *
6313     * @note This is only for articles with #REDIRECT in them. URL's containing a
6314     * local interwiki prefix (or a non-canonical special page name) are still hard
6315     * redirected regardless of this setting.
6316     */
6317    public const DisableHardRedirects = [
6318        'default' => false,
6319    ];
6320
6321    /**
6322     * Fix double redirects after a page move.
6323     *
6324     * Tends to conflict with page move vandalism, use only on a private wiki.
6325     */
6326    public const FixDoubleRedirects = [
6327        'default' => false,
6328    ];
6329
6330    // endregion -- End of title and interwiki settings
6331
6332    /***************************************************************************/
6333    // region   Interwiki links and sites
6334    /** @name   Interwiki links and sites */
6335
6336    /**
6337     * Array for local interwiki values, for each of the interwiki prefixes that point to
6338     * the current wiki.
6339     *
6340     * Note, recent changes feeds use only the first entry in this array. See $wgRCFeeds.
6341     */
6342    public const LocalInterwikis = [
6343        'default' => [],
6344        'type' => 'list',
6345    ];
6346
6347    /**
6348     * Expiry time for cache of interwiki table
6349     */
6350    public const InterwikiExpiry = [
6351        'default' => 10800,
6352    ];
6353
6354    /**
6355     * Interwiki cache as an associative array.
6356     *
6357     * When set, the InterwikiLookup service will not use the built-in `interwiki` database table,
6358     * but instead use this static array as its source.
6359     *
6360     * This cache data structure can be generated by the `dumpInterwiki.php` maintenance
6361     * script (which lives in the WikimediaMaintenance repository) and has key
6362     * formats such as the following:
6363     *
6364     *  - dbname:key - a simple key (e.g. enwiki:meta)
6365     *  - _sitename:key - site-scope key (e.g. wiktionary:meta)
6366     *  - __global:key - global-scope key (e.g. __global:meta)
6367     *  - __sites:dbname - site mapping (e.g. __sites:enwiki)
6368     *
6369     * Sites mapping just specifies site name, other keys provide "local url"
6370     * data layout.
6371     *
6372     * @see \MediaWiki\Interwiki\ClassicInterwikiLookup
6373     */
6374    public const InterwikiCache = [
6375        'default' => false,
6376        'type' => 'false|map',
6377        'mergeStrategy' => 'replace',
6378    ];
6379
6380    /**
6381     * Specify number of domains to check for messages.
6382     *
6383     * - 1: Just wiki(db)-level
6384     * - 2: wiki and global levels
6385     * - 3: site levels
6386     */
6387    public const InterwikiScopes = [
6388        'default' => 3,
6389    ];
6390
6391    /**
6392     * Fallback site, if unable to resolve from cache
6393     */
6394    public const InterwikiFallbackSite = [
6395        'default' => 'wiki',
6396    ];
6397
6398    /**
6399     * If local interwikis are set up which allow redirects,
6400     * set this regexp to restrict URLs which will be displayed
6401     * as 'redirected from' links.
6402     *
6403     * **Example:**
6404     * It might look something like this:
6405     *
6406     * ```
6407     * $wgRedirectSources = '!^https?://[a-z-]+\.wikipedia\.org/!';
6408     * ```
6409     *
6410     * Leave at false to avoid displaying any incoming redirect markers.
6411     * This does not affect intra-wiki redirects, which don't change
6412     * the URL.
6413     */
6414    public const RedirectSources = [
6415        'default' => false,
6416    ];
6417
6418    /**
6419     * Register handlers for specific types of sites.
6420     *
6421     * @since 1.21
6422     */
6423    public const SiteTypes = [
6424        'default' => [ 'mediawiki' => MediaWikiSite::class, ],
6425        'type' => 'map',
6426    ];
6427
6428    // endregion -- Interwiki links and sites
6429
6430    /***************************************************************************/
6431    // region   Parser settings
6432    /** @name   Parser settings
6433     *  These settings configure the transformation from wikitext to HTML.
6434     */
6435
6436    /**
6437     * Maximum indent level of toc.
6438     */
6439    public const MaxTocLevel = [
6440        'default' => 999,
6441    ];
6442
6443    /**
6444     * A complexity limit on template expansion: the maximum number of nodes visited
6445     * by PPFrame::expand()
6446     */
6447    public const MaxPPNodeCount = [
6448        'default' => 1_000_000,
6449    ];
6450
6451    /**
6452     * Maximum recursion depth for templates within templates.
6453     *
6454     * The current parser adds two levels to the PHP call stack for each template,
6455     * and xdebug limits the call stack to 256 by default. So this should hopefully
6456     * stop the parser before it hits the xdebug limit.
6457     */
6458    public const MaxTemplateDepth = [
6459        'default' => 100,
6460    ];
6461
6462    /**
6463     * @see self::MaxTemplateDepth
6464     */
6465    public const MaxPPExpandDepth = [
6466        'default' => 100,
6467    ];
6468
6469    /**
6470     * URL schemes that should be recognized as valid by UrlUtils::parse().
6471     *
6472     * WARNING: Do not add 'file:' to this or internal file links will be broken.
6473     * Instead, if you want to support file links, add 'file://'. The same applies
6474     * to any other protocols with the same name as a namespace. See task T46011 for
6475     * more information.
6476     *
6477     * @see \MediaWiki\Utils\UrlUtils::parse()
6478     */
6479    public const UrlProtocols = [
6480        'default' => [
6481            'bitcoin:', 'ftp://', 'ftps://', 'geo:', 'git://', 'gopher://', 'http://',
6482            'https://', 'irc://', 'ircs://', 'magnet:', 'mailto:', 'matrix:', 'mms://',
6483            'news:', 'nntp://', 'redis://', 'sftp://', 'sip:', 'sips:', 'sms:',
6484            'ssh://', 'svn://', 'tel:', 'telnet://', 'urn:', 'worldwind://', 'xmpp:',
6485            '//',
6486        ],
6487        'type' => 'list',
6488    ];
6489
6490    /**
6491     * If true, removes (by substituting) templates in signatures.
6492     */
6493    public const CleanSignatures = [
6494        'default' => true,
6495    ];
6496
6497    /**
6498     * Whether to allow inline image pointing to other websites
6499     */
6500    public const AllowExternalImages = [
6501        'default' => false,
6502    ];
6503
6504    /**
6505     * If the above is false, you can specify an exception here. Image URLs
6506     * that start with this string are then rendered, while all others are not.
6507     *
6508     * You can use this to set up a trusted, simple repository of images.
6509     * You may also specify an array of strings to allow multiple sites
6510     *
6511     * **Examples:**
6512     *
6513     * ```
6514     * $wgAllowExternalImagesFrom = 'http://127.0.0.1/';
6515     * $wgAllowExternalImagesFrom = [ 'http://127.0.0.1/', 'http://example.com' ];
6516     * ```
6517     */
6518    public const AllowExternalImagesFrom = [
6519        'default' => '',
6520    ];
6521
6522    /**
6523     * If $wgAllowExternalImages is false, you can allow an on-wiki
6524     * allow list of regular expression fragments to match the image URL
6525     * against. If the image matches one of the regular expression fragments,
6526     * the image will be displayed.
6527     *
6528     * Set this to true to enable the on-wiki allow list (MediaWiki:External image whitelist)
6529     * Or false to disable it
6530     *
6531     * @since 1.14
6532     */
6533    public const EnableImageWhitelist = [
6534        'default' => false,
6535    ];
6536
6537    /**
6538     * Configuration for HTML postprocessing tool. Set this to a configuration
6539     * array to enable an external tool. By default, we now use the RemexHtml
6540     * library; historically, other postprocessors were used.
6541     *
6542     * Setting this to null will use default settings.
6543     *
6544     * Keys include:
6545     *  - treeMutationTrace: a boolean to turn on Remex tracing
6546     *  - serializerTrace: a boolean to turn on Remex tracing
6547     *  - mungerTrace: a boolean to turn on Remex tracing
6548     *  - pwrap: whether <p> wrapping should be done (default true)
6549     *
6550     * See includes/tidy/RemexDriver.php for detail on configuration.
6551     *
6552     * Overriding the default configuration is strongly discouraged in
6553     * production.
6554     */
6555    public const TidyConfig = [
6556        'default' => [],
6557        'type' => 'map',
6558    ];
6559
6560    /**
6561     * Default Parsoid configuration.
6562     *
6563     * Overriding the default configuration is strongly discouraged in
6564     * production.
6565     *
6566     * @since 1.39
6567     */
6568    public const ParsoidSettings = [
6569        'default' => [
6570            'useSelser' => true,
6571        ],
6572        'type' => 'map',
6573    ];
6574
6575    /**
6576     * Enable legacy media HTML structure in the output from the Parser.  The
6577     * alternative modern HTML structure that replaces it is described at
6578     * https://www.mediawiki.org/wiki/Parsing/Media_structure
6579     *
6580     * @deprecated since 1.41
6581     * @since 1.36
6582     */
6583    public const ParserEnableLegacyMediaDOM = [
6584        'default' => false,
6585        'deprecated' => 'since 1.41',
6586    ];
6587
6588    /**
6589     * Enable legacy HTML structure for headings in the output from the Parser.
6590     * The legacy structure includes section edit links (and other markup added
6591     * by some extensions) inside the headings rather than outside them, leading
6592     * to poor accessibility. This doesn't affect headings on special pages.
6593     * Note that each skin also has to indicate support for the new structure.
6594     * More information: https://www.mediawiki.org/wiki/Heading_HTML_changes
6595     *
6596     * @since 1.43
6597     */
6598    public const ParserEnableLegacyHeadingDOM = [
6599        'default' => true,
6600    ];
6601
6602    /**
6603     * Enable shipping the styles for the media HTML structure that replaces
6604     * legacy, when $wgParserEnableLegacyMediaDOM is `false`.  This is configured
6605     * separately so that it can continue to be served after the latter is disabled
6606     * but still in the cache.
6607     *
6608     * @deprecated since 1.41
6609     * @internal Temporary flag, T51097.
6610     * @since 1.38
6611     */
6612    public const UseContentMediaStyles = [
6613        'default' => false,
6614        'deprecated' => 'since 1.41',
6615    ];
6616
6617    /**
6618     * Disable shipping the styles for the legacy media HTML structure
6619     * that has been replaced when $wgParserEnableLegacyMediaDOM is `false`.  This is
6620     * configured separately to give time for templates and extensions that mimic the
6621     * parser output to be migrated away.
6622     *
6623     * @internal Temporary feature flag for T318433.
6624     * @since 1.41
6625     */
6626    public const UseLegacyMediaStyles = [
6627        'default' => false,
6628    ];
6629
6630    /**
6631     * Allow raw, unchecked HTML in "<html>...</html>" sections.
6632     *
6633     * THIS IS VERY DANGEROUS on a publicly editable site, so USE $wgGroupPermissions
6634     * TO RESTRICT EDITING to only those that you trust
6635     */
6636    public const RawHtml = [
6637        'default' => false,
6638    ];
6639
6640    /**
6641     * Set a default target for external links, e.g. _blank to pop up a new window.
6642     *
6643     * This will also set the "noreferrer" and "noopener" link rel to prevent the
6644     * attack described at https://mathiasbynens.github.io/rel-noopener/ .
6645     * Some older browsers may not support these link attributes, hence
6646     * setting $wgExternalLinkTarget to _blank may represent a security risk
6647     * to some of your users.
6648     */
6649    public const ExternalLinkTarget = [
6650        'default' => false,
6651    ];
6652
6653    /**
6654     * If true, external URL links in wiki text will be given the
6655     * rel="nofollow" attribute as a hint to search engines that
6656     * they should not be followed for ranking purposes as they
6657     * are user-supplied and thus subject to spamming.
6658     */
6659    public const NoFollowLinks = [
6660        'default' => true,
6661    ];
6662
6663    /**
6664     * Namespaces in which $wgNoFollowLinks doesn't apply.
6665     *
6666     * See Language.php for a list of namespaces.
6667     */
6668    public const NoFollowNsExceptions = [
6669        'default' => [],
6670        'type' => 'list',
6671    ];
6672
6673    /**
6674     * If this is set to an array of domains, external links to these domain names
6675     * (or any subdomains) will not be set to rel="nofollow" regardless of the
6676     * value of $wgNoFollowLinks.  For instance:
6677     *
6678     * $wgNoFollowDomainExceptions = [ 'en.wikipedia.org', 'wiktionary.org', 'mediawiki.org' ];
6679     *
6680     * This would add rel="nofollow" to links to de.wikipedia.org, but not
6681     * en.wikipedia.org, wiktionary.org, en.wiktionary.org, us.en.wikipedia.org,
6682     * etc.
6683     *
6684     * Defaults to mediawiki.org for the links included in the software by default.
6685     */
6686    public const NoFollowDomainExceptions = [
6687        'default' => [ 'mediawiki.org', ],
6688        'type' => 'list',
6689    ];
6690
6691    /**
6692     * By default MediaWiki does not register links pointing to same server in
6693     * externallinks dataset, use this value to override:
6694     */
6695    public const RegisterInternalExternals = [
6696        'default' => false,
6697    ];
6698
6699    /**
6700     * Allow DISPLAYTITLE to change title display
6701     */
6702    public const AllowDisplayTitle = [
6703        'default' => true,
6704    ];
6705
6706    /**
6707     * For consistency, restrict DISPLAYTITLE to text that normalizes to the same
6708     * canonical DB key. Also disallow some inline CSS rules like display: none;
6709     * which can cause the text to be hidden or unselectable.
6710     */
6711    public const RestrictDisplayTitle = [
6712        'default' => true,
6713    ];
6714
6715    /**
6716     * Maximum number of calls per parse to expensive parser functions such as
6717     * PAGESINCATEGORY.
6718     */
6719    public const ExpensiveParserFunctionLimit = [
6720        'default' => 100,
6721    ];
6722
6723    /**
6724     * Preprocessor caching threshold
6725     * Setting it to 'false' will disable the preprocessor cache.
6726     */
6727    public const PreprocessorCacheThreshold = [
6728        'default' => 1000,
6729    ];
6730
6731    /**
6732     * Enable interwiki transcluding.  Only when iw_trans=1 in the interwiki table.
6733     */
6734    public const EnableScaryTranscluding = [
6735        'default' => false,
6736    ];
6737
6738    /**
6739     * Expiry time for transcluded templates cached in object cache.
6740     *
6741     * Only used $wgEnableInterwikiTranscluding is set to true.
6742     */
6743    public const TranscludeCacheExpiry = [
6744        'default' => 3600,
6745    ];
6746
6747    /**
6748     * Enable the magic links feature of automatically turning ISBN xxx,
6749     * PMID xxx, RFC xxx into links
6750     *
6751     * @since 1.28
6752     */
6753    public const EnableMagicLinks = [
6754        'default' => [
6755            'ISBN' => false,
6756            'PMID' => false,
6757            'RFC' => false,
6758        ],
6759        'type' => 'map',
6760    ];
6761
6762    /**
6763     * Set this to true to allow the {{USERLANGUAGE}} magic word to return the
6764     * actual user language. If it is false, {{USERLANGUAGE}} will return the
6765     * page language. Setting this to true is discouraged since the page
6766     * language should typically be used in the content area. Accessing the user
6767     * language using this feature reduces the efficiency of the parser cache.
6768     *
6769     * @since 1.43
6770     */
6771    public const ParserEnableUserLanguage = [
6772        'default' => false,
6773    ];
6774
6775    // endregion -- end of parser settings
6776
6777    /***************************************************************************/
6778    // region   Statistics and content analysis
6779    /** @name   Statistics and content analysis */
6780
6781    /**
6782     * Method used to determine if a page in a content namespace should be counted
6783     * as a valid article.
6784     *
6785     * Redirect pages will never be counted as valid articles.
6786     *
6787     * This variable can have the following values:
6788     * - 'any': all pages as considered as valid articles
6789     * - 'link': the page must contain a [[wiki link]] to be considered valid
6790     *
6791     * See also See https://www.mediawiki.org/wiki/Manual:Article_count
6792     *
6793     * Retroactively changing this variable will not affect the existing count,
6794     * to update it, you will need to run the maintenance/updateArticleCount.php
6795     * script.
6796     */
6797    public const ArticleCountMethod = [
6798        'default' => 'link',
6799    ];
6800
6801    /**
6802     * How many days user must be idle before he is considered inactive. Will affect
6803     * the number shown on Special:Statistics, Special:ActiveUsers, and the
6804     * {{NUMBEROFACTIVEUSERS}} magic word in wikitext.
6805     *
6806     * You might want to leave this as the default value, to provide comparable
6807     * numbers between different wikis.
6808     */
6809    public const ActiveUserDays = [
6810        'default' => 30,
6811    ];
6812
6813    /**
6814     * The following variables define 3 user experience levels:
6815     *
6816     * - newcomer: has not yet reached the 'learner' level
6817     *
6818     * - learner: has at least $wgLearnerEdits and has been
6819     *            a member for $wgLearnerMemberSince days
6820     *            but has not yet reached the 'experienced' level.
6821     *
6822     * - experienced: has at least $wgExperiencedUserEdits edits and
6823     *                has been a member for $wgExperiencedUserMemberSince days.
6824     */
6825    public const LearnerEdits = [
6826        'default' => 10,
6827    ];
6828
6829    /**
6830     * Number of days the user must exist before becoming a learner.
6831     *
6832     * @see self::LearnerEdits
6833     */
6834    public const LearnerMemberSince = [
6835        'default' => 4,
6836    ];
6837
6838    /**
6839     * Number of edits the user must have before becoming "experienced".
6840     *
6841     * @see self::LearnerEdits
6842     */
6843    public const ExperiencedUserEdits = [
6844        'default' => 500,
6845    ];
6846
6847    /**
6848     * Number of days the user must exist before becoming "experienced".
6849     *
6850     * @see self::LearnerEdits
6851     */
6852    public const ExperiencedUserMemberSince = [
6853        'default' => 30,
6854    ];
6855
6856    /**
6857     * Maximum number of revisions of a page that will be checked against every new edit
6858     * made to determine whether the edit was a manual revert.
6859     *
6860     * Computational time required increases roughly linearly with this configuration
6861     * variable.
6862     *
6863     * Larger values will let you detect very deep reverts, but at the same time can give
6864     * unexpected results (such as marking large amounts of edits as reverts) and may slow
6865     * down the wiki slightly when saving new edits.
6866     *
6867     * Setting this to 0 will disable the manual revert detection feature entirely.
6868     *
6869     * See this document for a discussion on this topic:
6870     * https://meta.wikimedia.org/wiki/Research:Revert
6871     *
6872     * @since 1.36
6873     */
6874    public const ManualRevertSearchRadius = [
6875        'default' => 15,
6876        'type' => 'integer',
6877    ];
6878
6879    /**
6880     * Maximum depth (revision count) of reverts that will have their reverted edits marked
6881     * with the mw-reverted change tag. Reverts deeper than that will not have any edits
6882     * marked as reverted at all.
6883     *
6884     * Large values can lead to lots of revisions being marked as "reverted", which may appear
6885     * confusing to users.
6886     *
6887     * Setting this to 0 will disable the reverted tag entirely.
6888     *
6889     * @since 1.36
6890     */
6891    public const RevertedTagMaxDepth = [
6892        'default' => 15,
6893        'type' => 'integer',
6894    ];
6895
6896    // endregion -- End of statistics and content analysis
6897
6898    /***************************************************************************/
6899    // region   User accounts, authentication
6900    /** @name   User accounts, authentication */
6901
6902    /**
6903     * Central ID lookup providers
6904     * Key is the provider ID, value is a specification for ObjectFactory
6905     *
6906     * @since 1.27
6907     */
6908    public const CentralIdLookupProviders = [
6909        'default' => [
6910            'local' => [
6911                'class' => LocalIdLookup::class,
6912                'services' => [
6913                    'MainConfig',
6914                    'DBLoadBalancerFactory',
6915                    'HideUserUtils',
6916                ]
6917            ]
6918        ],
6919        'type' => 'map',
6920    ];
6921
6922    /**
6923     * Central ID lookup provider to use by default
6924     */
6925    public const CentralIdLookupProvider = [
6926        'default' => 'local',
6927        'type' => 'string',
6928    ];
6929
6930    /**
6931     * User registration timestamp provider classes
6932     * @since 1.41
6933     */
6934    public const UserRegistrationProviders = [
6935        'default' => [
6936            LocalUserRegistrationProvider::TYPE => [
6937                'class' => LocalUserRegistrationProvider::class,
6938                'services' => [
6939                    'UserFactory'
6940                ]
6941            ]
6942        ],
6943        'type' => 'map',
6944    ];
6945
6946    /**
6947     * Password policy for the wiki.
6948     *
6949     * Structured as
6950     * ```
6951     * [
6952     *     'policies' => [ <group> => [ <policy> => <settings>, ... ], ... ],
6953     *     'checks' => [ <policy> => <callback>, ... ],
6954     * ]
6955     * ```
6956     * where <group> is a user group, <policy> is a password policy name
6957     * (arbitrary string) defined in the 'checks' part, <callback> is the
6958     * PHP callable implementing the policy check, <settings> is an array
6959     * of options with the following keys:
6960     * - value: (number, boolean or null) the value to pass to the callback
6961     * - forceChange: (boolean, default false) if the password is invalid, do
6962     *   not let the user log in without changing the password
6963     * - suggestChangeOnLogin: (boolean, default false) if true and the password is
6964     *   invalid, suggest a password change if logging in. If all the failing policies
6965     *   that apply to the user have this set to false, the password change
6966     *   screen will not be shown. 'forceChange' takes precedence over
6967     *   'suggestChangeOnLogin' if they are both present.
6968     * As a shorthand for [ 'value' => <value> ], simply <value> can be written.
6969     * When multiple password policies are defined for a user, the settings
6970     * arrays are merged, and for fields which are set in both arrays, the
6971     * larger value (as understood by PHP's 'max' method) is taken.
6972     *
6973     * A user's effective policy is the superset of all policy statements
6974     * from the policies for the groups where the user is a member. If more
6975     * than one group policy include the same policy statement, the value is
6976     * the max() of the values. Note true > false. The 'default' policy group
6977     * is required, and serves as the minimum policy for all users.
6978     *
6979     * Callbacks receive three arguments: the policy value, the User object
6980     * and the password; and must return a StatusValue. A non-good status
6981     * means the password will not be accepted for new accounts, and existing
6982     * accounts will be prompted for password change or barred from logging in
6983     * (depending on whether the status is a fatal or merely error/warning).
6984     *
6985     * The checks supported by core are:
6986     * - MinimalPasswordLength - Minimum length a user can set.
6987     * - MinimumPasswordLengthToLogin - Passwords shorter than this will
6988     *    not be allowed to login, or offered a chance to reset their password
6989     *    as part of the login workflow, regardless if it is correct.
6990     * - MaximalPasswordLength - maximum length password a user is allowed
6991     *    to attempt. Prevents DoS attacks with pbkdf2.
6992     * - PasswordCannotBeSubstringInUsername - Password cannot be a substring
6993     *    (contained within) the username.
6994     * - PasswordCannotMatchDefaults - Username/password combination cannot
6995     *    match a list of default passwords used by MediaWiki in the past.
6996     * - PasswordNotInCommonList - Password not in best practices list of
6997     *    100,000 commonly used passwords. Due to the size of the list this
6998     *    is a probabilistic test.
6999     *
7000     * If you add custom checks, for Special:PasswordPolicies to display them correctly,
7001     * every check should have a corresponding passwordpolicies-policy-<check> message,
7002     * and every settings field other than 'value' should have a corresponding
7003     * passwordpolicies-policyflag-<flag> message (<check> and <flag> are in lowercase).
7004     * The check message receives the policy value as a parameter, the flag message
7005     * receives the flag value (or values if it's an array).
7006     *
7007     * @since 1.26
7008     * @see \MediaWiki\Password\PasswordPolicyChecks
7009     * @see \MediaWiki\User\User::checkPasswordValidity()
7010     */
7011    public const PasswordPolicy = [
7012        'default' => [
7013            'policies' => [
7014                'bureaucrat' => [
7015                    'MinimalPasswordLength' => 10,
7016                    'MinimumPasswordLengthToLogin' => 1,
7017                ],
7018                'sysop' => [
7019                    'MinimalPasswordLength' => 10,
7020                    'MinimumPasswordLengthToLogin' => 1,
7021                ],
7022                'interface-admin' => [
7023                    'MinimalPasswordLength' => 10,
7024                    'MinimumPasswordLengthToLogin' => 1,
7025                ],
7026                'bot' => [
7027                    'MinimalPasswordLength' => 10,
7028                    'MinimumPasswordLengthToLogin' => 1,
7029                ],
7030                'default' => [
7031                    'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true ],
7032                    'PasswordCannotBeSubstringInUsername' => [
7033                        'value' => true,
7034                        'suggestChangeOnLogin' => true
7035                    ],
7036                    'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true ],
7037                    'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true ],
7038                    'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true ],
7039                ],
7040            ],
7041            'checks' => [
7042                'MinimalPasswordLength' => [ PasswordPolicyChecks::class, 'checkMinimalPasswordLength' ],
7043                'MinimumPasswordLengthToLogin' => [ PasswordPolicyChecks::class, 'checkMinimumPasswordLengthToLogin' ],
7044                'PasswordCannotBeSubstringInUsername' => [ PasswordPolicyChecks::class, 'checkPasswordCannotBeSubstringInUsername' ],
7045                'PasswordCannotMatchDefaults' => [ PasswordPolicyChecks::class, 'checkPasswordCannotMatchDefaults' ],
7046                'MaximalPasswordLength' => [ PasswordPolicyChecks::class, 'checkMaximalPasswordLength' ],
7047                'PasswordNotInCommonList' => [ PasswordPolicyChecks::class, 'checkPasswordNotInCommonList' ],
7048            ],
7049        ],
7050        'type' => 'map',
7051        'mergeStrategy' => 'array_replace_recursive',
7052    ];
7053
7054    /**
7055     * Configure AuthManager
7056     *
7057     * All providers are constructed using ObjectFactory, see that for the general
7058     * structure. The array may also contain a key "sort" used to order providers:
7059     * providers are stably sorted by this value, which should be an integer
7060     * (default is 0).
7061     *
7062     * Elements are:
7063     * - preauth: Array (keys ignored) of specifications for PreAuthenticationProviders
7064     * - primaryauth: Array (keys ignored) of specifications for PrimaryAuthenticationProviders
7065     * - secondaryauth: Array (keys ignored) of specifications for SecondaryAuthenticationProviders
7066     *
7067     * @since 1.27
7068     * @note If this is null or empty, the value from $wgAuthManagerAutoConfig is
7069     * used instead. Local customization should generally set this variable from
7070     * scratch to the desired configuration. Extensions that want to
7071     * auto-configure themselves should use $wgAuthManagerAutoConfig instead.
7072     */
7073    public const AuthManagerConfig = [
7074        'default' => null,
7075        'type' => '?map',
7076    ];
7077
7078    /**
7079     * @see self::AuthManagerConfig
7080     * @since 1.27
7081     */
7082    public const AuthManagerAutoConfig = [
7083        'default' => [
7084            'preauth' => [
7085                ThrottlePreAuthenticationProvider::class => [
7086                    'class' => ThrottlePreAuthenticationProvider::class,
7087                    'sort' => 0,
7088                ],
7089            ],
7090            'primaryauth' => [
7091                // TemporaryPasswordPrimaryAuthenticationProvider should come before
7092                // any other PasswordAuthenticationRequest-based
7093                // PrimaryAuthenticationProvider (or at least any that might return
7094                // FAIL rather than ABSTAIN for a wrong password), or password reset
7095                // won't work right. Do not remove this (or change the key) or
7096                // auto-configuration of other such providers in extensions will
7097                // probably auto-insert themselves in the wrong place.
7098                TemporaryPasswordPrimaryAuthenticationProvider::class => [
7099                    'class' => TemporaryPasswordPrimaryAuthenticationProvider::class,
7100                    'services' => [
7101                        'DBLoadBalancerFactory',
7102                        'UserOptionsLookup',
7103                    ],
7104                    'args' => [ [
7105                        // Fall through to LocalPasswordPrimaryAuthenticationProvider
7106                        'authoritative' => false,
7107                    ] ],
7108                    'sort' => 0,
7109                ],
7110                LocalPasswordPrimaryAuthenticationProvider::class => [
7111                    'class' => LocalPasswordPrimaryAuthenticationProvider::class,
7112                    'services' => [
7113                        'DBLoadBalancerFactory',
7114                    ],
7115                    'args' => [ [
7116                        // Last one should be authoritative, or else the user will get
7117                        // a less-than-helpful error message (something like "supplied
7118                        // authentication info not supported" rather than "wrong
7119                        // password") if it too fails.
7120                        'authoritative' => true,
7121                    ] ],
7122                    'sort' => 100,
7123                ],
7124            ],
7125            'secondaryauth' => [
7126                CheckBlocksSecondaryAuthenticationProvider::class => [
7127                    'class' => CheckBlocksSecondaryAuthenticationProvider::class,
7128                    'sort' => 0,
7129                ],
7130                ResetPasswordSecondaryAuthenticationProvider::class => [
7131                    'class' => ResetPasswordSecondaryAuthenticationProvider::class,
7132                    'sort' => 100,
7133                ],
7134                // Linking during login is experimental, enable at your own risk - T134952
7135                // MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider::class => [
7136                //   'class' => MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider::class,
7137                //   'sort' => 100,
7138                // ],
7139                EmailNotificationSecondaryAuthenticationProvider::class => [
7140                    'class' => EmailNotificationSecondaryAuthenticationProvider::class,
7141                    'services' => [
7142                        'DBLoadBalancerFactory',
7143                    ],
7144                    'sort' => 200,
7145                ],
7146            ],
7147        ],
7148        'type' => 'map',
7149        'mergeStrategy' => 'array_plus_2d',
7150    ];
7151
7152    /**
7153     * Configures RememberMe authentication request added by AuthManager. It can show a "remember
7154     * me" checkbox that, when checked, will cause it to take more time for the authenticated
7155     * session to expire. It can also be configured to always or to never extend the authentication
7156     * session.
7157     *
7158     * Valid values are listed in RememberMeAuthenticationRequest::ALLOWED_FLAGS.
7159     *
7160     * @since 1.36
7161     */
7162    public const RememberMe = [
7163        'default' => 'choose',
7164        'type' => 'string',
7165    ];
7166
7167    /**
7168     * Time frame for re-authentication.
7169     *
7170     * With only password-based authentication, you'd just ask the user to re-enter
7171     * their password to verify certain operations like changing the password or
7172     * changing the account's email address. But under AuthManager, the user might
7173     * not have a password (you might even have to redirect the browser to a
7174     * third-party service or something complex like that), you might want to have
7175     * both factors of a two-factor authentication, and so on. So, the options are:
7176     * - Incorporate the whole multi-step authentication flow within everything
7177     *   that needs to do this.
7178     * - Consider it good if they used Special:UserLogin during this session within
7179     *   the last X seconds.
7180     * - Come up with a third option.
7181     *
7182     * MediaWiki currently takes the second option. This setting configures the
7183     * "X seconds".
7184     *
7185     * This allows for configuring different time frames for different
7186     * "operations". The operations used in MediaWiki core include:
7187     * - LinkAccounts
7188     * - UnlinkAccount
7189     * - ChangeCredentials
7190     * - RemoveCredentials
7191     * - ChangeEmail
7192     *
7193     * Additional operations may be used by extensions, either explicitly by
7194     * calling AuthManager::securitySensitiveOperationStatus(),
7195     * ApiAuthManagerHelper::securitySensitiveOperation() or
7196     * SpecialPage::checkLoginSecurityLevel(), or implicitly by overriding
7197     * SpecialPage::getLoginSecurityLevel() or by subclassing
7198     * AuthManagerSpecialPage.
7199     *
7200     * The key 'default' is used if a requested operation isn't defined in the array.
7201     *
7202     * @since 1.27
7203     */
7204    public const ReauthenticateTime = [
7205        'default' => [ 'default' => 300, ],
7206        'type' => 'map',
7207        'additionalProperties' => [ 'type' => 'integer', ],
7208    ];
7209
7210    /**
7211     * Whether to allow security-sensitive operations when re-authentication is not possible.
7212     *
7213     * If AuthManager::canAuthenticateNow() is false (e.g. the current
7214     * SessionProvider is not able to change users, such as when OAuth is in use),
7215     * AuthManager::securitySensitiveOperationStatus() cannot sensibly return
7216     * SEC_REAUTH. Setting an operation true here will have it return SEC_OK in
7217     * that case, while setting it false will have it return SEC_FAIL.
7218     *
7219     * The key 'default' is used if a requested operation isn't defined in the array.
7220     *
7221     * @since 1.27
7222     * @see self::ReauthenticateTime
7223     */
7224    public const AllowSecuritySensitiveOperationIfCannotReauthenticate = [
7225        'default' => [ 'default' => true, ],
7226        'type' => 'map',
7227        'additionalProperties' => [ 'type' => 'boolean', ],
7228    ];
7229
7230    /**
7231     * List of AuthenticationRequest class names which are not changeable through
7232     * Special:ChangeCredentials and the changeauthenticationdata API.
7233     *
7234     * This is only enforced on the client level; AuthManager itself (e.g.
7235     * AuthManager::allowsAuthenticationDataChange calls) is not affected.
7236     * Class names are checked for exact match (not for subclasses).
7237     *
7238     * @since 1.27
7239     */
7240    public const ChangeCredentialsBlacklist = [
7241        'default' => [
7242            TemporaryPasswordAuthenticationRequest::class,
7243        ],
7244        'type' => 'list',
7245        'items' => [ 'type' => 'string', ],
7246    ];
7247
7248    /**
7249     * List of AuthenticationRequest class names which are not removable through
7250     * Special:RemoveCredentials and the removeauthenticationdata API.
7251     *
7252     * This is only enforced on the client level; AuthManager itself (e.g.
7253     * AuthManager::allowsAuthenticationDataChange calls) is not affected.
7254     * Class names are checked for exact match (not for subclasses).
7255     *
7256     * @since 1.27
7257     */
7258    public const RemoveCredentialsBlacklist = [
7259        'default' => [
7260            PasswordAuthenticationRequest::class,
7261        ],
7262        'type' => 'list',
7263        'items' => [ 'type' => 'string', ],
7264    ];
7265
7266    /**
7267     * Specifies if users should be sent to a password-reset form on login, if their
7268     * password doesn't meet the requirements of User::isValidPassword().
7269     *
7270     * @since 1.23
7271     */
7272    public const InvalidPasswordReset = [
7273        'default' => true,
7274    ];
7275
7276    /**
7277     * Default password type to use when hashing user passwords.
7278     *
7279     * Must be set to a type defined in $wgPasswordConfig, or a type that
7280     * is registered by default in PasswordFactory.php.
7281     *
7282     * @since 1.24
7283     */
7284    public const PasswordDefault = [
7285        'default' => 'pbkdf2',
7286    ];
7287
7288    /**
7289     * Configuration for built-in password types.
7290     *
7291     * Maps the password type to an array of options:
7292     *
7293     * - class: The Password class to use.
7294     * - factory (since 1.40): A function that creates and returns a suitable Password object.
7295     *   This option is intended only for internal use; the function signature is unstable and
7296     *   subject to change in future versions.
7297     *
7298     * All other options are class-dependent.
7299     *
7300     * An advanced example:
7301     *
7302     * ```
7303     * $wgPasswordConfig['bcrypt-peppered'] = [
7304     *     'class' => EncryptedPassword::class,
7305     *     'underlying' => 'bcrypt',
7306     *     'secrets' => [
7307     *         hash( 'sha256', 'secret', true ),
7308     *     ],
7309     *     'cipher' => 'aes-256-cbc',
7310     * ];
7311     * ```
7312     *
7313     * @since 1.24
7314     */
7315    public const PasswordConfig = [
7316        'default' => [
7317            'A' => [
7318                'class' => MWOldPassword::class,
7319            ],
7320            'B' => [
7321                'class' => MWSaltedPassword::class,
7322            ],
7323            'pbkdf2-legacyA' => [
7324                'class' => LayeredParameterizedPassword::class,
7325                'types' => [
7326                    'A',
7327                    'pbkdf2',
7328                ],
7329            ],
7330            'pbkdf2-legacyB' => [
7331                'class' => LayeredParameterizedPassword::class,
7332                'types' => [
7333                    'B',
7334                    'pbkdf2',
7335                ],
7336            ],
7337            'bcrypt' => [
7338                'class' => BcryptPassword::class,
7339                'cost' => 9,
7340            ],
7341            'pbkdf2' => [
7342                'class' => Pbkdf2PasswordUsingOpenSSL::class,
7343                'algo' => 'sha512',
7344                'cost' => '30000',
7345                'length' => '64',
7346            ],
7347            'argon2' => [
7348                'class' => Argon2Password::class,
7349
7350                // Algorithm used:
7351                // * 'argon2i' is optimized against side-channel attacks
7352                // * 'argon2id' is optimized against both side-channel and GPU cracking
7353                // * 'auto' to use the best available algorithm. If you're using more than one server, be
7354                //   careful when you're mixing PHP versions because newer PHP might generate hashes that
7355                //   older versions would not understand.
7356                'algo' => 'auto',
7357
7358                // The parameters below are the same as options accepted by password_hash().
7359                // Set them to override that function's defaults.
7360                //
7361                // 'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
7362                // 'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST,
7363                // 'threads' => PASSWORD_ARGON2_DEFAULT_THREADS,
7364            ],
7365        ],
7366        'type' => 'map',
7367    ];
7368
7369    /**
7370     * Whether to allow password resets ("enter some identifying data, and we'll send an email
7371     * with a temporary password you can use to get back into the account") identified by
7372     * various bits of data.  Setting all of these to false (or the whole variable to false)
7373     * has the effect of disabling password resets entirely
7374     */
7375    public const PasswordResetRoutes = [
7376        'default' => [
7377            'username' => true,
7378            'email' => true,
7379        ],
7380        'type' => 'map',
7381    ];
7382
7383    /**
7384     * Maximum number of Unicode characters in signature
7385     */
7386    public const MaxSigChars = [
7387        'default' => 255,
7388    ];
7389
7390    /**
7391     * Behavior of signature validation. Allowed values are:
7392     *  - 'warning' - invalid signatures cause a warning to be displayed on the preferences page,
7393     * but they are still used when signing comments; new invalid signatures can still be saved as
7394     * normal
7395     *  - 'new' - existing invalid signatures behave as above; new invalid signatures can't be
7396     * saved
7397     *  - 'disallow' - existing invalid signatures are no longer used when signing comments; new
7398     * invalid signatures can't be saved
7399     *
7400     * @since 1.35
7401     */
7402    public const SignatureValidation = [
7403        'default' => 'warning',
7404    ];
7405
7406    /**
7407     * List of lint error codes which don't cause signature validation to fail.
7408     *
7409     * @see https://www.mediawiki.org/wiki/Help:Lint_errors
7410     * @since 1.35
7411     */
7412    public const SignatureAllowedLintErrors = [
7413        'default' => [ 'obsolete-tag', ],
7414        'type' => 'list',
7415    ];
7416
7417    /**
7418     * Maximum number of bytes in username. You want to run the maintenance
7419     * script ./maintenance/checkUsernames.php once you have changed this value.
7420     */
7421    public const MaxNameChars = [
7422        'default' => 255,
7423    ];
7424
7425    /**
7426     * Array of usernames which may not be registered or logged in from
7427     * Maintenance scripts can still use these
7428     *
7429     * @see \MediaWiki\User\User::MAINTENANCE_SCRIPT_USER
7430     */
7431    public const ReservedUsernames = [
7432        'default' => [
7433            'MediaWiki default', // Default 'Main Page' and MediaWiki: message pages
7434            'Conversion script', // Used for the old Wikipedia software upgrade
7435            'Maintenance script', // Maintenance scripts which perform editing, image import script
7436            'Template namespace initialisation script', // Used in 1.2->1.3 upgrade
7437            'ScriptImporter', // Default user name used by maintenance/importSiteScripts.php
7438            'Delete page script', // Default user name used by maintenance/deleteBatch.php
7439            'Move page script', // Default user name used by maintenance/deleteBatch.php
7440            'Command line script', // Default user name used by maintenance/undelete.php
7441            'Unknown user', // Used in WikiImporter & RevisionStore for revisions with no author and in User for invalid user id
7442            'msg:double-redirect-fixer', // Automatic double redirect fix
7443            'msg:usermessage-editor', // Default user for leaving user messages
7444            'msg:proxyblocker', // For $wgProxyList and Special:Blockme (removed in 1.22)
7445            'msg:sorbs', // For $wgEnableDnsBlacklist etc.
7446            'msg:spambot_username', // Used by cleanupSpam.php
7447            'msg:autochange-username', // Used by anon category RC entries (removed in 1.44)
7448        ],
7449        'type' => 'list',
7450    ];
7451
7452    /**
7453     * Settings added to this array will override the default globals for the user
7454     * preferences used by anonymous visitors and newly created accounts.
7455     *
7456     * For instance, to disable editing on double clicks:
7457     * $wgDefaultUserOptions ['editondblclick'] = 0;
7458     *
7459     * To save storage space, no user_properties row will be stored for users with the
7460     * default setting for a given option, even if the user manually selects that option.
7461     * This means that a change to the defaults will change the setting for all users who
7462     * have been using the default setting; there is no way for users to opt out of this.
7463     * $wgConditionalUserOptions can be used to change the default value for future users
7464     * only.
7465     *
7466     * @see self::ConditionalUserOptions
7467     */
7468    public const DefaultUserOptions = [
7469        'default' =>
7470            // This array should be sorted by key
7471            [
7472                'ccmeonemails' => 0,
7473                'date' => 'default',
7474                'diffonly' => 0,
7475                'diff-type' => 'table',
7476                'disablemail' => 0,
7477                'editfont' => 'monospace',
7478                'editondblclick' => 0,
7479                'editrecovery' => 0,
7480                'editsectiononrightclick' => 0,
7481                'email-allow-new-users' => 1,
7482                'enotifminoredits' => 0,
7483                'enotifrevealaddr' => 0,
7484                'enotifusertalkpages' => 1,
7485                'enotifwatchlistpages' => 1,
7486                'extendwatchlist' => 1,
7487                'fancysig' => 0,
7488                'forceeditsummary' => 0,
7489                'forcesafemode' => 0,
7490                'gender' => 'unknown',
7491                'hidecategorization' => 1,
7492                'hideminor' => 0,
7493                'hidepatrolled' => 0,
7494                'imagesize' => 2,
7495                'minordefault' => 0,
7496                'newpageshidepatrolled' => 0,
7497                'nickname' => '',
7498                'norollbackdiff' => 0,
7499                'prefershttps' => 1,
7500                'previewonfirst' => 0,
7501                'previewontop' => 1,
7502                'pst-cssjs' => 1,
7503                'rcdays' => 7,
7504                'rcenhancedfilters-disable' => 0,
7505                'rclimit' => 50,
7506                'requireemail' => 0,
7507                'search-match-redirect' => true,
7508                'search-special-page' => 'Search',
7509                'search-thumbnail-extra-namespaces' => true,
7510                'searchlimit' => 20,
7511                'showhiddencats' => 0,
7512                'shownumberswatching' => 1,
7513                'showrollbackconfirmation' => 0,
7514                'skin' => false,
7515                'skin-responsive' => 1,
7516                'thumbsize' => 5,
7517                'underline' => 2,
7518                'useeditwarning' => 1,
7519                'uselivepreview' => 0,
7520                'usenewrc' => 1,
7521                'watchcreations' => 1,
7522                'watchdefault' => 1,
7523                'watchdeletion' => 0,
7524                'watchlistdays' => 7,
7525                'watchlisthideanons' => 0,
7526                'watchlisthidebots' => 0,
7527                'watchlisthidecategorization' => 1,
7528                'watchlisthideliu' => 0,
7529                'watchlisthideminor' => 0,
7530                'watchlisthideown' => 0,
7531                'watchlisthidepatrolled' => 0,
7532                'watchlistreloadautomatically' => 0,
7533                'watchlistunwatchlinks' => 0,
7534                'watchmoves' => 0,
7535                'watchrollback' => 0,
7536                'watchuploads' => 1,
7537                'wlenhancedfilters-disable' => 0,
7538                'wllimit' => 250,
7539            ],
7540        'type' => 'map',
7541    ];
7542
7543    /**
7544     * Conditional defaults for user options
7545     *
7546     * Map of user options to conditional defaults descriptors, which is an array
7547     * of conditional cases [ VALUE, CONDITION1, CONDITION2 ], where VALUE is the default value for
7548     * all users that meet ALL conditions, and each CONDITION is either a:
7549     *     (a) a CUDCOND_* constant (when condition does not take any arguments), or
7550     *     (b) an array [ CUDCOND_*, argument1, argument1, ... ] (when chosen condition takes at
7551     *         least one argument).
7552     *
7553     * When `null` is used as the VALUE, it is interpreted as "no conditional default for this
7554     * condition". In other words, `null` and $wgDefaultUserOptions['user-option'] can be used
7555     * interchangeably as the VALUE.
7556     *
7557     * All conditions are evaluated in order. When no condition matches.
7558     * $wgDefaultUserOptions is used instead.
7559     *
7560     * Example of valid configuration:
7561     *   $wgConditionalUserOptions['user-option'] = [
7562     *       [ 'registered in 2024', [ CUDCOND_AFTER, '20240101000000' ] ]
7563     *   ];
7564     *
7565     * List of valid conditions:
7566     *   * CUDCOND_AFTER: user registered after given timestamp (args: string $timestamp)
7567     *   * CUDCOND_ANON: allows specifying a default for anonymous (logged-out, non-temporary) users
7568     *   * CUDCOND_NAMED: allows specifying a default for named (registered, non-temporary) users
7569     *   * CUDCOND_USERGROUP: users with a specific user group
7570     *
7571     * @since 1.42
7572     * @see self::DefaultUserOptions
7573     */
7574    public const ConditionalUserOptions = [
7575        'default' => [],
7576        'type' => 'map',
7577    ];
7578
7579    /**
7580     * An array of preferences to not show for the user
7581     */
7582    public const HiddenPrefs = [
7583        'default' => [],
7584        'type' => 'list',
7585    ];
7586
7587    /**
7588     * Characters to prevent during new account creations.
7589     *
7590     * This is used in a regular expression character class during
7591     * registration (regex metacharacters like / are escaped).
7592     */
7593    public const InvalidUsernameCharacters = [
7594        'default' => '@:>=',
7595    ];
7596
7597    /**
7598     * Character used as a delimiter when testing for interwiki userrights
7599     * (In Special:UserRights, it is possible to modify users on different
7600     * databases if the delimiter is used, e.g. "Someuser@enwiki").
7601     *
7602     * It is recommended that you have this delimiter in
7603     * $wgInvalidUsernameCharacters above, or you will not be able to
7604     * modify the user rights of those users via Special:UserRights
7605     */
7606    public const UserrightsInterwikiDelimiter = [
7607        'default' => '@',
7608    ];
7609
7610    /**
7611     * This is to let user authenticate using https when they come from http.
7612     *
7613     * Based on an idea by George Herbert on wikitech-l:
7614     * https://lists.wikimedia.org/pipermail/wikitech-l/2010-October/050039.html
7615     *
7616     * @since 1.17
7617     */
7618    public const SecureLogin = [
7619        'default' => false,
7620    ];
7621
7622    /**
7623     * Versioning for authentication tokens.
7624     *
7625     * If non-null, this is combined with the user's secret (the user_token field
7626     * in the DB) to generate the token cookie. Changing this will invalidate all
7627     * active sessions (i.e. it will log everyone out).
7628     *
7629     * @since 1.27
7630     */
7631    public const AuthenticationTokenVersion = [
7632        'default' => null,
7633        'type' => '?string',
7634    ];
7635
7636    /**
7637     * MediaWiki\Session\SessionProvider configuration.
7638     *
7639     * Values are ObjectFactory specifications for the SessionProviders to be
7640     * used. Keys in the array are ignored; the class name is conventionally
7641     * used as the key to avoid collisions. Order is not significant.
7642     *
7643     * @since 1.27
7644     */
7645    public const SessionProviders = [
7646        'type' => 'map',
7647        'default' => [
7648            \MediaWiki\Session\CookieSessionProvider::class => [
7649                'class' => \MediaWiki\Session\CookieSessionProvider::class,
7650                'args' => [ [
7651                    'priority' => 30,
7652                ] ],
7653            ],
7654            \MediaWiki\Session\BotPasswordSessionProvider::class => [
7655                'class' => \MediaWiki\Session\BotPasswordSessionProvider::class,
7656                'args' => [ [
7657                    'priority' => 75,
7658                ] ],
7659                'services' => [
7660                    'GrantsInfo'
7661                ],
7662            ],
7663        ],
7664    ];
7665
7666    /**
7667     * Configuration for automatic creation of temporary accounts on page save.
7668     * This can be enabled to avoid exposing the IP addresses of casual editors who
7669     * do not explicitly create an account.
7670     *
7671     * @warning This is EXPERIMENTAL, enabling may break extensions.
7672     *
7673     * An associative array with the following keys:
7674     *
7675     *   - known: (bool) Whether auto-creation is known about. Set this to 'true' if
7676     *     temp accounts have been created on this wiki already. This setting allows
7677     *     temp users to be recognized even if auto-creation is currently disabled.
7678     *     If auto-creation is enabled via the 'enabled' property, then 'known' is
7679     *     overriden to true.
7680     *   - enabled: (bool) Whether auto-creation is enabled. If changing this
7681     *     value from 'true' to 'false', you should also set 'known' to true, so
7682     *     that relevant code can continue to identify temporary accounts as
7683     *     visually and conceptually distinct from anonymous accounts and named accounts.
7684     *   - actions: (array) A list of actions for which the feature is enabled.
7685     *     Currently only "edit" is supported.
7686     *   - genPattern: (string) The pattern used when generating new usernames.
7687     *     This should have "$1" indicating the place where the serial string will
7688     *     be substituted.
7689     *   - matchPattern: (string|string[]|null) The pattern used when determining whether a
7690     *     username is a temporary user. This affects the rights of the user
7691     *     and also prevents explicit creation of users with matching names.
7692     *     This is ignored if "enabled" is false. If the value is null, the
7693     *     the genPattern value is used as the matchPattern.
7694     *   - reservedPattern: (string) A pattern used to determine whether a
7695     *     username should be denied for explicit creation, in addition to
7696     *     matchPattern. This is used even if "enabled" is false.
7697     *   - serialProvider: (array) Configuration for generation of unique integer
7698     *     indexes which are used to make temporary usernames.
7699     *       - type: (string) May be "local" to allocate indexes using the local
7700     *         database. If the CentralAuth extension is enabled, it may be
7701     *         "centralauth". Extensions may plug in additional types using the
7702     *         TempUserSerialProviders attribute.
7703     *       - numShards (int, default 1): A small integer. This can be set to a
7704     *         value greater than 1 to avoid acquiring a global lock when
7705     *         allocating IDs, at the expense of making the IDs be non-monotonic.
7706     *       - useYear: (bool) Restart at 1 each time the year changes (in UTC).
7707     *         To avoid naming conflicts, the year is included in the name after
7708     *         the prefix, in the form 'YYYY-'.
7709     *   - serialMapping: (array) Configuration for mapping integer indexes to strings
7710     *     to substitute into genPattern.
7711     *       - type: (string) May be
7712     *         - "plain-numeric" to use ASCII decimal numbers
7713     *         - "localized-numeric" to use numbers localized using a specific language
7714     *         - "filtered-radix" to use numbers in an arbitrary base between 2 and 36,
7715     *           with an optional list of "bad" IDs to skip over.
7716     *         - "scramble": to use ASCII decimal numbers that are short but
7717     *           non-consecutive.
7718     *       - language: (string) With "localized-numeric", the language code
7719     *       - radix: (int) With "filtered-radix", the base
7720     *       - badIndexes: (array) With "filtered-radix", an array with the bad unmapped
7721     *         indexes in the values. The integers must be sorted and the list
7722     *         must never change after the indexes have been allocated. The keys must
7723     *         be zero-based array indexes.
7724     *       - uppercase: (bool) With "filtered-radix", whether to use uppercase
7725     *         letters, default false.
7726     *       - offset: (int) With "plain-numeric", a constant to add to the stored index.
7727     *    - expireAfterDays: (int|null, default 90) If not null, how many days should the temporary
7728     *      accounts expire? Requires expireTemporaryAccounts.php to be periodically executed in
7729     *      order to work.
7730     *    - notifyBeforeExpirationDays: (int|null, default 10) If not null, how many days before the
7731     *      expiration of a temporary account should it be notified that their account is to be expired.
7732     *
7733     * @unstable EXPERIMENTAL
7734     * @since 1.39
7735     */
7736    public const AutoCreateTempUser = [
7737        'properties' => [
7738            'known' => [ 'type' => 'bool', 'default' => false ],
7739            'enabled' => [ 'type' => 'bool', 'default' => false ],
7740            'actions' => [ 'type' => 'list', 'default' => [ 'edit' ] ],
7741            'genPattern' => [ 'type' => 'string', 'default' => '~$1' ],
7742            'matchPattern' => [ 'type' => 'string|array|null', 'default' => null ],
7743            'reservedPattern' => [ 'type' => 'string|null', 'default' => '~$1' ],
7744            'serialProvider' => [ 'type' => 'object', 'default' => [ 'type' => 'local', 'useYear' => true ] ],
7745            'serialMapping' => [ 'type' => 'object', 'default' => [ 'type' => 'plain-numeric' ] ],
7746            'expireAfterDays' => [ 'type' => 'int|null', 'default' => 90 ],
7747            'notifyBeforeExpirationDays' => [ 'type' => 'int|null', 'default' => 10 ],
7748        ],
7749        'type' => 'object',
7750    ];
7751
7752    // endregion -- end user accounts
7753
7754    /***************************************************************************/
7755    // region   User rights, access control and monitoring
7756    /** @name   User rights, access control and monitoring */
7757
7758    /**
7759     * Number of seconds before autoblock entries expire. Default 86400 = 1 day.
7760     */
7761    public const AutoblockExpiry = [
7762        'default' => 86400,
7763    ];
7764
7765    /**
7766     * Set this to true to allow blocked users to edit their own user talk page.
7767     *
7768     * This only applies to sitewide blocks. Partial blocks always allow users to
7769     * edit their own user talk page unless otherwise specified in the block
7770     * restrictions.
7771     */
7772    public const BlockAllowsUTEdit = [
7773        'default' => true,
7774    ];
7775
7776    /**
7777     * Limits on the possible sizes of range blocks.
7778     *
7779     * CIDR notation is hard to understand, it's easy to mistakenly assume that a
7780     * /1 is a small range and a /31 is a large range. For IPv4, setting a limit of
7781     * half the number of bits avoids such errors, and allows entire ISPs to be
7782     * blocked using a small number of range blocks.
7783     *
7784     * For IPv6, RFC 3177 recommends that a /48 be allocated to every residential
7785     * customer, so range blocks larger than /64 (half the number of bits) will
7786     * plainly be required. RFC 4692 implies that a very large ISP may be
7787     * allocated a /19 if a generous HD-Ratio of 0.8 is used, so we will use that
7788     * as our limit. As of 2012, blocking the whole world would require a /4 range.
7789     */
7790    public const BlockCIDRLimit = [
7791        'default' => [
7792            'IPv4' => 16,
7793            'IPv6' => 19,
7794        ],
7795        'type' => 'map',
7796    ];
7797
7798    /**
7799     * If true, sitewide blocked users will not be allowed to login. (Direct
7800     * blocks only; IP blocks are ignored.) This can be used to remove users'
7801     * read access on a private wiki.
7802     */
7803    public const BlockDisablesLogin = [
7804        'default' => false,
7805    ];
7806
7807    /**
7808     * Flag to enable partial blocks against performing certain actions.
7809     *
7810     * @unstable Temporary feature flag, T280532
7811     * @since 1.37
7812     */
7813    public const EnablePartialActionBlocks = [
7814        'default' => false,
7815        'type' => 'boolean',
7816    ];
7817
7818    /**
7819     * If this is false, the number of blocks of a given target is limited to only 1.
7820     *
7821     * @since 1.42
7822     */
7823    public const EnableMultiBlocks = [
7824        'default' => false,
7825        'type' => 'boolean',
7826    ];
7827
7828    /**
7829     *  Ipblocks table schema migration stage, for normalizing ipb_address field and
7830     *     adding the block_target table.
7831     *
7832     * Use the SCHEMA_COMPAT_XXX flags. Supported values:
7833     *
7834     *   - SCHEMA_COMPAT_OLD
7835     *   - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
7836     *   - SCHEMA_COMPAT_NEW
7837     *
7838     * History:
7839     *   - 1.42: Added
7840     *   - 1.43: Default changed from SCHEMA_COMPAT_OLD to SCHEMA_COMPAT_NEW
7841     *   - 1.43: Deprecated, ignored, SCHEMA_COMPAT_NEW is implied
7842     *
7843     * @deprecated since 1.43
7844     */
7845    public const BlockTargetMigrationStage = [
7846        'default' => SCHEMA_COMPAT_NEW,
7847        'type' => 'integer',
7848    ];
7849
7850    /**
7851     * Pages anonymous user may see, set as an array of pages titles.
7852     *
7853     * **Example:**
7854     *
7855     * ```
7856     * $wgWhitelistRead = [ "Main Page", "Wikipedia:Help" ];
7857     * ```
7858     *
7859     * Special:Userlogin and Special:ChangePassword are always allowed.
7860     *
7861     * @note This will only work if $wgGroupPermissions['*']['read'] is false --
7862     * see below. Otherwise, ALL pages are accessible, regardless of this setting.
7863     * @note Also that this will only protect _pages in the wiki_. Uploaded files
7864     * will remain readable. You can use img_auth.php to protect uploaded files,
7865     * see https://www.mediawiki.org/wiki/Manual:Image_Authorization
7866     * @note Extensions should not modify this, but use the TitleReadWhitelist
7867     * hook instead.
7868     */
7869    public const WhitelistRead = [
7870        'default' => false,
7871    ];
7872
7873    /**
7874     * Pages anonymous user may see, set as an array of regular expressions.
7875     *
7876     * This function will match the regexp against the title name, which
7877     * is without underscore.
7878     *
7879     * **Example:**
7880     * To whitelist [[Main Page]]:
7881     *
7882     * ```
7883     * $wgWhitelistReadRegexp = [ "/Main Page/" ];
7884     * ```
7885     * @note Unless ^ and/or $ is specified, a regular expression might match
7886     * pages not intended to be allowed.  The above example will also
7887     * allow a page named 'Security Main Page'.
7888     *
7889     * **Example:**
7890     * To allow reading any page starting with 'User' regardless of the case:
7891     *
7892     * ```
7893     * $wgWhitelistReadRegexp = [ "@^UsEr.*@i" ];
7894     * ```
7895     *
7896     * Will allow both [[User is banned]] and [[User:JohnDoe]]
7897     * @note This will only work if $wgGroupPermissions['*']['read'] is false --
7898     * see below. Otherwise, ALL pages are accessible, regardless of this setting.
7899     */
7900    public const WhitelistReadRegexp = [
7901        'default' => false,
7902    ];
7903
7904    /**
7905     * Should editors be required to have a validated e-mail
7906     * address before being allowed to edit?
7907     */
7908    public const EmailConfirmToEdit = [
7909        'default' => false,
7910    ];
7911
7912    /**
7913     * Should MediaWiki attempt to protect user's privacy when doing redirects?
7914     * Keep this true if access counts to articles are made public.
7915     */
7916    public const HideIdentifiableRedirects = [
7917        'default' => true,
7918    ];
7919
7920    /**
7921     * Permission keys given to users in each group.
7922     *
7923     * This is an array where the keys are all groups and each value is an
7924     * array of the format (right => boolean).
7925     *
7926     * The second format is used to support per-namespace permissions.
7927     * Note that this feature does not fully work for all permission types.
7928     *
7929     * All users are implicitly in the '*' group including anonymous visitors;
7930     * logged-in users are all implicitly in the 'user' group. These will be
7931     * combined with the permissions of all groups that a given user is listed
7932     * in the user_groups table.
7933     *
7934     * Note: Don't set $wgGroupPermissions = []; unless you know what you're
7935     * doing! This will wipe all permissions, and may mean that your users are
7936     * unable to perform certain essential tasks or access new functionality
7937     * when new permissions are introduced and default grants established.
7938     *
7939     * Functionality to make pages inaccessible has not been extensively tested
7940     * for security. Use at your own risk!
7941     *
7942     * This replaces $wgWhitelistAccount and $wgWhitelistEdit
7943     */
7944    public const GroupPermissions = [
7945        'type' => 'map',
7946        'additionalProperties' => [
7947            'type' => 'map',
7948            'additionalProperties' => [ 'type' => 'boolean', ],
7949        ],
7950        'mergeStrategy' => 'array_plus_2d',
7951        'default' => [
7952            '*' => [
7953                'createaccount' => true,
7954                'read' => true,
7955                'edit' => true,
7956                'createpage' => true,
7957                'createtalk' => true,
7958                'viewmyprivateinfo' => true,
7959                'editmyprivateinfo' => true,
7960                'editmyoptions' => true,
7961            ],
7962            'user' => [
7963                'move' => true,
7964                'move-subpages' => true,
7965                'move-rootuserpages' => true,
7966                'move-categorypages' => true,
7967                'movefile' => true,
7968                'read' => true,
7969                'edit' => true,
7970                'createpage' => true,
7971                'createtalk' => true,
7972                'upload' => true,
7973                'reupload' => true,
7974                'reupload-shared' => true,
7975                'minoredit' => true,
7976                'editmyusercss' => true,
7977                'editmyuserjson' => true,
7978                'editmyuserjs' => true,
7979                'editmyuserjsredirect' => true,
7980                'sendemail' => true,
7981                'applychangetags' => true,
7982                'changetags' => true,
7983                'editcontentmodel' => true,
7984                'viewmywatchlist' => true,
7985                'editmywatchlist' => true,
7986            ],
7987            'autoconfirmed' => [
7988                'autoconfirmed' => true,
7989                'editsemiprotected' => true,
7990            ],
7991            'bot' => [
7992                'bot' => true,
7993                'autoconfirmed' => true,
7994                'editsemiprotected' => true,
7995                'nominornewtalk' => true,
7996                'autopatrol' => true,
7997                'suppressredirect' => true,
7998                'apihighlimits' => true,
7999            ],
8000            'sysop' => [
8001                'block' => true,
8002                'createaccount' => true,
8003                'delete' => true,
8004                'bigdelete' => true,
8005                'deletedhistory' => true,
8006                'deletedtext' => true,
8007                'undelete' => true,
8008                'editinterface' => true,
8009                'editsitejson' => true,
8010                'edituserjson' => true,
8011                'import' => true,
8012                'importupload' => true,
8013                'move' => true,
8014                'move-subpages' => true,
8015                'move-rootuserpages' => true,
8016                'move-categorypages' => true,
8017                'patrol' => true,
8018                'autopatrol' => true,
8019                'protect' => true,
8020                'editprotected' => true,
8021                'rollback' => true,
8022                'upload' => true,
8023                'reupload' => true,
8024                'reupload-shared' => true,
8025                'unwatchedpages' => true,
8026                'autoconfirmed' => true,
8027                'editsemiprotected' => true,
8028                'ipblock-exempt' => true,
8029                'blockemail' => true,
8030                'markbotedits' => true,
8031                'apihighlimits' => true,
8032                'browsearchive' => true,
8033                'noratelimit' => true,
8034                'movefile' => true,
8035                'unblockself' => true,
8036                'suppressredirect' => true,
8037                'mergehistory' => true,
8038                'managechangetags' => true,
8039                'deletechangetags' => true,
8040            ],
8041            'interface-admin' => [
8042                'editinterface' => true,
8043                'editsitecss' => true,
8044                'editsitejson' => true,
8045                'editsitejs' => true,
8046                'editusercss' => true,
8047                'edituserjson' => true,
8048                'edituserjs' => true,
8049            ],
8050            'bureaucrat' => [
8051                'userrights' => true,
8052                'noratelimit' => true,
8053                'renameuser' => true,
8054            ],
8055            'suppress' => [
8056                'hideuser' => true,
8057                'suppressrevision' => true,
8058                'viewsuppressed' => true,
8059                'suppressionlog' => true,
8060                'deleterevision' => true,
8061                'deletelogentry' => true,
8062            ],
8063        ],
8064    ];
8065
8066    /**
8067     * List of groups which should be considered privileged (user accounts
8068     * belonging in these groups can be abused in dangerous ways).
8069     * This is used for some security checks, mainly logging.
8070     * @since 1.41
8071     * @see \MediaWiki\User\UserGroupManager::getUserPrivilegedGroups()
8072     */
8073    public const PrivilegedGroups = [
8074        'default' => [
8075            'bureaucrat',
8076            'interface-admin',
8077            'suppress',
8078            'sysop',
8079        ],
8080        'type' => 'list',
8081    ];
8082
8083    /**
8084     * Permission keys revoked from users in each group.
8085     *
8086     * This acts the same way as $wgGroupPermissions above, except that
8087     * if the user is in a group here, the permission will be removed from them.
8088     *
8089     * Improperly setting this could mean that your users will be unable to perform
8090     * certain essential tasks, so use at your own risk!
8091     */
8092    public const RevokePermissions = [
8093        'default' => [],
8094        'type' => 'map',
8095        'mergeStrategy' => 'array_plus_2d',
8096    ];
8097
8098    /**
8099     * Groups that should inherit permissions from another group
8100     *
8101     * This allows defining a group that inherits its permissions
8102     * from another group without having to copy all the permission
8103     * grants over. For example, if you wanted a manual "confirmed"
8104     * group that had the same permissions as "autoconfirmed":
8105     *
8106     * ```
8107     * $wgGroupInheritsPermissions['confirmed'] = 'autoconfirmed';
8108     * ```
8109     *
8110     * Recursive inheritance is currently not supported. In the above
8111     * example, confirmed will only gain the permissions explicitly
8112     * granted (or revoked) from autoconfirmed, not any permissions
8113     * that autoconfirmed might inherit.
8114     *
8115     * @since 1.38
8116     */
8117    public const GroupInheritsPermissions = [
8118        'default' => [],
8119        'type' => 'map',
8120        'additionalProperties' => [ 'type' => 'string', ],
8121    ];
8122
8123    /**
8124     * Implicit groups, aren't shown on Special:Listusers or somewhere else
8125     */
8126    public const ImplicitGroups = [
8127        'default' => [ '*', 'user', 'autoconfirmed' ],
8128        'type' => 'list',
8129    ];
8130
8131    /**
8132     * A map of group names that the user is in, to group names that those users
8133     * are allowed to add or revoke.
8134     *
8135     * Setting the list of groups to add or revoke to true is equivalent to "any
8136     * group".
8137     *
8138     * **Example:**
8139     * To allow sysops to add themselves to the "bot" group:
8140     *
8141     * ```
8142     * $wgGroupsAddToSelf = [ 'sysop' => [ 'bot' ] ];
8143     * ```
8144     *
8145     * **Example:**
8146     * Implicit groups may be used for the source group, for instance:
8147     *
8148     * ```
8149     * $wgGroupsRemoveFromSelf = [ '*' => true ];
8150     * ```
8151     *
8152     * This allows users in the '*' group (i.e. any user) to remove themselves from
8153     * any group that they happen to be in.
8154     */
8155    public const GroupsAddToSelf = [
8156        'default' => [],
8157        'type' => 'map',
8158    ];
8159
8160    /**
8161     * @see self::GroupsAddToSelf
8162     */
8163    public const GroupsRemoveFromSelf = [
8164        'default' => [],
8165        'type' => 'map',
8166    ];
8167
8168    /**
8169     * Set of available actions that can be restricted via action=protect
8170     * You probably shouldn't change this.
8171     *
8172     * Translated through restriction-* messages.
8173     * RestrictionStore::listApplicableRestrictionTypes() will remove restrictions that are not
8174     * applicable to a specific title (create and upload)
8175     */
8176    public const RestrictionTypes = [
8177        'default' => [ 'create', 'edit', 'move', 'upload' ],
8178        'type' => 'list',
8179    ];
8180
8181    /**
8182     * Rights which can be required for each protection level (via action=protect)
8183     *
8184     * You can add a new protection level that requires a specific
8185     * permission by manipulating this array. The ordering of elements
8186     * dictates the order on the protection form's lists.
8187     *
8188     *   - '' will be ignored (i.e. unprotected)
8189     *   - 'autoconfirmed' is quietly rewritten to 'editsemiprotected' for backwards compatibility
8190     *   - 'sysop' is quietly rewritten to 'editprotected' for backwards compatibility
8191     */
8192    public const RestrictionLevels = [
8193        'default' => [ '', 'autoconfirmed', 'sysop' ],
8194        'type' => 'list',
8195    ];
8196
8197    /**
8198     * Restriction levels that can be used with cascading protection
8199     *
8200     * A page can only be protected with cascading protection if the
8201     * requested restriction level is included in this array.
8202     *
8203     * 'autoconfirmed' is quietly rewritten to 'editsemiprotected' for backwards compatibility.
8204     * 'sysop' is quietly rewritten to 'editprotected' for backwards compatibility.
8205     */
8206    public const CascadingRestrictionLevels = [
8207        'default' => [ 'sysop', ],
8208        'type' => 'list',
8209    ];
8210
8211    /**
8212     * Restriction levels that should be considered "semiprotected"
8213     *
8214     * Certain places in the interface recognize a dichotomy between "protected"
8215     * and "semiprotected", without further distinguishing the specific levels. In
8216     * general, if anyone can be eligible to edit a protection level merely by
8217     * reaching some condition in $wgAutopromote, it should probably be considered
8218     * "semiprotected".
8219     *
8220     * 'autoconfirmed' is quietly rewritten to 'editsemiprotected' for backwards compatibility.
8221     * 'sysop' is not changed, since it really shouldn't be here.
8222     */
8223    public const SemiprotectedRestrictionLevels = [
8224        'default' => [ 'autoconfirmed', ],
8225        'type' => 'list',
8226    ];
8227
8228    /**
8229     * Set the minimum permissions required to edit pages in each
8230     * namespace.  If you list more than one permission, a user must
8231     * have all of them to edit pages in that namespace.
8232     *
8233     * @note NS_MEDIAWIKI is implicitly restricted to 'editinterface'.
8234     */
8235    public const NamespaceProtection = [
8236        'default' => [],
8237        'type' => 'map',
8238    ];
8239
8240    /**
8241     * Pages in namespaces in this array can not be used as templates.
8242     *
8243     * Elements MUST be numeric namespace ids, you can safely use the MediaWiki
8244     * namespaces constants (NS_USER, NS_MAIN...).
8245     *
8246     * Among other things, this may be useful to enforce read-restrictions
8247     * which may otherwise be bypassed by using the template mechanism.
8248     */
8249    public const NonincludableNamespaces = [
8250        'default' => [],
8251        'type' => 'map',
8252    ];
8253
8254    /**
8255     * Number of seconds an account is required to age before it's given the
8256     * implicit 'autoconfirm' group membership. This can be used to limit
8257     * privileges of new accounts.
8258     *
8259     * Accounts created by earlier versions of the software may not have a
8260     * recorded creation date, and will always be considered to pass the age test.
8261     *
8262     * When left at 0, all registered accounts will pass.
8263     *
8264     * **Example:**
8265     * Set automatic confirmation to 10 minutes (which is 600 seconds):
8266     *
8267     * ```
8268     * $wgAutoConfirmAge = 600;     // ten minutes
8269     * ```
8270     *
8271     * Set age to one day:
8272     *
8273     * ```
8274     * $wgAutoConfirmAge = 3600*24; // one day
8275     * ```
8276     */
8277    public const AutoConfirmAge = [
8278        'default' => 0,
8279    ];
8280
8281    /**
8282     * Number of edits an account requires before it is autoconfirmed.
8283     *
8284     * Passing both this AND the time requirement is needed. Example:
8285     *
8286     * **Example:**
8287     *
8288     * ```
8289     * $wgAutoConfirmCount = 50;
8290     * ```
8291     */
8292    public const AutoConfirmCount = [
8293        'default' => 0,
8294    ];
8295
8296    /**
8297     * Array containing the conditions of automatic promotion of a user to specific groups.
8298     *
8299     * The basic syntax for `$wgAutopromote` is:
8300     *
8301     *     $wgAutopromote = [
8302     *         'groupname' => cond,
8303     *         'group2' => cond2,
8304     *     ];
8305     *
8306     * A `cond` may be:
8307     *  - a single condition without arguments:
8308     *      Note that Autopromote wraps a single non-array value into an array
8309     *      e.g. `APCOND_EMAILCONFIRMED` OR
8310     *           [ `APCOND_EMAILCONFIRMED` ]
8311     *  - a single condition with arguments:
8312     *      e.g. `[ APCOND_EDITCOUNT, 100 ]`
8313     *  - a set of conditions:
8314     *      e.g. `[ 'operand', cond1, cond2, ... ]`
8315     *
8316     * When constructing a set of conditions, the following conditions are available:
8317     *  - `&` (**AND**):
8318     *      promote if user matches **ALL** conditions
8319     *  - `|` (**OR**):
8320     *      promote if user matches **ANY** condition
8321     *  - `^` (**XOR**):
8322     *      promote if user matches **ONLY ONE OF THE CONDITIONS**
8323     *  - `!` (**NOT**):
8324     *      promote if user matces **NO** condition
8325     *  - [ APCOND_EMAILCONFIRMED ]:
8326     *      true if user has a confirmed e-mail
8327     *  - [ APCOND_EDITCOUNT, number of edits (if null or missing $wgAutoConfirmCount will be used)]:
8328     *      true if user has the at least the number of edits as the passed parameter
8329     *  - [ APCOND_AGE, seconds since registration (if null or missing $wgAutoConfirmAge will be used)]:
8330     *      true if the length of time since the user created his/her account
8331     *      is at least the same length of time as the passed parameter
8332     *  - [ APCOND_AGE_FROM_EDIT, seconds since first edit ]:
8333     *      true if the length of time since the user made his/her first edit
8334     *      is at least the same length of time as the passed parameter
8335     *  - [ APCOND_INGROUPS, group1, group2, ... ]:
8336     *      true if the user is a member of each of the passed groups
8337     *  - [ APCOND_ISIP, ip ]:
8338     *      true if the user has the passed IP address
8339     *  - [ APCOND_IPINRANGE, range ]:
8340     *      true if the user has an IP address in the range of the passed parameter
8341     *  - [ APCOND_BLOCKED ]:
8342     *      true if the user is sitewide blocked
8343     *  - [ APCOND_ISBOT ]:
8344     *      true if the user is a bot
8345     *  - similar constructs can be defined by extensions
8346     *
8347     * The sets of conditions are evaluated recursively, so you can use nested sets of conditions
8348     * linked by operands.
8349     *
8350     * Note that if $wgEmailAuthentication is disabled, APCOND_EMAILCONFIRMED will be true for any
8351     * user who has provided an e-mail address.
8352     */
8353    public const Autopromote = [
8354        'default' => [
8355            'autoconfirmed' => [ '&',
8356                [ APCOND_EDITCOUNT, null ], // NOTE: null means $wgAutoConfirmCount
8357                [ APCOND_AGE, null ], // NOTE: null means AutoConfirmAge
8358            ],
8359        ],
8360        'type' => 'map',
8361    ];
8362
8363    /**
8364     * Automatically add a usergroup to any user who matches certain conditions.
8365     *
8366     * Does not add the user to the group again if it has been removed.
8367     * Also, does not remove the group if the user no longer meets the criteria.
8368     *
8369     * The format is:
8370     *
8371     * ```
8372     * [ event => criteria, ... ]
8373     * ```
8374     *
8375     * The only recognised value for event is 'onEdit' (when the user edits).
8376     *
8377     * Criteria has the same format as $wgAutopromote
8378     *
8379     * @see self::Autopromote
8380     * @since 1.18
8381     */
8382    public const AutopromoteOnce = [
8383        'default' => [ 'onEdit' => [], ],
8384        'type' => 'map',
8385    ];
8386
8387    /**
8388     * Put user rights log entries for autopromotion in recent changes?
8389     *
8390     * @since 1.18
8391     */
8392    public const AutopromoteOnceLogInRC = [
8393        'default' => true,
8394    ];
8395
8396    /**
8397     * Defines a denylist of group names. One-shot autopromotions into these groups will not cause a
8398     * RecentChanges entry to be inserted even if AutopromoteOnceLogInRC is set, as long as they are the
8399     * only new groups the user was autopromoted to.
8400     *
8401     * @since 1.44
8402     */
8403    public const AutopromoteOnceRCExcludedGroups = [
8404        'default' => [],
8405        'type' => 'array',
8406    ];
8407
8408    /**
8409     * $wgAddGroups and $wgRemoveGroups can be used to give finer control over who
8410     * can assign which groups at Special:Userrights.
8411     *
8412     * **Example:**
8413     * Bureaucrats can add any group:
8414     *
8415     * ```
8416     * $wgAddGroups['bureaucrat'] = true;
8417     * ```
8418     *
8419     * Bureaucrats can only remove bots and sysops:
8420     *
8421     * ```
8422     * $wgRemoveGroups['bureaucrat'] = [ 'bot', 'sysop' ];
8423     * ```
8424     *
8425     * Sysops can make bots:
8426     *
8427     * ```
8428     * $wgAddGroups['sysop'] = [ 'bot' ];
8429     * ```
8430     *
8431     * Sysops can disable other sysops in an emergency, and disable bots:
8432     *
8433     * ```
8434     * $wgRemoveGroups['sysop'] = [ 'sysop', 'bot' ];
8435     * ```
8436     */
8437    public const AddGroups = [
8438        'default' => [],
8439        'type' => 'map',
8440    ];
8441
8442    /**
8443     * @see self::AddGroups
8444     */
8445    public const RemoveGroups = [
8446        'default' => [],
8447        'type' => 'map',
8448    ];
8449
8450    /**
8451     * A list of available rights, in addition to the ones defined by the core.
8452     * Rights in this list are denied unless explicitly granted, typically
8453     * using GroupPermissions.
8454     *
8455     * For extensions only.
8456     *
8457     * @see self::GroupPermissions
8458     * @see self::ImplicitRights
8459     */
8460    public const AvailableRights = [
8461        'default' => [],
8462        'type' => 'list',
8463        'items' => [ 'type' => 'string', ],
8464    ];
8465
8466    /**
8467     * A list of implicit rights, in addition to the ones defined by the core.
8468     * Rights in this list are granted implicitly to all users, but rate limits
8469     * may apply to them.
8470     *
8471     * Extensions that define rate limits should add the corresponding right to
8472     * either ImplicitRights or AvailableRights, depending on whether the right
8473     * should be granted to everyone.
8474     *
8475     * @since 1.41
8476     * @see self::RateLimits
8477     * @see self::AvailableRights
8478     */
8479    public const ImplicitRights = [
8480        'default' => [],
8481        'type' => 'list',
8482        'items' => [ 'type' => 'string', ]
8483    ];
8484
8485    /**
8486     * Optional to restrict deletion of pages with higher revision counts
8487     * to users with the 'bigdelete' permission. (Default given to sysops.)
8488     */
8489    public const DeleteRevisionsLimit = [
8490        'default' => 0,
8491    ];
8492
8493    /**
8494     * Page deletions with > this number of revisions will use the job queue.
8495     *
8496     * Revisions will be archived in batches of (at most) this size, one batch per job.
8497     */
8498    public const DeleteRevisionsBatchSize = [
8499        'default' => 1000,
8500    ];
8501
8502    /**
8503     * The maximum number of edits a user can have and
8504     * can still be hidden by users with the hideuser permission.
8505     *
8506     * This is limited for performance reason.
8507     * Set to false to disable the limit.
8508     *
8509     * @since 1.23
8510     */
8511    public const HideUserContribLimit = [
8512        'default' => 1000,
8513    ];
8514
8515    /**
8516     * Number of accounts each IP address may create per specified period(s).
8517     *
8518     * **Example:**
8519     *
8520     * ```
8521     * $wgAccountCreationThrottle = [
8522     *  // no more than 100 per month
8523     *  [
8524     *   'count' => 100,
8525     *   'seconds' => 30*86400,
8526     *  ],
8527     *  // no more than 10 per day
8528     *  [
8529     *   'count' => 10,
8530     *   'seconds' => 86400,
8531     *  ],
8532     * ];
8533     * ```
8534     *
8535     * @note For backwards compatibility reasons, this may also be given as a single
8536     *       integer, representing the number of account creations per day.
8537     * @see self::TempAccountCreationThrottle for the temporary accounts version of
8538     *       this throttle
8539     * @warning Requires $wgMainCacheType to be enabled
8540     */
8541    public const AccountCreationThrottle = [
8542        'default' => [ [
8543            'count' => 0,
8544            'seconds' => 86400,
8545        ] ],
8546        'type' => 'int|list',
8547    ];
8548
8549    /**
8550     * Number of temporary accounts each IP address may create per specified period(s).
8551     *
8552     * **Example:**
8553     *
8554     * ```
8555     * $wgTempAccountCreationThrottle = [
8556     *  // no more than 100 per month
8557     *  [
8558     *   'count' => 100,
8559     *   'seconds' => 30*86400,
8560     *  ],
8561     *  // no more than 6 per day
8562     *  [
8563     *   'count' => 6,
8564     *   'seconds' => 86400,
8565     *  ],
8566     * ];
8567     * ```
8568     *
8569     * @see self::AccountCreationThrottle for the regular account version of this throttle.
8570     * @warning Requires $wgMainCacheType to be enabled
8571     *
8572     * @since 1.42
8573     */
8574    public const TempAccountCreationThrottle = [
8575        'default' => [ [
8576            'count' => 6,
8577            'seconds' => 86400,
8578        ] ],
8579        'type' => 'list',
8580    ];
8581
8582    /**
8583     * Number of temporary accounts usernames each IP address may acquire per specified period(s).
8584     *
8585     * This should be set to a higher value than TempAccountCreationThrottle.
8586     *
8587     * On editing, we first attempt to acquire a temp username before proceeding with saving an edit
8588     * and potentially creating a temp account if the edit save is successful.
8589     *
8590     * Some edits may fail (due to core or extensions denying an edit); this throttle ensures that
8591     * there are limits to the number of temporary account names that can be acquired and stored in
8592     * the database.
8593     *
8594     * **Example:**
8595     *
8596     * ```
8597     * $wgTempAccountNameAcquisitionThrottle = [
8598     *  // no more than 100 per month
8599     *  [
8600     *   'count' => 100,
8601     *   'seconds' => 30*86400,
8602     *  ],
8603     *  // no more than 60 per day
8604     *  [
8605     *   'count' => 60,
8606     *   'seconds' => 86400,
8607     *  ],
8608     * ];
8609     * ```
8610     *
8611     * @see self::TempAccountCreationThrottle Make sure that TempAccountNameAcquisitionThrottle is greater than or
8612     *   equal to TempAccountCreationThrottle
8613     * @warning Requires $wgMainCacheType to be enabled
8614     *
8615     * @since 1.42
8616     */
8617    public const TempAccountNameAcquisitionThrottle = [
8618        'default' => [ [
8619            'count' => 60,
8620            'seconds' => 86400,
8621        ] ],
8622        'type' => 'list',
8623    ];
8624
8625    /**
8626     * Edits matching these regular expressions in body text
8627     * will be recognised as spam and rejected automatically.
8628     *
8629     * There's no administrator override on-wiki, so be careful what you set. :)
8630     * May be an array of regexes or a single string for backwards compatibility.
8631     *
8632     * @see https://en.wikipedia.org/wiki/Regular_expression
8633     * @note Each regex needs a beginning/end delimiter, eg: # or /
8634     */
8635    public const SpamRegex = [
8636        'default' => [],
8637        'type' => 'list',
8638    ];
8639
8640    /**
8641     * Same as SpamRegex except for edit summaries
8642     */
8643    public const SummarySpamRegex = [
8644        'default' => [],
8645        'type' => 'list',
8646    ];
8647
8648    /**
8649     * Whether to use DNS blacklists in $wgDnsBlacklistUrls to check for open
8650     * proxies
8651     *
8652     * @since 1.16
8653     */
8654    public const EnableDnsBlacklist = [
8655        'default' => false,
8656    ];
8657
8658    /**
8659     * List of DNS blacklists to use, if $wgEnableDnsBlacklist is true.
8660     *
8661     * This is an array of either a URL or an array with the URL and a key (should
8662     * the blacklist require a key).
8663     *
8664     * **Example:**
8665     *
8666     * ```
8667     * $wgDnsBlacklistUrls = [
8668     *   // String containing URL
8669     *   'http.dnsbl.sorbs.net.',
8670     *   // Array with URL and key, for services that require a key
8671     *   [ 'dnsbl.httpbl.net.', 'mykey' ],
8672     *   // Array with just the URL. While this works, it is recommended that you
8673     *   // just use a string as shown above
8674     *   [ 'opm.tornevall.org.' ]
8675     * ];
8676     * ```
8677     *
8678     * @note You should end the domain name with a . to avoid searching your
8679     * eventual domain search suffixes.
8680     * @since 1.16
8681     */
8682    public const DnsBlacklistUrls = [
8683        'default' => [ 'http.dnsbl.sorbs.net.', ],
8684        'type' => 'list',
8685    ];
8686
8687    /**
8688     * List of banned IP addresses.
8689     *
8690     * This can have the following formats:
8691     * - An array of addresses
8692     * - A string, in which case this is the path to a file
8693     *   containing the list of IP addresses, one per line
8694     */
8695    public const ProxyList = [
8696        'default' => [],
8697        'type' => 'string|list',
8698    ];
8699
8700    /**
8701     * Proxy whitelist, list of addresses that are assumed to be non-proxy despite
8702     * what the other methods might say.
8703     */
8704    public const ProxyWhitelist = [
8705        'default' => [],
8706        'type' => 'list',
8707    ];
8708
8709    /**
8710     * IP ranges that should be considered soft-blocked (anon-only, account
8711     * creation allowed). The intent is to use this to prevent anonymous edits from
8712     * shared resources such as Wikimedia Labs.
8713     *
8714     * @since 1.29
8715     */
8716    public const SoftBlockRanges = [
8717        'default' => [],
8718        'type' => 'list',
8719        'items' => [ 'type' => 'string', ],
8720    ];
8721
8722    /**
8723     * Whether to look at the X-Forwarded-For header's list of (potentially spoofed)
8724     * IPs and apply IP blocks to them. This allows for IP blocks to work with correctly-configured
8725     * (transparent) proxies without needing to block the proxies themselves.
8726     */
8727    public const ApplyIpBlocksToXff = [
8728        'default' => false,
8729    ];
8730
8731    /**
8732     * Simple rate limiter options to brake edit floods.
8733     *
8734     * Maximum number actions allowed in the given number of seconds; after that
8735     * the violating client receives HTTP 500 error pages until the period
8736     * elapses.
8737     *
8738     * **Example:**
8739     * Limits per configured per action and then type of users.
8740     *
8741     * ```
8742     * $wgRateLimits = [
8743     *     'edit' => [
8744     *         'anon' => [ x, y ], // any and all anonymous edits (aggregate)
8745     *         'user' => [ x, y ], // each logged-in user
8746     *         'user-global' => [ x, y ], // per username, across all sites (assumes names are
8747     * global)
8748     *         'newbie' => [ x, y ], // each new autoconfirmed accounts; overrides 'user'
8749     *         'ip' => [ x, y ], // each anon and recent account, across all sites
8750     *         'subnet' => [ x, y ], // ... within a /24 subnet in IPv4 or /64 in IPv6
8751     *         'ip-all' => [ x, y ], // per ip, across all sites
8752     *         'subnet-all' => [ x, y ], // ... within a /24 subnet in IPv4 or /64 in IPv6
8753     *         'groupName' => [ x, y ], // by group membership
8754     *     ]
8755     * ];
8756     * ```
8757     *
8758     * **Normally, the 'noratelimit' right allows a user to bypass any rate**
8759     * limit checks. This can be disabled on a per-action basis by setting the
8760     * special '&can-bypass' key to false in that action's configuration.
8761     *
8762     * ```
8763     * $wgRateLimits = [
8764     *     'some-action' => [
8765     *         '&can-bypass' => false,
8766     *         'user' => [ x, y ],
8767     * ];
8768     * ```
8769     *
8770     * @see self::ImplicitRights
8771     * @warning Requires that $wgMainCacheType is set to something persistent
8772     */
8773    public const RateLimits = [
8774        'default' => [
8775            // Page edits
8776            'edit' => [
8777                'ip' => [ 8, 60 ],
8778                'newbie' => [ 8, 60 ],
8779                'user' => [ 90, 60 ],
8780            ],
8781            // Page moves
8782            'move' => [
8783                'newbie' => [ 2, 120 ],
8784                'user' => [ 8, 60 ],
8785            ],
8786            // File uploads
8787            'upload' => [
8788                'ip' => [ 8, 60 ],
8789                'newbie' => [ 8, 60 ],
8790            ],
8791            // Page rollbacks
8792            'rollback' => [
8793                'user' => [ 10, 60 ],
8794                'newbie' => [ 5, 120 ]
8795            ],
8796            // Triggering password resets emails
8797            'mailpassword' => [
8798                'ip' => [ 5, 3600 ],
8799            ],
8800            // Emailing other users using MediaWiki
8801            'sendemail' => [
8802                'ip' => [ 5, 86400 ],
8803                'newbie' => [ 5, 86400 ],
8804                'user' => [ 20, 86400 ],
8805            ],
8806            'changeemail' => [
8807                'ip-all' => [ 10, 3600 ],
8808                'user' => [ 4, 86400 ]
8809            ],
8810            // since 1.33 - rate limit email confirmations
8811            'confirmemail' => [
8812                'ip-all' => [ 10, 3600 ],
8813                'user' => [ 4, 86400 ]
8814            ],
8815            // Purging pages
8816            'purge' => [
8817                'ip' => [ 30, 60 ],
8818                'user' => [ 30, 60 ],
8819            ],
8820            // Purges of link tables
8821            'linkpurge' => [
8822                'ip' => [ 30, 60 ],
8823                'user' => [ 30, 60 ],
8824            ],
8825            // Files rendered via thumb.php or thumb_handler.php
8826            'renderfile' => [
8827                'ip' => [ 700, 30 ],
8828                'user' => [ 700, 30 ],
8829            ],
8830            // Same as above but for non-standard thumbnails
8831            'renderfile-nonstandard' => [
8832                'ip' => [ 70, 30 ],
8833                'user' => [ 70, 30 ],
8834            ],
8835            // Stashing edits into cache before save
8836            'stashedit' => [
8837                'ip' => [ 30, 60 ],
8838                'newbie' => [ 30, 60 ],
8839            ],
8840            // Stash base HTML for VE edits
8841            'stashbasehtml' => [
8842                'ip' => [ 5, 60 ],
8843                'newbie' => [ 5, 60 ],
8844            ],
8845            // Adding or removing change tags
8846            'changetags' => [
8847                'ip' => [ 8, 60 ],
8848                'newbie' => [ 8, 60 ],
8849            ],
8850            // Changing the content model of a page
8851            'editcontentmodel' => [
8852                'newbie' => [ 2, 120 ],
8853                'user' => [ 8, 60 ],
8854            ],
8855        ],
8856        'type' => 'map',
8857        'mergeStrategy' => 'array_plus_2d',
8858    ];
8859
8860    /**
8861     * Array of IPs / CIDR ranges which should be excluded from rate limits.
8862     *
8863     * This may be useful for allowing NAT gateways for conferences, etc.
8864     */
8865    public const RateLimitsExcludedIPs = [
8866        'default' => [],
8867        'type' => 'list',
8868    ];
8869
8870    /**
8871     * Log IP addresses in the recentchanges table; can be accessed only by
8872     * extensions (e.g. CheckUser) or a DB admin
8873     * Used for retroactive autoblocks
8874     */
8875    public const PutIPinRC = [
8876        'default' => true,
8877    ];
8878
8879    /**
8880     * Integer defining default number of entries to show on
8881     * special pages which are query-pages such as Special:Whatlinkshere.
8882     */
8883    public const QueryPageDefaultLimit = [
8884        'default' => 50,
8885    ];
8886
8887    /**
8888     * Limit password attempts to X attempts per Y seconds per IP per account.
8889     *
8890     * Value is an array of arrays. Each sub-array must have a key for count
8891     * (ie count of how many attempts before throttle) and a key for seconds.
8892     * If the key 'allIPs' (case sensitive) is present, then the limit is
8893     * just per account instead of per IP per account.
8894     *
8895     * @since 1.27 allIps support and multiple limits added in 1.27. Prior
8896     * to 1.27 this only supported having a single throttle.
8897     * @warning Requires $wgMainCacheType to be enabled
8898     */
8899    public const PasswordAttemptThrottle = [
8900        'default' => [
8901            // Short term limit
8902            [ 'count' => 5, 'seconds' => 300 ],
8903            // Long term limit. We need to balance the risk
8904            // of somebody using this as a DoS attack to lock someone
8905            // out of their account, and someone doing a brute force attack.
8906            [ 'count' => 150, 'seconds' => 60 * 60 * 48 ],
8907        ],
8908        'type' => 'list',
8909    ];
8910
8911    /**
8912     * Users authorize consumers (like Apps) to act on their behalf but only with
8913     * a subset of the user's normal account rights (signed off on by the user).
8914     * The possible rights to grant to a consumer are bundled into groups called
8915     * "grants". Each grant defines some rights it lets consumers inherit from the
8916     * account they may act on behalf of. Note that a user granting a right does
8917     * nothing if that user does not actually have that right to begin with.
8918     *
8919     * @since 1.27
8920     */
8921    public const GrantPermissions = [
8922        'default' => [
8923            'basic' => [
8924                'autocreateaccount' => true,
8925                'autoconfirmed' => true,
8926                'autopatrol' => true,
8927                'editsemiprotected' => true,
8928                'ipblock-exempt' => true,
8929                'nominornewtalk' => true,
8930                'patrolmarks' => true,
8931                'read' => true,
8932                'unwatchedpages' => true,
8933            ],
8934            'highvolume' => [
8935                'bot' => true,
8936                'apihighlimits' => true,
8937                'noratelimit' => true,
8938                'markbotedits' => true,
8939            ],
8940            'import' => [
8941                'import' => true,
8942                'importupload' => true,
8943            ],
8944            'editpage' => [
8945                'edit' => true,
8946                'minoredit' => true,
8947                'applychangetags' => true,
8948                'changetags' => true,
8949                'editcontentmodel' => true,
8950                'pagelang' => true,
8951            ],
8952            'editprotected' => [
8953                'edit' => true,
8954                'minoredit' => true,
8955                'applychangetags' => true,
8956                'changetags' => true,
8957                'editcontentmodel' => true,
8958                'editprotected' => true,
8959            ],
8960            'editmycssjs' => [
8961                'edit' => true,
8962                'minoredit' => true,
8963                'applychangetags' => true,
8964                'changetags' => true,
8965                'editcontentmodel' => true,
8966                'editmyusercss' => true,
8967                'editmyuserjson' => true,
8968                'editmyuserjs' => true,
8969            ],
8970            'editmyoptions' => [
8971                'editmyoptions' => true,
8972                'editmyuserjson' => true,
8973            ],
8974            'editinterface' => [
8975                'edit' => true,
8976                'minoredit' => true,
8977                'applychangetags' => true,
8978                'changetags' => true,
8979                'editcontentmodel' => true,
8980                'editinterface' => true,
8981                'edituserjson' => true,
8982                'editsitejson' => true,
8983            ],
8984            'editsiteconfig' => [
8985                'edit' => true,
8986                'minoredit' => true,
8987                'applychangetags' => true,
8988                'changetags' => true,
8989                'editcontentmodel' => true,
8990                'editinterface' => true,
8991                'edituserjson' => true,
8992                'editsitejson' => true,
8993                'editusercss' => true,
8994                'edituserjs' => true,
8995                'editsitecss' => true,
8996                'editsitejs' => true,
8997            ],
8998            'createeditmovepage' => [
8999                'edit' => true,
9000                'minoredit' => true,
9001                'applychangetags' => true,
9002                'changetags' => true,
9003                'editcontentmodel' => true,
9004                'createpage' => true,
9005                'createtalk' => true,
9006                'delete-redirect' => true,
9007                'move' => true,
9008                'move-rootuserpages' => true,
9009                'move-subpages' => true,
9010                'move-categorypages' => true,
9011                'suppressredirect' => true,
9012            ],
9013            'uploadfile' => [
9014                'upload' => true,
9015                'reupload-own' => true,
9016            ],
9017            'uploadeditmovefile' => [
9018                'upload' => true,
9019                'reupload-own' => true,
9020                'reupload' => true,
9021                'reupload-shared' => true,
9022                'upload_by_url' => true,
9023                'movefile' => true,
9024                'suppressredirect' => true,
9025            ],
9026            'patrol' => [
9027                'patrol' => true,
9028            ],
9029            'rollback' => [
9030                'rollback' => true,
9031            ],
9032            'blockusers' => [
9033                'block' => true,
9034                'blockemail' => true,
9035            ],
9036            'viewdeleted' => [
9037                'browsearchive' => true,
9038                'deletedhistory' => true,
9039                'deletedtext' => true,
9040            ],
9041            'viewrestrictedlogs' => [
9042                'suppressionlog' => true,
9043            ],
9044            'delete' => [
9045                'edit' => true,
9046                'minoredit' => true,
9047                'applychangetags' => true,
9048                'changetags' => true,
9049                'editcontentmodel' => true,
9050                'browsearchive' => true,
9051                'deletedhistory' => true,
9052                'deletedtext' => true,
9053                'delete' => true,
9054                'bigdelete' => true,
9055                'deletelogentry' => true,
9056                'deleterevision' => true,
9057                'undelete' => true,
9058            ],
9059            'oversight' => [
9060                'suppressrevision' => true,
9061                'viewsuppressed' => true,
9062            ],
9063            'protect' => [
9064                'edit' => true,
9065                'minoredit' => true,
9066                'applychangetags' => true,
9067                'changetags' => true,
9068                'editcontentmodel' => true,
9069                'editprotected' => true,
9070                'protect' => true,
9071            ],
9072            'viewmywatchlist' => [
9073                'viewmywatchlist' => true,
9074            ],
9075            'editmywatchlist' => [
9076                'editmywatchlist' => true,
9077            ],
9078            'sendemail' => [
9079                'sendemail' => true,
9080            ],
9081            'createaccount' => [
9082                'createaccount' => true,
9083            ],
9084            'privateinfo' => [
9085                'viewmyprivateinfo' => true,
9086            ],
9087            'mergehistory' => [
9088                'mergehistory' => true,
9089            ],
9090        ],
9091        'type' => 'map',
9092        'mergeStrategy' => 'array_plus_2d',
9093        'additionalProperties' => [
9094            'type' => 'map',
9095            'additionalProperties' => [ 'type' => 'boolean', ],
9096        ],
9097    ];
9098
9099    /**
9100     * Grant groups are used on some user interfaces to display conceptually
9101     * similar grants together.
9102     *
9103     * This configuration value should usually be set by extensions, not
9104     * site administrators.
9105     *
9106     * @see self::GrantPermissions
9107     * @since 1.27
9108     */
9109    public const GrantPermissionGroups = [
9110        'default' =>
9111            [
9112                // Hidden grants are implicitly present
9113                'basic'               => 'hidden',
9114
9115                'editpage'            => 'page-interaction',
9116                'createeditmovepage'  => 'page-interaction',
9117                'editprotected'       => 'page-interaction',
9118                'patrol'              => 'page-interaction',
9119
9120                'uploadfile'          => 'file-interaction',
9121                'uploadeditmovefile'  => 'file-interaction',
9122
9123                'sendemail'           => 'email',
9124
9125                'viewmywatchlist'     => 'watchlist-interaction',
9126                'editviewmywatchlist' => 'watchlist-interaction',
9127
9128                'editmycssjs'         => 'customization',
9129                'editmyoptions'       => 'customization',
9130
9131                'editinterface'       => 'administration',
9132                'editsiteconfig'      => 'administration',
9133                'rollback'            => 'administration',
9134                'blockusers'          => 'administration',
9135                'delete'              => 'administration',
9136                'viewdeleted'         => 'administration',
9137                'viewrestrictedlogs'  => 'administration',
9138                'protect'             => 'administration',
9139                'oversight'           => 'administration',
9140                'createaccount'       => 'administration',
9141                'mergehistory'        => 'administration',
9142                'import'              => 'administration',
9143
9144                'highvolume'          => 'high-volume',
9145
9146                'privateinfo'         => 'private-information',
9147            ],
9148        'type' => 'map',
9149        'additionalProperties' => [ 'type' => 'string', ],
9150    ];
9151
9152    /**
9153     * Group grants by risk level. Keys are grant names (i.e. keys from GrantPermissions),
9154     * values are GrantsInfo::RISK_* constants.
9155     *
9156     * Note that this classification is only informative; merely applying 'security' or 'internal'
9157     * to a grant won't prevent it from being available. It's used to give guidance to users
9158     * in various interfaces about the riskiness of the various grants.
9159     *
9160     * @since 1.42
9161     */
9162    public const GrantRiskGroups = [
9163        'default' => [
9164            'basic'               => GrantsInfo::RISK_LOW,
9165            'editpage'            => GrantsInfo::RISK_LOW,
9166            'createeditmovepage'  => GrantsInfo::RISK_LOW,
9167            'editprotected'       => GrantsInfo::RISK_VANDALISM,
9168            'patrol'              => GrantsInfo::RISK_LOW,
9169            'uploadfile'          => GrantsInfo::RISK_LOW,
9170            'uploadeditmovefile'  => GrantsInfo::RISK_LOW,
9171            'sendemail'           => GrantsInfo::RISK_SECURITY,
9172            'viewmywatchlist'     => GrantsInfo::RISK_LOW,
9173            'editviewmywatchlist' => GrantsInfo::RISK_LOW,
9174            'editmycssjs'         => GrantsInfo::RISK_SECURITY,
9175            'editmyoptions'       => GrantsInfo::RISK_SECURITY,
9176            'editinterface'       => GrantsInfo::RISK_VANDALISM,
9177            'editsiteconfig'      => GrantsInfo::RISK_SECURITY,
9178            'rollback'            => GrantsInfo::RISK_LOW,
9179            'blockusers'          => GrantsInfo::RISK_VANDALISM,
9180            'delete'              => GrantsInfo::RISK_VANDALISM,
9181            'viewdeleted'         => GrantsInfo::RISK_VANDALISM,
9182            'viewrestrictedlogs'  => GrantsInfo::RISK_SECURITY,
9183            'protect'             => GrantsInfo::RISK_VANDALISM,
9184            'oversight'           => GrantsInfo::RISK_SECURITY,
9185            'createaccount'       => GrantsInfo::RISK_LOW,
9186            'mergehistory'        => GrantsInfo::RISK_VANDALISM,
9187            'import'              => GrantsInfo::RISK_SECURITY,
9188            'highvolume'          => GrantsInfo::RISK_LOW,
9189            'privateinfo'         => GrantsInfo::RISK_LOW,
9190        ],
9191        'type' => 'map',
9192    ];
9193
9194    /**
9195     * @since 1.27
9196     */
9197    public const EnableBotPasswords = [
9198        'default' => true,
9199        'type' => 'boolean',
9200    ];
9201
9202    /**
9203     * Cluster for the bot_passwords table
9204     *
9205     * @since 1.27
9206     * @deprecated since 1.42 Use $wgVirtualDomainsMapping instead.
9207     */
9208    public const BotPasswordsCluster = [
9209        'default' => false,
9210        'type' => 'string|false',
9211    ];
9212
9213    /**
9214     * Database name for the bot_passwords table
9215     *
9216     * To use a database with a table prefix, set this variable to
9217     * "{$database}-{$prefix}".
9218     *
9219     * @since 1.27
9220     * @deprecated since 1.42 Use $wgVirtualDomainsMapping instead.
9221     */
9222    public const BotPasswordsDatabase = [
9223        'default' => false,
9224        'type' => 'string|false',
9225    ];
9226
9227    // endregion -- end of user rights settings
9228
9229    /***************************************************************************/
9230    // region   Security
9231    /** @name   Security */
9232
9233    /**
9234     * This should always be customised in LocalSettings.php
9235     */
9236    public const SecretKey = [
9237        'default' => false,
9238    ];
9239
9240    /**
9241     * Allow user Javascript page?
9242     * This enables a lot of neat customizations, but may
9243     * increase security risk to users and server load.
9244     */
9245    public const AllowUserJs = [
9246        'default' => false,
9247    ];
9248
9249    /**
9250     * Allow user Cascading Style Sheets (CSS)?
9251     * This enables a lot of neat customizations, but may
9252     * increase security risk to users and server load.
9253     */
9254    public const AllowUserCss = [
9255        'default' => false,
9256    ];
9257
9258    /**
9259     * Allow style-related user-preferences?
9260     *
9261     * This controls whether the `editfont` and `underline` preferences
9262     * are available to users.
9263     */
9264    public const AllowUserCssPrefs = [
9265        'default' => true,
9266    ];
9267
9268    /**
9269     * Use the site's Javascript page?
9270     */
9271    public const UseSiteJs = [
9272        'default' => true,
9273    ];
9274
9275    /**
9276     * Use the site's Cascading Style Sheets (CSS)?
9277     */
9278    public const UseSiteCss = [
9279        'default' => true,
9280    ];
9281
9282    /**
9283     * Break out of framesets. This can be used to prevent clickjacking attacks,
9284     * or to prevent external sites from framing your site with ads.
9285     */
9286    public const BreakFrames = [
9287        'default' => false,
9288    ];
9289
9290    /**
9291     * The X-Frame-Options header to send on pages sensitive to clickjacking
9292     * attacks, such as edit pages. This prevents those pages from being displayed
9293     * in a frame or iframe. The options are:
9294     *
9295     *   - 'DENY': Do not allow framing. This is recommended for most wikis.
9296     *
9297     *   - 'SAMEORIGIN': Allow framing by pages on the same domain. This can be used
9298     *         to allow framing within a trusted domain. This is insecure if there
9299     *         is a page on the same domain which allows framing of arbitrary URLs.
9300     *
9301     *   - false: Allow all framing. This opens up the wiki to XSS attacks and thus
9302     *         full compromise of local user accounts. Private wikis behind a
9303     *         corporate firewall are especially vulnerable. This is not
9304     *         recommended.
9305     *
9306     * For extra safety, set $wgBreakFrames = true, to prevent framing on all pages,
9307     * not just edit pages.
9308     */
9309    public const EditPageFrameOptions = [
9310        'default' => 'DENY',
9311    ];
9312
9313    /**
9314     * Disallow framing of API pages directly, by setting the X-Frame-Options
9315     * header. Since the API returns CSRF tokens, allowing the results to be
9316     * framed can compromise your user's account security.
9317     *
9318     * Options are:
9319     *   - 'DENY': Do not allow framing. This is recommended for most wikis.
9320     *   - 'SAMEORIGIN': Allow framing by pages on the same domain.
9321     *   - false: Allow all framing.
9322     * Note: $wgBreakFrames will override this for human formatted API output.
9323     */
9324    public const ApiFrameOptions = [
9325        'default' => 'DENY',
9326    ];
9327
9328    /**
9329     * Controls Content-Security-Policy header
9330     *
9331     * @warning May cause slowness on Windows due to slow random number generator.
9332     *
9333     * @unstable EXPERIMENTAL
9334     * @since 1.32
9335     * @see https://www.w3.org/TR/CSP2/
9336     */
9337    public const CSPHeader = [
9338        'default' => false,
9339        'type' => 'false|object',
9340    ];
9341
9342    /**
9343     * Controls Content-Security-Policy-Report-Only header
9344     *
9345     * @since 1.32
9346     */
9347    public const CSPReportOnlyHeader = [
9348        'default' => false,
9349        'type' => 'false|object',
9350    ];
9351
9352    /**
9353     * List of urls which appear often to be triggering CSP reports
9354     * but do not appear to be caused by actual content, but by client
9355     * software inserting scripts (i.e. Ad-Ware).
9356     *
9357     * List based on results from Wikimedia logs.
9358     *
9359     * @since 1.28
9360     */
9361    public const CSPFalsePositiveUrls = [
9362        'default' => [
9363            'https://3hub.co' => true,
9364            'https://morepro.info' => true,
9365            'https://p.ato.mx' => true,
9366            'https://s.ato.mx' => true,
9367            'https://adserver.adtech.de' => true,
9368            'https://ums.adtechus.com' => true,
9369            'https://cas.criteo.com' => true,
9370            'https://cat.nl.eu.criteo.com' => true,
9371            'https://atpixel.alephd.com' => true,
9372            'https://rtb.metrigo.com' => true,
9373            'https://d5p.de17a.com' => true,
9374            'https://ad.lkqd.net/vpaid/vpaid.js' => true,
9375            'https://ad.lkqd.net/vpaid/vpaid.js?fusion=1.0' => true,
9376            'https://t.lkqd.net/t' => true,
9377            'chrome-extension' => true,
9378        ],
9379        'type' => 'map',
9380    ];
9381
9382    /**
9383     * Allow anonymous cross origin requests to the REST API.
9384     *
9385     * This should be disabled for intranet sites (sites behind a firewall).
9386     *
9387     * @since 1.36
9388     */
9389    public const AllowCrossOrigin = [
9390        'default' => false,
9391        'type' => 'boolean',
9392    ];
9393
9394    /**
9395     * Allows authenticated cross-origin requests to the REST API with session cookies.
9396     *
9397     * With this option enabled, any origin specified in $wgCrossSiteAJAXdomains may send session
9398     * cookies for authorization in the REST API.
9399     *
9400     * There is a performance impact by enabling this option. Therefore, it should be left disabled
9401     * for most wikis and clients should instead use OAuth to make cross-origin authenticated
9402     * requests.
9403     *
9404     * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
9405     * @since 1.36
9406     */
9407    public const RestAllowCrossOriginCookieAuth = [
9408        'default' => false,
9409        'type' => 'boolean',
9410    ];
9411
9412    /**
9413     * Secret for session storage.
9414     *
9415     * This should be set in LocalSettings.php, otherwise $wgSecretKey will
9416     * be used.
9417     *
9418     * @since 1.27
9419     */
9420    public const SessionSecret = [
9421        'default' => false,
9422    ];
9423
9424    // endregion -- end of security
9425
9426    /***************************************************************************/
9427    // region   Cookie settings
9428    /** @name   Cookie settings */
9429
9430    /**
9431     * Default cookie lifetime, in seconds. Setting to 0 makes all cookies session-only.
9432     */
9433    public const CookieExpiration = [
9434        'default' => 30 * 86400,
9435    ];
9436
9437    /**
9438     * Default login cookie lifetime, in seconds. Setting
9439     * $wgExtendLoginCookieExpiration to null will use $wgCookieExpiration to
9440     * calculate the cookie lifetime. As with $wgCookieExpiration, 0 will make
9441     * login cookies session-only.
9442     */
9443    public const ExtendedLoginCookieExpiration = [
9444        'default' => 180 * 86400,
9445    ];
9446
9447    /**
9448     * Set to set an explicit domain on the login cookies eg, "justthis.domain.org"
9449     * or ".any.subdomain.net"
9450     */
9451    public const CookieDomain = [
9452        'default' => '',
9453    ];
9454
9455    /**
9456     * Set this variable if you want to restrict cookies to a certain path within
9457     * the domain specified by $wgCookieDomain.
9458     */
9459    public const CookiePath = [
9460        'default' => '/',
9461    ];
9462
9463    /**
9464     * Whether the "secure" flag should be set on the cookie. This can be:
9465     *   - true:      Set secure flag
9466     *   - false:     Don't set secure flag
9467     *   - "detect":  Set the secure flag if $wgServer is set to an HTTPS URL,
9468     *                or if $wgForceHTTPS is true.
9469     *
9470     * If $wgForceHTTPS is true, session cookies will be secure regardless of this
9471     * setting. However, other cookies will still be affected.
9472     */
9473    public const CookieSecure = [
9474        'default' => 'detect',
9475        'dynamicDefault' => [ 'use' => [ 'ForceHTTPS' ] ]
9476    ];
9477
9478    public static function getDefaultCookieSecure( $forceHTTPS ): bool {
9479        return $forceHTTPS || ( WebRequest::detectProtocol() === 'https' );
9480    }
9481
9482    /**
9483     * Cookies generated by MediaWiki have names starting with this prefix. Set it
9484     * to a string to use a custom prefix. Setting it to false causes the database
9485     * name to be used as a prefix.
9486     */
9487    public const CookiePrefix = [
9488        'default' => false,
9489        'dynamicDefault' => [
9490            'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix' ]
9491        ],
9492    ];
9493
9494    public static function getDefaultCookiePrefix(
9495        $sharedDB, $sharedPrefix, $sharedTables, $dbName, $dbPrefix
9496    ): string {
9497        if ( $sharedDB && in_array( 'user', $sharedTables ) ) {
9498            return $sharedDB . ( $sharedPrefix ? "_$sharedPrefix" : '' );
9499        }
9500        return $dbName . ( $dbPrefix ? "_$dbPrefix" : '' );
9501    }
9502
9503    /**
9504     * Set authentication cookies to HttpOnly to prevent access by JavaScript,
9505     * in browsers that support this feature. This can mitigates some classes of
9506     * XSS attack.
9507     */
9508    public const CookieHttpOnly = [
9509        'default' => true,
9510    ];
9511
9512    /**
9513     * The SameSite cookie attribute used for login cookies. This can be "Lax",
9514     * "Strict", "None" or empty/null to omit the attribute.
9515     *
9516     * This only applies to login cookies, since the correct value for other
9517     * cookies depends on what kind of cookie it is.
9518     *
9519     * @since 1.35
9520     */
9521    public const CookieSameSite = [
9522        'default' => null,
9523        'type' => '?string',
9524    ];
9525
9526    /**
9527     * A list of cookies that vary the cache (for use by extensions)
9528     */
9529    public const CacheVaryCookies = [
9530        'default' => [],
9531        'type' => 'list',
9532    ];
9533
9534    /**
9535     * Override to customise the session name
9536     */
9537    public const SessionName = [
9538        'default' => false,
9539    ];
9540
9541    /**
9542     * Whether to set a cookie when a user is autoblocked. Doing so means that a blocked user, even
9543     * after logging out and moving to a new IP address, will still be blocked. This cookie will
9544     * contain an authentication code if $wgSecretKey is set, or otherwise will just be the block
9545     * ID (in which case there is a possibility of an attacker discovering the names of revdeleted
9546     * users, so it is best to use this in conjunction with $wgSecretKey being set).
9547     */
9548    public const CookieSetOnAutoblock = [
9549        'default' => true,
9550    ];
9551
9552    /**
9553     * Whether to set a cookie when a logged-out user is blocked. Doing so means that a blocked
9554     * user, even after moving to a new IP address, will still be blocked. This cookie will contain
9555     * an authentication code if $wgSecretKey is set, or otherwise will just be the block ID (in
9556     * which case there is a possibility of an attacker discovering the names of revdeleted users,
9557     * so it is best to use this in conjunction with $wgSecretKey being set).
9558     */
9559    public const CookieSetOnIpBlock = [
9560        'default' => true,
9561    ];
9562
9563    // endregion -- end of cookie settings
9564
9565    /***************************************************************************/
9566    // region   Profiling, testing and debugging
9567    /** @name   Profiling, testing and debugging */
9568    // See $wgProfiler for how to enable profiling.
9569
9570    /**
9571     * Enable verbose debug logging for all channels and log levels.
9572     *
9573     * See https://www.mediawiki.org/wiki/How_to_debug
9574     *
9575     * For static requests, this enables all channels and warning-level and
9576     * above only. Use $wgDebugRawPage to make those verbose as well.
9577     *
9578     * The debug log file should be not be web-accessible if it is used in
9579     * a production environment, as may contain private data.
9580     */
9581    public const DebugLogFile = [
9582        'default' => '',
9583    ];
9584
9585    /**
9586     * Prefix for debug log lines
9587     */
9588    public const DebugLogPrefix = [
9589        'default' => '',
9590    ];
9591
9592    /**
9593     * If true, instead of redirecting, show a page with a link to the redirect
9594     * destination. This allows for the inspection of PHP error messages, and easy
9595     * resubmission of form data. For developer use only.
9596     */
9597    public const DebugRedirects = [
9598        'default' => false,
9599    ];
9600
9601    /**
9602     * If true, debug logging is also enabled for load.php and action=raw requests.
9603     *
9604     * By default, $wgDebugLogFile enables all channels and warning-level and
9605     * above for static requests.
9606     *
9607     * This ensures that the debug log is likely a chronological record of
9608     * of specific web request you are debugging, instead of overlapping with
9609     * messages from static requests, which would make it unclear which message
9610     * originated from what request.
9611     *
9612     * Also, during development this can make browsing and JavaScript testing
9613     * considerably slower (T85805).
9614     */
9615    public const DebugRawPage = [
9616        'default' => false,
9617    ];
9618
9619    /**
9620     * Send debug data to an HTML comment in the output.
9621     *
9622     * This may occasionally be useful when supporting a non-technical end-user.
9623     * It's more secure than exposing the debug log file to the web, since the
9624     * output only contains private data for the current user. But it's not ideal
9625     * for development use since data is lost on fatal errors and redirects.
9626     */
9627    public const DebugComments = [
9628        'default' => false,
9629    ];
9630
9631    /**
9632     * Write SQL queries to the debug log.
9633     *
9634     * This setting is only used $wgLBFactoryConf['class'] is set to
9635     * '\Wikimedia\Rdbms\LBFactorySimple'; otherwise the DBO_DEBUG flag must be set in
9636     * the 'flags' option of the database connection to achieve the same functionality.
9637     */
9638    public const DebugDumpSql = [
9639        'default' => false,
9640    ];
9641
9642    /**
9643     * Performance expectations for DB usage
9644     *
9645     * @since 1.26
9646     */
9647    public const TrxProfilerLimits = [
9648        'default' => [
9649            // HTTP GET/HEAD requests.
9650            // Primary queries should not happen on GET requests
9651            'GET' => [
9652                'masterConns' => 0,
9653                'writes' => 0,
9654                'readQueryTime' => 5,
9655                'readQueryRows' => 10000
9656            ],
9657            // HTTP POST requests.
9658            // Primary reads and writes will happen for a subset of these.
9659            'POST' => [
9660                'readQueryTime' => 5,
9661                'writeQueryTime' => 1,
9662                'readQueryRows' => 100_000,
9663                'maxAffected' => 1000
9664            ],
9665            'POST-nonwrite' => [
9666                'writes' => 0,
9667                'readQueryTime' => 5,
9668                'readQueryRows' => 10000
9669            ],
9670            // Deferred updates that run after HTTP response is sent for GET requests
9671            'PostSend-GET' => [
9672                'readQueryTime' => 5,
9673                'writeQueryTime' => 1,
9674                'readQueryRows' => 10000,
9675                'maxAffected' => 1000,
9676                // Log primary queries under the post-send entry point as they are discouraged
9677                'masterConns' => 0,
9678                'writes' => 0,
9679            ],
9680            // Deferred updates that run after HTTP response is sent for POST requests
9681            'PostSend-POST' => [
9682                'readQueryTime' => 5,
9683                'writeQueryTime' => 1,
9684                'readQueryRows' => 100_000,
9685                'maxAffected' => 1000
9686            ],
9687            // Background job runner
9688            'JobRunner' => [
9689                'readQueryTime' => 30,
9690                'writeQueryTime' => 5,
9691                'readQueryRows' => 100_000,
9692                'maxAffected' => 500 // ballpark of $wgUpdateRowsPerQuery
9693            ],
9694            // Command-line scripts
9695            'Maintenance' => [
9696                'writeQueryTime' => 5,
9697                'maxAffected' => 1000
9698            ]
9699        ],
9700        'type' => 'map',
9701    ];
9702
9703    /**
9704     * Map of string log group names to log destinations.
9705     *
9706     * If set, wfDebugLog() output for that group will go to that file instead
9707     * of the regular $wgDebugLogFile. Useful for enabling selective logging
9708     * in production.
9709     *
9710     * Log destinations may be one of the following:
9711     * - false to completely remove from the output, including from $wgDebugLogFile.
9712     * - string values specifying a filename or URI.
9713     * - associative array with keys:
9714     *   - 'destination' desired filename or URI.
9715     *   - 'sample' an integer value, specifying a sampling factor (optional)
9716     *   - 'level' A \Psr\Log\LogLevel constant, indicating the minimum level
9717     *             to log (optional, since 1.25)
9718     *
9719     * **Example:**
9720     *
9721     * ```
9722     * $wgDebugLogGroups['redis'] = '/var/log/mediawiki/redis.log';
9723     * ```
9724     *
9725     * **Advanced example:**
9726     *
9727     * ```
9728     * $wgDebugLogGroups['memcached'] = [
9729     *     'destination' => '/var/log/mediawiki/memcached.log',
9730     *     'sample' => 1000,  // log 1 message out of every 1,000.
9731     *     'level' => \Psr\Log\LogLevel::WARNING
9732     * ];
9733     * ```
9734     */
9735    public const DebugLogGroups = [
9736        'default' => [],
9737        'type' => 'map',
9738    ];
9739
9740    /**
9741     * Default service provider for creating Psr\Log\LoggerInterface instances.
9742     *
9743     * The value should be an array suitable for use with
9744     * ObjectFactory::getObjectFromSpec(). The created object is expected to
9745     * implement the MediaWiki\Logger\Spi interface. See ObjectFactory for additional
9746     * details.
9747     *
9748     * Alternately the MediaWiki\Logger\LoggerFactory::registerProvider method can
9749     * be called to inject an MediaWiki\Logger\Spi instance into the LoggerFactory
9750     * and bypass the use of this configuration variable entirely.
9751     *
9752     * **To completely disable logging:**
9753     *
9754     * ```
9755     * $wgMWLoggerDefaultSpi = [ 'class' => \MediaWiki\Logger\NullSpi::class ];
9756     * ```
9757     *
9758     * @since 1.25
9759     * @see \MwLogger
9760     */
9761    public const MWLoggerDefaultSpi = [
9762        'default' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ],
9763        'mergeStrategy' => 'replace',
9764        'type' => 'map',
9765    ];
9766
9767    /**
9768     * Display debug data at the bottom of the main content area.
9769     *
9770     * Useful for developers and technical users trying to working on a closed wiki.
9771     */
9772    public const ShowDebug = [
9773        'default' => false,
9774    ];
9775
9776    /**
9777     * Show the contents of $wgHooks in Special:Version
9778     */
9779    public const SpecialVersionShowHooks = [
9780        'default' => false,
9781    ];
9782
9783    /**
9784     * Show exception message and stack trace when printing details about uncaught exceptions
9785     * in web response output.
9786     *
9787     * This may reveal private information in error messages or function parameters.
9788     * If set to false, only the exception type or class name will be exposed.
9789     */
9790    public const ShowExceptionDetails = [
9791        'default' => false,
9792    ];
9793
9794    /**
9795     * If true, send the exception backtrace to the error log
9796     */
9797    public const LogExceptionBacktrace = [
9798        'default' => true,
9799    ];
9800
9801    /**
9802     * If true, the MediaWiki error handler passes errors/warnings to the default error handler
9803     * after logging them. The setting is ignored when the track_errors php.ini flag is true.
9804     */
9805    public const PropagateErrors = [
9806        'default' => true,
9807    ];
9808
9809    /**
9810     * Expose backend server host names through the API and various HTML comments
9811     */
9812    public const ShowHostnames = [
9813        'default' => false,
9814    ];
9815
9816    /**
9817     * Override server hostname detection with a hardcoded value.
9818     *
9819     * Should be a string, default false.
9820     *
9821     * @since 1.20
9822     */
9823    public const OverrideHostname = [
9824        'default' => false,
9825    ];
9826
9827    /**
9828     * If set to true MediaWiki will throw notices for some possible error
9829     * conditions and for deprecated functions.
9830     */
9831    public const DevelopmentWarnings = [
9832        'default' => false,
9833    ];
9834
9835    /**
9836     * Release limitation to wfDeprecated warnings, if set to a release number
9837     * development warnings will not be generated for deprecations added in releases
9838     * after the limit.
9839     */
9840    public const DeprecationReleaseLimit = [
9841        'default' => false,
9842    ];
9843
9844    /**
9845     * Profiler configuration.
9846     *
9847     * To use a profiler, set $wgProfiler in LocalSettings.php.
9848     *
9849     * Options:
9850     *
9851     * - 'class' (`string`): The Profiler subclass to use.
9852     *   Default: ProfilerStub.
9853     * - 'sampling' (`integer`): Only enable the profiler on one in this many requests.
9854     *   For requests that are not in the sampling,
9855     *   the 'class' option will be replaced with ProfilerStub.
9856     *   Default: `1`.
9857     * - 'threshold' (`float`): Only process the recorded data if the total elapsed
9858     *   time for a request is more than this number of seconds.
9859     *   Default: `0.0`.
9860     * - 'output' (`string|string[]`):  ProfilerOutput subclass or subclasess to use.
9861     *   Default: `[]`.
9862     *
9863     * The options array is passed in its entirety to the specified
9864     * Profiler `class`. Check individual Profiler subclasses for additional
9865     * options that may be available.
9866     *
9867     * Profiler subclasses available in MediaWiki core:
9868     *
9869     * - ProfilerXhprof: Based on XHProf or Tideways-XHProf.
9870     * - ProfilerExcimer: Based on Excimer.
9871     * - ProfilerSectionOnly
9872     *
9873     * Profiler output classes available in MediaWiki:
9874     *
9875     * - ProfilerOutputText: outputs profiling data in the web page body as
9876     *   a comment.  You can make the profiling data in HTML render visibly
9877     *   instead by setting the 'visible' configuration flag.
9878     *
9879     * - ProfilerOutputStats: outputs profiling data as StatsD metrics.
9880     *   It expects that $wgStatsdServer is set to the host (or host:port)
9881     *   of a statsd server.
9882     *
9883     * - ProfilerOutputDump: outputs dump files that are compatible
9884     *   with the XHProf gui. It expects that `$wgProfiler['outputDir']`
9885     *   is set as well.
9886     *
9887     * Examples:
9888     *
9889     * ```
9890     * $wgProfiler = [
9891     *   'class' => ProfilerXhprof::class,
9892     *   'output' => ProfilerOutputText::class,
9893     * ];
9894     * ```
9895     *
9896     * ```
9897     * $wgProfiler = [
9898     *   'class' => ProfilerXhprof::class,
9899     *   'output' => [ ProfilerOutputText::class ],
9900     *   'sampling' => 50, // one in every 50 requests
9901     * ];
9902     * ```
9903     *
9904     * For performance, the profiler is always disabled for CLI scripts as they
9905     * could be long running and the data would accumulate. Use the `--profiler`
9906     * parameter of maintenance scripts to override this.
9907     *
9908     * @since 1.17.0
9909     */
9910    public const Profiler = [
9911        'default' => [],
9912        'type' => 'map',
9913        'mergeStrategy' => 'replace',
9914    ];
9915
9916    /**
9917     * Destination of statsd metrics.
9918     *
9919     * A host or host:port of a statsd server. Port defaults to 8125.
9920     *
9921     * If not set, statsd metrics will not be collected.
9922     *
9923     * @see MediaWiki::emitBufferedStatsdData()
9924     * @since 1.25
9925     */
9926    public const StatsdServer = [
9927        'default' => false,
9928    ];
9929
9930    /**
9931     * Prefix for metric names sent to $wgStatsdServer.
9932     *
9933     * @see \MediaWiki\MediaWikiServices::getInstance()->getStatsdDataFactory
9934     * @see \Wikimedia\Stats\BufferingStatsdDataFactory
9935     * @since 1.25
9936     */
9937    public const StatsdMetricPrefix = [
9938        'default' => 'MediaWiki',
9939    ];
9940
9941    /**
9942     * Stats output target URI e.g. udp://127.0.0.1:8125
9943     *
9944     * If null, metrics will not be sent.
9945     * Note: this only affects metrics instantiated by the StatsFactory service
9946     *
9947     * @since 1.38
9948     */
9949    public const StatsTarget = [
9950        'default' => null,
9951        'type' => '?string',
9952    ];
9953
9954    /**
9955     * Stats output format
9956     *
9957     * If null, metrics will not be rendered nor sent.
9958     * Note: this only affects metrics instantiated by the StatsFactory service
9959     *
9960     * @see \Wikimedia\Stats\OutputFormats::SUPPORTED_FORMATS
9961     * @since 1.41
9962     */
9963    public const StatsFormat = [
9964        'default' => null,
9965        'type' => '?string',
9966    ];
9967
9968    /**
9969     * Stats service name prefix
9970     *
9971     * Required.  Must not be zero-length.
9972     * Defaults to: 'mediawiki'
9973     * Note: this only affects metrics instantiated by the StatsFactory service
9974     *
9975     * @since 1.41
9976     */
9977    public const StatsPrefix = [
9978        'default' => 'mediawiki',
9979        'type' => 'string',
9980    ];
9981
9982    /**
9983     * Configuration for OpenTelemetry instrumentation, or `null` to disable it.
9984     * Possible keys:
9985     * - `samplingProbability`: probability in % of sampling a trace for which no sampling decision has been
9986     * taken yet. Must be between 0 and 100.
9987     * - `serviceName`: name of the service being instrumented.
9988     * - `endpoint`: URL of the OpenTelemetry collector to send trace data to.
9989     * This has to be an endpoint accepting OTLP data over HTTP (not gRPC).
9990     *
9991     * An example config to send data to a local OpenTelemetry or Jaeger collector instance:
9992     * ```
9993     * $wgOpenTelemetryConfig = [
9994     *  'samplingProbability' => 0.1,
9995     *  'serviceName' => 'mediawiki-local',
9996     *  'endpoint' => 'http://127.0.0.1:4318/v1/traces',
9997     * ];
9998     * ```
9999     * @since 1.43
10000     */
10001    public const OpenTelemetryConfig = [
10002        'default' => null,
10003        'type' => 'map|null'
10004    ];
10005
10006    /**
10007     * InfoAction retrieves a list of transclusion links (both to and from).
10008     *
10009     * This number puts a limit on that query in the case of highly transcluded
10010     * templates.
10011     */
10012    public const PageInfoTransclusionLimit = [
10013        'default' => 50,
10014    ];
10015
10016    /**
10017     * Allow running of QUnit tests via [[Special:JavaScriptTest]].
10018     */
10019    public const EnableJavaScriptTest = [
10020        'default' => false,
10021    ];
10022
10023    /**
10024     * Overwrite the caching key prefix with custom value.
10025     *
10026     * @since 1.19
10027     */
10028    public const CachePrefix = [
10029        'default' => false,
10030    ];
10031
10032    /**
10033     * Display the new debugging toolbar. This also enables profiling on database
10034     * queries and other useful output.
10035     *
10036     * Will be ignored if $wgUseFileCache or $wgUseCdn is enabled.
10037     *
10038     * @since 1.19
10039     */
10040    public const DebugToolbar = [
10041        'default' => false,
10042    ];
10043
10044    // endregion -- end of profiling, testing and debugging
10045
10046    /***************************************************************************/
10047    // region   Search
10048    /** @name   Search */
10049
10050    /**
10051     * Set this to true to disable the full text search feature.
10052     */
10053    public const DisableTextSearch = [
10054        'default' => false,
10055    ];
10056
10057    /**
10058     * Set to true to have nicer highlighted text in search results,
10059     * by default off due to execution overhead
10060     */
10061    public const AdvancedSearchHighlighting = [
10062        'default' => false,
10063    ];
10064
10065    /**
10066     * Regexp to match word boundaries, defaults for non-CJK languages
10067     * should be empty for CJK since the words are not separate
10068     */
10069    public const SearchHighlightBoundaries = [
10070        'default' => '[\\p{Z}\\p{P}\\p{C}]',
10071    ];
10072
10073    /**
10074     * Templates for OpenSearch suggestions, defaults to API action=opensearch
10075     *
10076     * Sites with heavy load would typically have these point to a custom
10077     * PHP wrapper to avoid firing up mediawiki for every keystroke
10078     *
10079     * Placeholders: {searchTerms}
10080     */
10081    public const OpenSearchTemplates = [
10082        'default' => [
10083            'application/x-suggestions+json' => false,
10084            'application/x-suggestions+xml' => false,
10085        ],
10086        'type' => 'map',
10087    ];
10088
10089    /**
10090     * This was previously a used to force empty responses from ApiOpenSearch
10091     * with the 'suggest' parameter set.
10092     *
10093     * @deprecated since 1.35 No longer used
10094     */
10095    public const EnableOpenSearchSuggest = [
10096        'default' => true,
10097        'obsolete' => 'Since 1.35, no longer used',
10098        'description' => 'Has been emitting warnings since 1.39 (LTS). ' .
10099            'Can be removed completely in 1.44, assuming 1.43 is an LTS release.'
10100    ];
10101
10102    /**
10103     * Integer defining default number of entries to show on
10104     * OpenSearch call.
10105     */
10106    public const OpenSearchDefaultLimit = [
10107        'default' => 10,
10108    ];
10109
10110    /**
10111     * Minimum length of extract in <Description>. Actual extracts will last until the end of
10112     * sentence.
10113     */
10114    public const OpenSearchDescriptionLength = [
10115        'default' => 100,
10116    ];
10117
10118    /**
10119     * Expiry time for search suggestion responses
10120     */
10121    public const SearchSuggestCacheExpiry = [
10122        'default' => 1200,
10123    ];
10124
10125    /**
10126     * If you've disabled search semi-permanently, this also disables updates to the
10127     * table. If you ever re-enable, be sure to rebuild the search table.
10128     */
10129    public const DisableSearchUpdate = [
10130        'default' => false,
10131    ];
10132
10133    /**
10134     * List of namespaces which are searched by default.
10135     *
10136     * **Example:**
10137     *
10138     * ```
10139     * $wgNamespacesToBeSearchedDefault[NS_MAIN] = true;
10140     * $wgNamespacesToBeSearchedDefault[NS_PROJECT] = true;
10141     * ```
10142     */
10143    public const NamespacesToBeSearchedDefault = [
10144        'default' => [ NS_MAIN => true, ],
10145        'type' => 'map',
10146    ];
10147
10148    /**
10149     * Disable the internal MySQL-based search, to allow it to be
10150     * implemented by an extension instead.
10151     */
10152    public const DisableInternalSearch = [
10153        'default' => false,
10154    ];
10155
10156    /**
10157     * Set this to a URL to forward search requests to some external location.
10158     *
10159     * If the URL includes '$1', this will be replaced with the URL-encoded
10160     * search term. Before using this, $wgDisableTextSearch must be set to true.
10161     *
10162     * **Example:**
10163     * To forward to Google you'd have something like:
10164     *
10165     * ```
10166     * $wgSearchForwardUrl =
10167     * 'https://www.google.com/search?q=$1' .
10168     * '&domains=https://example.com' .
10169     * '&sitesearch=https://example.com' .
10170     * '&ie=utf-8&oe=utf-8';
10171     * ```
10172     */
10173    public const SearchForwardUrl = [
10174        'default' => null,
10175    ];
10176
10177    /**
10178     * Array of namespaces to generate a Google sitemap for when the
10179     * maintenance/generateSitemap.php script is run, or false if one is to be
10180     * generated for all namespaces.
10181     */
10182    public const SitemapNamespaces = [
10183        'default' => false,
10184        'type' => 'false|list',
10185    ];
10186
10187    /**
10188     * Custom namespace priorities for sitemaps. Setting this will allow you to
10189     * set custom priorities to namespaces when sitemaps are generated using the
10190     * maintenance/generateSitemap.php script.
10191     *
10192     * This should be a map of namespace IDs to priority
10193     *
10194     * **Example:**
10195     *
10196     * ```
10197     * $wgSitemapNamespacesPriorities = [
10198     *     NS_USER => '0.9',
10199     *     NS_HELP => '0.0',
10200     * ];
10201     * ```
10202     */
10203    public const SitemapNamespacesPriorities = [
10204        'default' => false,
10205        'type' => 'false|map',
10206    ];
10207
10208    /**
10209     * If true, searches for IP addresses will be redirected to that IP's
10210     * contributions page. E.g. searching for "1.2.3.4" will redirect to
10211     * [[Special:Contributions/1.2.3.4]]
10212     */
10213    public const EnableSearchContributorsByIP = [
10214        'default' => true,
10215    ];
10216
10217    /**
10218     * Options for Special:Search completion widget form created by SearchFormWidget class.
10219     *
10220     * Settings that can be used:
10221     * - showDescriptions: true/false - whether to show opensearch description results
10222     * - performSearchOnClick:  true/false - whether to perform search on click
10223     * See also TitleWidget.js UI widget.
10224     *
10225     * @since 1.34
10226     */
10227    public const SpecialSearchFormOptions = [
10228        'default' => [],
10229        'type' => 'map',
10230    ];
10231
10232    /**
10233     * Set true to allow logged-in users to set a preference whether or not matches in
10234     * search results should force redirection to that page. If false, the preference is
10235     * not exposed and cannot be altered from site default. To change your site's default
10236     * preference, set via $wgDefaultUserOptions['search-match-redirect'].
10237     *
10238     * @since 1.35
10239     */
10240    public const SearchMatchRedirectPreference = [
10241        'default' => false,
10242        'type' => 'boolean',
10243    ];
10244
10245    /**
10246     * Controls whether zero-result search queries with suggestions should display results for
10247     * these suggestions.
10248     *
10249     * @since 1.26
10250     */
10251    public const SearchRunSuggestedQuery = [
10252        'default' => true,
10253        'type' => 'boolean',
10254    ];
10255
10256    // endregion -- end of search settings
10257
10258    /***************************************************************************/
10259    // region   Edit user interface
10260    /** @name   Edit user interface */
10261
10262    /**
10263     * Path to the GNU diff3 utility. If the file doesn't exist, edit conflicts will
10264     * fall back to the old behavior (no merging).
10265     */
10266    public const Diff3 = [
10267        'default' => '/usr/bin/diff3',
10268    ];
10269
10270    /**
10271     * Path to the GNU diff utility.
10272     */
10273    public const Diff = [
10274        'default' => '/usr/bin/diff',
10275    ];
10276
10277    /**
10278     * Which namespaces have special treatment where they should be preview-on-open
10279     * Internally only Category: pages apply, but using this extensions (e.g. Semantic MediaWiki)
10280     * can specify namespaces of pages they have special treatment for
10281     */
10282    public const PreviewOnOpenNamespaces = [
10283        'default' => [
10284            NS_CATEGORY => true
10285        ],
10286        'type' => 'map',
10287    ];
10288
10289    /**
10290     * Enable the UniversalEditButton for browsers that support it
10291     * (currently only Firefox with an extension)
10292     * See http://universaleditbutton.org for more background information
10293     */
10294    public const UniversalEditButton = [
10295        'default' => true,
10296    ];
10297
10298    /**
10299     * If user doesn't specify any edit summary when making a an edit, MediaWiki
10300     * will try to automatically create one. This feature can be disabled by set-
10301     * ting this variable false.
10302     */
10303    public const UseAutomaticEditSummaries = [
10304        'default' => true,
10305    ];
10306
10307    // endregion -- end edit UI
10308
10309    /***************************************************************************/
10310    // region   Maintenance
10311    /** @name   Maintenance */
10312    // See also $wgSiteNotice
10313
10314    /**
10315     * For colorized maintenance script output, is your terminal background dark ?
10316     */
10317    public const CommandLineDarkBg = [
10318        'default' => false,
10319    ];
10320
10321    /**
10322     * Set this to a string to put the wiki into read-only mode. The text will be
10323     * used as an explanation to users.
10324     *
10325     * This prevents most write operations via the web interface. Cache updates may
10326     * still be possible. To prevent database writes completely, use the read_only
10327     * option in MySQL.
10328     */
10329    public const ReadOnly = [
10330        'default' => null,
10331    ];
10332
10333    /**
10334     * Set this to true to put the wiki watchlists into read-only mode.
10335     *
10336     * @since 1.31
10337     */
10338    public const ReadOnlyWatchedItemStore = [
10339        'default' => false,
10340        'type' => 'boolean',
10341    ];
10342
10343    /**
10344     * If this lock file exists (size > 0), the wiki will be forced into read-only mode.
10345     *
10346     * Its contents will be shown to users as part of the read-only warning
10347     * message.
10348     *
10349     * Will default to "{$wgUploadDirectory}/lock_yBgMBwiR" in Setup.php
10350     */
10351    public const ReadOnlyFile = [
10352        'default' => false,
10353        'dynamicDefault' => [ 'use' => [ 'UploadDirectory' ] ]
10354    ];
10355
10356    /**
10357     * @param mixed $uploadDirectory Value of UploadDirectory
10358     * @return string
10359     */
10360    public static function getDefaultReadOnlyFile( $uploadDirectory ): string {
10361        return "$uploadDirectory/lock_yBgMBwiR";
10362    }
10363
10364    /**
10365     * When you run the web-based upgrade utility, it will tell you what to set
10366     * this to in order to authorize the upgrade process. It will subsequently be
10367     * used as a password, to authorize further upgrades.
10368     *
10369     * For security, do not set this to a guessable string. Use the value supplied
10370     * by the install/upgrade process. To cause the upgrader to generate a new key,
10371     * delete the old key from LocalSettings.php.
10372     */
10373    public const UpgradeKey = [
10374        'default' => false,
10375    ];
10376
10377    /**
10378     * Fully specified path to git binary
10379     */
10380    public const GitBin = [
10381        'default' => '/usr/bin/git',
10382    ];
10383
10384    /**
10385     * Map GIT repository URLs to viewer URLs to provide links in Special:Version
10386     *
10387     * Key is a pattern passed to preg_match() and preg_replace(),
10388     * without the delimiters (which are #) and must match the whole URL.
10389     * The value is the replacement for the key (it can contain $1, etc.)
10390     * %h will be replaced by the short SHA-1 (7 first chars) and %H by the
10391     * full SHA-1 of the HEAD revision.
10392     * %r will be replaced with a URL-encoded version of $1.
10393     * %R will be replaced with $1 and no URL-encoding
10394     *
10395     * @since 1.20
10396     */
10397    public const GitRepositoryViewers = [
10398        'default' => [
10399            'https://(?:[a-z0-9_]+@)?gerrit.wikimedia.org/r/(?:p/)?(.*)' => 'https://gerrit.wikimedia.org/g/%R/+/%H',
10400            'ssh://(?:[a-z0-9_]+@)?gerrit.wikimedia.org:29418/(.*)' => 'https://gerrit.wikimedia.org/g/%R/+/%H',
10401        ],
10402        'type' => 'map',
10403    ];
10404
10405    // endregion -- End of maintenance
10406
10407    /***************************************************************************/
10408    // region   Recent changes, new pages, watchlist and history
10409    /** @name   Recent changes, new pages, watchlist and history */
10410
10411    /**
10412     * Recentchanges items are periodically purged; entries older than this many
10413     * seconds will go.
10414     *
10415     * Default: 90 days = about three months
10416     */
10417    public const RCMaxAge = [
10418        'default' => 90 * 24 * 3600,
10419    ];
10420
10421    /**
10422     * Page watchers inactive for more than this many seconds are considered inactive.
10423     *
10424     * Used mainly by action=info. Default: 180 days = about six months.
10425     *
10426     * @since 1.26
10427     */
10428    public const WatchersMaxAge = [
10429        'default' => 180 * 24 * 3600,
10430    ];
10431
10432    /**
10433     * If active watchers (per above) are this number or less, do not disclose it.
10434     *
10435     * Left to 1, prevents unprivileged users from knowing for sure that there are 0.
10436     * Set to -1 if you want to always complement watchers count with this info.
10437     *
10438     * @since 1.26
10439     */
10440    public const UnwatchedPageSecret = [
10441        'default' => 1,
10442    ];
10443
10444    /**
10445     * Filter $wgRCLinkDays by $wgRCMaxAge to avoid showing links for numbers
10446     * higher than what will be stored. Note that this is disabled by default
10447     * because we sometimes do have RC data which is beyond the limit for some
10448     * reason, and some users may use the high numbers to display that data which
10449     * is still there.
10450     */
10451    public const RCFilterByAge = [
10452        'default' => false,
10453    ];
10454
10455    /**
10456     * List of Limits options to list in the Special:Recentchanges and
10457     * Special:Recentchangeslinked pages.
10458     */
10459    public const RCLinkLimits = [
10460        'default' => [ 50, 100, 250, 500 ],
10461        'type' => 'list',
10462    ];
10463
10464    /**
10465     * List of Days options to list in the Special:Recentchanges and
10466     * Special:Recentchangeslinked pages.
10467     *
10468     * @see \MediaWiki\SpecialPage\ChangesListSpecialPage::getLinkDays
10469     */
10470    public const RCLinkDays = [
10471        'default' => [ 1, 3, 7, 14, 30 ],
10472        'type' => 'list',
10473    ];
10474
10475    /**
10476     * Configuration for feeds to which notifications about recent changes will be sent.
10477     *
10478     * The following feed classes are available by default:
10479     * - 'UDPRCFeedEngine' - sends recent changes over UDP to the specified server.
10480     * - 'RedisPubSubFeedEngine' - send recent changes to Redis.
10481     *
10482     * Only 'class' or 'uri' is required. If 'uri' is set instead of 'class', then
10483     * RecentChange::getEngine() is used to determine the class. All options are
10484     * passed to the constructor.
10485     *
10486     * Common options:
10487     * - 'class' -- The class to use for this feed (must implement RCFeed).
10488     * - 'omit_bots' -- Exclude bot edits from the feed. (default: false)
10489     * - 'omit_anon' -- Exclude anonymous edits from the feed. (default: false)
10490     * - 'omit_user' -- Exclude edits by registered users from the feed. (default: false)
10491     * - 'omit_minor' -- Exclude minor edits from the feed. (default: false)
10492     * - 'omit_patrolled' -- Exclude patrolled edits from the feed. (default: false)
10493     *
10494     * FormattedRCFeed-specific options:
10495     * - 'uri' -- [required] The address to which the messages are sent.
10496     *   The uri scheme of this string will be looked up in $wgRCEngines
10497     *   to determine which FormattedRCFeed class to use.
10498     * - 'formatter' -- [required] The class (implementing RCFeedFormatter) which will
10499     *   produce the text to send. This can also be an object of the class.
10500     *   Formatters available by default: JSONRCFeedFormatter, XMLRCFeedFormatter,
10501     *   IRCColourfulRCFeedFormatter.
10502     *
10503     * IRCColourfulRCFeedFormatter-specific options:
10504     * - 'add_interwiki_prefix' -- whether the titles should be prefixed with
10505     *   the first entry in the $wgLocalInterwikis array
10506     *
10507     * JSONRCFeedFormatter-specific options:
10508     * - 'channel' -- if set, the 'channel' parameter is also set in JSON values.
10509     *
10510     * **Examples:**
10511     *
10512     * ```
10513     * $wgRCFeeds['example'] = [
10514     *     'uri' => 'udp://localhost:1336',
10515     *     'formatter' => 'JSONRCFeedFormatter',
10516     *     'add_interwiki_prefix' => false,
10517     *     'omit_bots' => true,
10518     * ];
10519     * ```
10520     *
10521     * ```
10522     * $wgRCFeeds['example'] = [
10523     *     'uri' => 'udp://localhost:1338',
10524     *     'formatter' => 'IRCColourfulRCFeedFormatter',
10525     *     'add_interwiki_prefix' => false,
10526     *     'omit_bots' => true,
10527     * ];
10528     * ```
10529     *
10530     * ```
10531     * $wgRCFeeds['example'] = [
10532     *     'class' => ExampleRCFeed::class,
10533     * ];
10534     * ```
10535     *
10536     * @since 1.22
10537     */
10538    public const RCFeeds = [
10539        'default' => [],
10540        'type' => 'map',
10541    ];
10542
10543    /**
10544     * Used by RecentChange::getEngine to find the correct engine for a given URI scheme.
10545     *
10546     * Keys are scheme names, values are names of FormattedRCFeed sub classes.
10547     *
10548     * @since 1.22
10549     */
10550    public const RCEngines = [
10551        'default' => [
10552            'redis' => RedisPubSubFeedEngine::class,
10553            'udp' => UDPRCFeedEngine::class,
10554        ],
10555        'type' => 'map',
10556    ];
10557
10558    /**
10559     * Treat category membership changes as a RecentChange.
10560     *
10561     * Changes are mentioned in RC for page actions as follows:
10562     * - creation: pages created with categories are mentioned
10563     * - edit: category additions/removals to existing pages are mentioned
10564     * - move: nothing is mentioned (unless templates used depend on the title)
10565     * - deletion: nothing is mentioned
10566     * - undeletion: nothing is mentioned
10567     *
10568     * @since 1.27
10569     */
10570    public const RCWatchCategoryMembership = [
10571        'default' => false,
10572    ];
10573
10574    /**
10575     * Use RC Patrolling to check for vandalism (from recent changes and watchlists)
10576     * New pages and new files are included.
10577     *
10578     * @note If you disable all patrolling features, you probably also want to
10579     * remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
10580     * Special:Log.
10581     */
10582    public const UseRCPatrol = [
10583        'default' => true,
10584    ];
10585
10586    /**
10587     * Polling rate, in seconds, used by the 'live update' and 'view newest' features
10588     * of the RCFilters app on SpecialRecentChanges and Special:Watchlist.
10589     *
10590     * 0 to disable completely.
10591     */
10592    public const StructuredChangeFiltersLiveUpdatePollingRate = [
10593        'default' => 3,
10594    ];
10595
10596    /**
10597     * Use new page patrolling to check new pages on Special:Newpages
10598     *
10599     * @note If you disable all patrolling features, you probably also want to
10600     * remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
10601     * Special:Log.
10602     */
10603    public const UseNPPatrol = [
10604        'default' => true,
10605    ];
10606
10607    /**
10608     * Use file patrolling to check new files on Special:Newfiles
10609     *
10610     * @note If you disable all patrolling features, you probably also want to
10611     * remove 'patrol' from $wgFilterLogTypes so a show/hide link isn't shown on
10612     * Special:Log.
10613     * @since 1.27
10614     */
10615    public const UseFilePatrol = [
10616        'default' => true,
10617    ];
10618
10619    /**
10620     * Provide syndication feeds (RSS, Atom) for, e.g., Recentchanges, Newpages
10621     */
10622    public const Feed = [
10623        'default' => true,
10624    ];
10625
10626    /**
10627     * Set maximum number of results to return in syndication feeds (RSS, Atom) for
10628     * eg Recentchanges, Newpages.
10629     */
10630    public const FeedLimit = [
10631        'default' => 50,
10632    ];
10633
10634    /**
10635     * _Minimum_ timeout for cached Recentchanges feed, in seconds.
10636     *
10637     * A cached version will continue to be served out even if changes
10638     * are made, until this many seconds runs out since the last render.
10639     *
10640     * If set to 0, feed caching is disabled. Use this for debugging only;
10641     * feed generation can be pretty slow with diffs.
10642     */
10643    public const FeedCacheTimeout = [
10644        'default' => 60,
10645    ];
10646
10647    /**
10648     * When generating Recentchanges RSS/Atom feed, diffs will not be generated for
10649     * pages larger than this size.
10650     */
10651    public const FeedDiffCutoff = [
10652        'default' => 32768,
10653    ];
10654
10655    /**
10656     * Override the site's default RSS/ATOM feed for recentchanges that appears on
10657     * every page. Some sites might have a different feed they'd like to promote
10658     * instead of the RC feed (maybe like a "Recent New Articles" or "Breaking news" one).
10659     *
10660     * Should be a format as key (either 'rss' or 'atom') and an URL to the feed
10661     * as value.
10662     *
10663     * **Example:**
10664     * Configure the 'atom' feed to https://example.com/somefeed.xml
10665     *
10666     * ```
10667     * $wgSiteFeed['atom'] = "https://example.com/somefeed.xml";
10668     * ```
10669     */
10670    public const OverrideSiteFeed = [
10671        'default' => [],
10672        'type' => 'map',
10673    ];
10674
10675    /**
10676     * Available feeds objects.
10677     *
10678     * Should probably only be defined when a page is syndicated ie when
10679     * $wgOut->isSyndicated() is true.
10680     */
10681    public const FeedClasses = [
10682        'default' => [
10683            'rss' => \MediaWiki\Feed\RSSFeed::class,
10684            'atom' => \MediaWiki\Feed\AtomFeed::class,
10685        ],
10686        'type' => 'map',
10687    ];
10688
10689    /**
10690     * Which feed types should we provide by default?  This can include 'rss',
10691     * 'atom', neither, or both.
10692     */
10693    public const AdvertisedFeedTypes = [
10694        'default' => [ 'atom', ],
10695        'type' => 'list',
10696    ];
10697
10698    /**
10699     * Show watching users in recent changes, watchlist and page history views
10700     */
10701    public const RCShowWatchingUsers = [
10702        'default' => false,
10703    ];
10704
10705    /**
10706     * Show the amount of changed characters in recent changes
10707     */
10708    public const RCShowChangedSize = [
10709        'default' => true,
10710    ];
10711
10712    /**
10713     * If the difference between the character counts of the text
10714     * before and after the edit is below that value, the value will be
10715     * highlighted on the RC page.
10716     */
10717    public const RCChangedSizeThreshold = [
10718        'default' => 500,
10719    ];
10720
10721    /**
10722     * Show "Updated (since my last visit)" marker in RC view, watchlist and history
10723     * view for watched pages with new changes
10724     */
10725    public const ShowUpdatedMarker = [
10726        'default' => true,
10727    ];
10728
10729    /**
10730     * Disable links to talk pages of anonymous users (IPs) in listings on special
10731     * pages like page history, Special:Recentchanges, etc.
10732     */
10733    public const DisableAnonTalk = [
10734        'default' => false,
10735    ];
10736
10737    /**
10738     * Allow filtering by change tag in recentchanges, history, etc
10739     * Has no effect if no tags are defined.
10740     */
10741    public const UseTagFilter = [
10742        'default' => true,
10743    ];
10744
10745    /**
10746     * List of core tags to enable.
10747     *
10748     * @since 1.31
10749     * @since 1.36 Added 'mw-manual-revert' and 'mw-reverted'
10750     * @see \ChangeTags::TAG_CONTENT_MODEL_CHANGE
10751     * @see \ChangeTags::TAG_NEW_REDIRECT
10752     * @see \ChangeTags::TAG_REMOVED_REDIRECT
10753     * @see \ChangeTags::TAG_CHANGED_REDIRECT_TARGET
10754     * @see \ChangeTags::TAG_BLANK
10755     * @see \ChangeTags::TAG_REPLACE
10756     * @see \ChangeTags::TAG_ROLLBACK
10757     * @see \ChangeTags::TAG_UNDO
10758     * @see \ChangeTags::TAG_MANUAL_REVERT
10759     * @see \ChangeTags::TAG_REVERTED
10760     * @see \ChangeTags::TAG_SERVER_SIDE_UPLOAD
10761     */
10762    public const SoftwareTags = [
10763        'default' => [
10764            'mw-contentmodelchange' => true,
10765            'mw-new-redirect' => true,
10766            'mw-removed-redirect' => true,
10767            'mw-changed-redirect-target' => true,
10768            'mw-blank' => true,
10769            'mw-replace' => true,
10770            'mw-rollback' => true,
10771            'mw-undo' => true,
10772            'mw-manual-revert' => true,
10773            'mw-reverted' => true,
10774            'mw-server-side-upload' => true,
10775        ],
10776        'type' => 'map',
10777        'additionalProperties' => [ 'type' => 'boolean', ],
10778    ];
10779
10780    /**
10781     * If set to an integer, pages that are watched by this many users or more
10782     * will not require the unwatchedpages permission to view the number of
10783     * watchers.
10784     *
10785     * @since 1.21
10786     */
10787    public const UnwatchedPageThreshold = [
10788        'default' => false,
10789    ];
10790
10791    /**
10792     * Flags (letter symbols) shown in recent changes and watchlist to indicate
10793     * certain types of edits.
10794     *
10795     * To register a new one:
10796     *
10797     * ```
10798     * $wgRecentChangesFlags['flag'] => [
10799     *   // message for the letter displayed next to rows on changes lists
10800     *   'letter' => 'letter-msg',
10801     *   // message for the tooltip of the letter
10802     *   'title' => 'tooltip-msg',
10803     *   // optional (defaults to 'tooltip-msg'), message to use in the legend box
10804     *   'legend' => 'legend-msg',
10805     *   // optional (defaults to 'flag'), CSS class to put on changes lists rows
10806     *   'class' => 'css-class',
10807     *   // optional (defaults to 'any'), how top-level flag is determined.  'any'
10808     *   // will set the top-level flag if any line contains the flag, 'all' will
10809     *   // only be set if all lines contain the flag.
10810     *   'grouping' => 'any',
10811     * ];
10812     * ```
10813     *
10814     * @since 1.22
10815     */
10816    public const RecentChangesFlags = [
10817        'default' => [
10818            'newpage' => [
10819                'letter' => 'newpageletter',
10820                'title' => 'recentchanges-label-newpage',
10821                'legend' => 'recentchanges-legend-newpage',
10822                'grouping' => 'any',
10823            ],
10824            'minor' => [
10825                'letter' => 'minoreditletter',
10826                'title' => 'recentchanges-label-minor',
10827                'legend' => 'recentchanges-legend-minor',
10828                'class' => 'minoredit',
10829                'grouping' => 'all',
10830            ],
10831            'bot' => [
10832                'letter' => 'boteditletter',
10833                'title' => 'recentchanges-label-bot',
10834                'legend' => 'recentchanges-legend-bot',
10835                'class' => 'botedit',
10836                'grouping' => 'all',
10837            ],
10838            'unpatrolled' => [
10839                'letter' => 'unpatrolledletter',
10840                'title' => 'recentchanges-label-unpatrolled',
10841                'legend' => 'recentchanges-legend-unpatrolled',
10842                'grouping' => 'any',
10843            ],
10844        ],
10845        'type' => 'map',
10846    ];
10847
10848    /**
10849     * Whether to enable the watchlist expiry feature.
10850     *
10851     * @since 1.35
10852     */
10853    public const WatchlistExpiry = [
10854        'default' => false,
10855        'type' => 'boolean',
10856    ];
10857
10858    /**
10859     * Chance of expired watchlist items being purged on any page edit.
10860     *
10861     * Only has effect if $wgWatchlistExpiry is true.
10862     *
10863     * If this is zero, expired watchlist items will not be removed
10864     * and the purgeExpiredWatchlistItems.php maintenance script should be run periodically.
10865     *
10866     * @since 1.35
10867     */
10868    public const WatchlistPurgeRate = [
10869        'default' => 0.1,
10870        'type' => 'float',
10871    ];
10872
10873    /**
10874     * Relative maximum duration for watchlist expiries, as accepted by strtotime().
10875     *
10876     * This relates to finite watchlist expiries only. Pages can be watched indefinitely
10877     * regardless of what this is set to.
10878     *
10879     * This is used to ensure the watchlist_expiry table doesn't grow to be too big.
10880     *
10881     * Only has effect if $wgWatchlistExpiry is true.
10882     *
10883     * Set to null to allow expiries of any duration.
10884     *
10885     * @since 1.35
10886     */
10887    public const WatchlistExpiryMaxDuration = [
10888        'default' => '1 year',
10889        'type' => '?string',
10890    ];
10891
10892    // endregion -- end RC/watchlist
10893
10894    /***************************************************************************/
10895    // region   Copyright and credits settings
10896    /** @name   Copyright and credits settings */
10897
10898    /**
10899     * Override for copyright metadata.
10900     *
10901     * This is the name of the page containing information about the wiki's copyright status,
10902     * which will be added as a link in the footer if it is specified. It overrides
10903     * $wgRightsUrl if both are specified.
10904     */
10905    public const RightsPage = [
10906        'default' => null,
10907    ];
10908
10909    /**
10910     * Set this to specify an external URL containing details about the content license used on your
10911     * wiki.
10912     *
10913     * If $wgRightsPage is set then this setting is ignored.
10914     */
10915    public const RightsUrl = [
10916        'default' => null,
10917    ];
10918
10919    /**
10920     * If either $wgRightsUrl or $wgRightsPage is specified then this variable gives the text for
10921     * the link. Otherwise, it will be treated as raw HTML.
10922     *
10923     * If using $wgRightsUrl then this value must be specified. If using $wgRightsPage then the
10924     * name
10925     * of the page will also be used as the link text if this variable is not set.
10926     */
10927    public const RightsText = [
10928        'default' => null,
10929    ];
10930
10931    /**
10932     * Override for copyright metadata.
10933     */
10934    public const RightsIcon = [
10935        'default' => null,
10936    ];
10937
10938    /**
10939     * Set this to true if you want detailed copyright information forms on Upload.
10940     */
10941    public const UseCopyrightUpload = [
10942        'default' => false,
10943    ];
10944
10945    /**
10946     * Set this to the number of authors that you want to be credited below an
10947     * article text. Set it to zero to hide the attribution block, and a negative
10948     * number (like -1) to show all authors. Note that this will require 2-3 extra
10949     * database hits, which can have a not insignificant impact on performance for
10950     * large wikis.
10951     */
10952    public const MaxCredits = [
10953        'default' => 0,
10954    ];
10955
10956    /**
10957     * If there are more than $wgMaxCredits authors, show $wgMaxCredits of them.
10958     *
10959     * Otherwise, link to a separate credits page.
10960     */
10961    public const ShowCreditsIfMax = [
10962        'default' => true,
10963    ];
10964
10965    // endregion -- end of copyright and credits settings
10966
10967    /***************************************************************************/
10968    // region   Import / Export
10969    /** @name   Import / Export */
10970
10971    /**
10972     * List of interwiki prefixes for wikis we'll accept as sources for
10973     * Special:Import and API action=import. Since complete page history can be
10974     * imported, these should be 'trusted'.
10975     *
10976     * This can either be a regular array, or an associative map specifying
10977     * subprojects on the interwiki map of the target wiki, or a mix of the two,
10978     * e.g.
10979     *
10980     * ```
10981     * $wgImportSources = [
10982     *     'wikipedia' => [ 'cs', 'en', 'fr', 'zh' ],
10983     *     'wikispecies',
10984     *     'wikia' => [ 'animanga', 'brickipedia', 'desserts' ],
10985     * ];
10986     * ```
10987     *
10988     * If you have a very complex import sources setup, you can lazy-load it using
10989     * the ImportSources hook.
10990     *
10991     * If a user has the 'import' permission but not the 'importupload' permission,
10992     * they will only be able to run imports through this transwiki interface.
10993     */
10994    public const ImportSources = [
10995        'default' => [],
10996        'type' => 'map',
10997    ];
10998
10999    /**
11000     * Optional default target namespace for interwiki imports.
11001     *
11002     * Can use this to create an incoming "transwiki"-style queue.
11003     * Set to numeric key, not the name.
11004     *
11005     * Users may override this in the Special:Import dialog.
11006     */
11007    public const ImportTargetNamespace = [
11008        'default' => null,
11009    ];
11010
11011    /**
11012     * If set to false, disables the full-history option on Special:Export.
11013     *
11014     * This is currently poorly optimized for long edit histories, so is
11015     * disabled on Wikimedia's sites.
11016     */
11017    public const ExportAllowHistory = [
11018        'default' => true,
11019    ];
11020
11021    /**
11022     * If set nonzero, Special:Export requests for history of pages with
11023     * more revisions than this will be rejected. On some big sites things
11024     * could get bogged down by very very long pages.
11025     */
11026    public const ExportMaxHistory = [
11027        'default' => 0,
11028    ];
11029
11030    /**
11031     * Return distinct author list (when not returning full history)
11032     */
11033    public const ExportAllowListContributors = [
11034        'default' => false,
11035    ];
11036
11037    /**
11038     * If non-zero, Special:Export accepts a "pagelink-depth" parameter
11039     * up to this specified level, which will cause it to include all
11040     * pages linked to from the pages you specify. Since this number
11041     * can become *really really large* and could easily break your wiki,
11042     * it's disabled by default for now.
11043     *
11044     * @warning There's a HARD CODED limit of 5 levels of recursion to prevent a
11045     * crazy-big export from being done by someone setting the depth number too
11046     * high. In other words, last resort safety net.
11047     */
11048    public const ExportMaxLinkDepth = [
11049        'default' => 0,
11050    ];
11051
11052    /**
11053     * Whether to allow the "export all pages in namespace" option
11054     */
11055    public const ExportFromNamespaces = [
11056        'default' => false,
11057    ];
11058
11059    /**
11060     * Whether to allow exporting the entire wiki into a single file
11061     */
11062    public const ExportAllowAll = [
11063        'default' => false,
11064    ];
11065
11066    /**
11067     * Maximum number of pages returned by the GetPagesFromCategory and
11068     * GetPagesFromNamespace functions.
11069     *
11070     * @since 1.27
11071     */
11072    public const ExportPagelistLimit = [
11073        'default' => 5000,
11074    ];
11075
11076    /**
11077     * The schema to use by default when generating XML dumps. This allows sites to control
11078     * explicitly when to make breaking changes to their export and dump format.
11079     */
11080    public const XmlDumpSchemaVersion = [
11081        'default' => XML_DUMP_SCHEMA_VERSION_11,
11082    ];
11083
11084    // endregion -- end of import/export
11085
11086    /***************************************************************************/
11087    // region   Wiki Farm
11088    /** @name   Wiki Farm */
11089
11090    /**
11091     * A directory that contains site-specific configuration files.
11092     *
11093     * Setting this will enable multi-tenant ("wiki farm") mode, causing
11094     * site-specific settings to be loaded based on information from the web request.
11095     *
11096     * @unstable EXPERIMENTAL
11097     * @since 1.38
11098     */
11099    public const WikiFarmSettingsDirectory = [
11100        'default' => null
11101    ];
11102
11103    /**
11104     * The file extension to be used when looking up site-specific settings files in
11105     * $wgWikiFarmSettingsDirectory, such as 'json' or 'yaml'.
11106     *
11107     * @unstable EXPERIMENTAL
11108     * @since 1.38
11109     */
11110    public const WikiFarmSettingsExtension = [
11111        'default' => 'yaml'
11112    ];
11113
11114    // endregion -- End Wiki Farm
11115
11116    /***************************************************************************/
11117    // region   Extensions
11118    /** @name   Extensions */
11119
11120    /**
11121     * A list of callback functions which are called once MediaWiki is fully
11122     * initialised
11123     */
11124    public const ExtensionFunctions = [
11125        'default' => [],
11126        'type' => 'list',
11127    ];
11128
11129    /**
11130     * Extension messages files.
11131     *
11132     * Associative array mapping extension name to the filename where messages can be
11133     * found. The file should contain variable assignments. Any of the variables
11134     * present in languages/messages/MessagesEn.php may be defined, but $messages
11135     * is the most common.
11136     *
11137     * Variables defined in extensions will override conflicting variables defined
11138     * in the core.
11139     *
11140     * Since MediaWiki 1.23, use of this variable to define messages is discouraged; instead, store
11141     * messages in JSON format and use $wgMessagesDirs. For setting other variables than
11142     * $messages, $wgExtensionMessagesFiles should still be used. Use a DIFFERENT key because
11143     * any entry having a key that also exists in $wgMessagesDirs will be ignored.
11144     *
11145     * Extensions using the JSON message format can preserve backward compatibility with
11146     * earlier versions of MediaWiki by using a compatibility shim, such as one generated
11147     * by the generateJsonI18n.php maintenance script, listing it under the SAME key
11148     * as for the $wgMessagesDirs entry.
11149     *
11150     * **Example:**
11151     *
11152     * ```
11153     * $wgExtensionMessagesFiles['ConfirmEdit'] = __DIR__.'/ConfirmEdit.i18n.php';
11154     * ```
11155     */
11156    public const ExtensionMessagesFiles = [
11157        'default' => [],
11158        'type' => 'map',
11159    ];
11160
11161    /**
11162     * Extension messages directories.
11163     *
11164     * Associative array mapping extension name to the path of the directory where message files can
11165     * be found. The message files are expected to be JSON files named for their language code, e.g.
11166     * en.json, de.json, etc. Extensions with messages in multiple places may specify an array of
11167     * message directories.
11168     *
11169     * Message directories in core should be added to LocalisationCache::getMessagesDirs()
11170     *
11171     * **Simple example:**
11172     *
11173     * ```
11174     * $wgMessagesDirs['Example'] = __DIR__ . '/i18n';
11175     * ```
11176     *
11177     * **Complex example:**
11178     *
11179     * ```
11180     * $wgMessagesDirs['Example'] = [
11181     *     __DIR__ . '/lib/ve/i18n',
11182     *     __DIR__ . '/lib/ooui/i18n',
11183     *     __DIR__ . '/i18n',
11184     * ]
11185     * ```
11186     *
11187     * @since 1.23
11188     */
11189    public const MessagesDirs = [
11190        'default' => [],
11191        'type' => 'map',
11192    ];
11193
11194    /**
11195     * Message directories containing JSON files for localisation of special page aliases.
11196     *
11197     * Associative array mapping extension name to the directory where configurations can be
11198     * found. The directory is expected to contain JSON files corresponding to each language code.
11199     *
11200     * Variables defined in extensions will override conflicting variables defined
11201     * in the core. We recommend using this configuration to set variables that require localisation:
11202     * special page aliases, and in the future namespace aliases and magic words.
11203     *
11204     * **Simple example**: extension.json
11205     * ```
11206     * "TranslationAliasesDirs": {
11207     *   "TranslationNotificationsAlias": "i18n/aliases"
11208     * }
11209     * ```
11210     * **Complex example**: extension.json
11211     *  ```
11212     *  "TranslationAliasesDirs": {
11213     *    "TranslationNotificationsAlias": [ "i18n/special-page-aliases", "i18n/magic-words", "i18n/namespaces" ]
11214     *  }
11215     *  ```
11216     *
11217     * @unstable EXPERIMENTAL
11218     * @since 1.42
11219     */
11220    public const TranslationAliasesDirs = [
11221        'default' => [],
11222        'type' => 'map',
11223    ];
11224
11225    /**
11226     * Array of files with list(s) of extension entry points to be used in
11227     * maintenance/mergeMessageFileList.php
11228     *
11229     * @since 1.22
11230     */
11231    public const ExtensionEntryPointListFiles = [
11232        'default' => [],
11233        'type' => 'map',
11234    ];
11235
11236    /**
11237     * Whether to include the NewPP limit report as a HTML comment
11238     */
11239    public const EnableParserLimitReporting = [
11240        'default' => true,
11241    ];
11242
11243    /**
11244     * List of valid skin names
11245     *
11246     * The key should be the name in all lower case.
11247     *
11248     * As of 1.35, the value should be a an array in the form of the ObjectFactory specification.
11249     *
11250     * For example for 'foobarskin' where the PHP class is 'MediaWiki\Skins\FooBar\FooBarSkin' set:
11251     *
11252     * **skin.json Example:**
11253     *
11254     * ```
11255     * "ValidSkinNames": {
11256     *    "foobarskin": {
11257     *        "displayname": "FooBarSkin",
11258     *        "class": "MediaWiki\\Skins\\FooBar\\FooBarSkin"
11259     *    }
11260     * }
11261     * ```
11262     *
11263     * Historically, the value was a properly cased name for the skin (and is still currently
11264     * supported). This value will be prefixed with "Skin" to create the class name of the
11265     * skin to load. Use Skin::getSkinNames() as an accessor if you wish to have access to the
11266     * full list.
11267     */
11268    public const ValidSkinNames = [
11269        'default' => [],
11270        'type' => 'map',
11271    ];
11272
11273    /**
11274     * Special page list. This is an associative array mapping the (canonical) names of
11275     * special pages to either a class name or a ObjectFactory spec to be instantiated, or a callback to use for
11276     * creating the special page object. In all cases, the result must be an instance of SpecialPage.
11277     */
11278    public const SpecialPages = [
11279        'default' => [],
11280        'type' => 'map',
11281    ];
11282
11283    /**
11284     * Obsolete switch that controlled legacy case-insensitive classloading.
11285     *
11286     * Case-insensitive classloading was needed for loading data that had
11287     * been serialized by PHP 4 with the class names converted to lowercase.
11288     * It is no longer necessary since 1.31; the lowercase forms in question
11289     * are now listed in autoload.php (T166759).
11290     *
11291     * @deprecated since 1.35
11292     */
11293    public const AutoloadAttemptLowercase = [
11294        'default' => false,
11295        'obsolete' => 'Since 1.40; no longer has any effect.',
11296        'description' => 'Has been emitting warnings since 1.39 (LTS). ' .
11297            'Can be removed completely in 1.44, assuming 1.43 is an LTS release.'
11298    ];
11299
11300    /**
11301     * Add information about an installed extension, keyed by its type.
11302     *
11303     * This is for use from LocalSettings.php and legacy PHP-entrypoint
11304     * extensions. In general, extensions should (only) declare this
11305     * information in their extension.json file.
11306     *
11307     * The 'name', 'path' and 'author' keys are required.
11308     *
11309     * ```
11310     * $wgExtensionCredits['other'][] = [
11311     *     'path' => __FILE__,
11312     *     'name' => 'Example extension',
11313     *     'namemsg' => 'exampleextension-name',
11314     *     'author' => [
11315     *         'Foo Barstein',
11316     *     ],
11317     *     'version' => '0.0.1',
11318     *     'url' => 'https://example.org/example-extension/',
11319     *     'descriptionmsg' => 'exampleextension-desc',
11320     *     'license-name' => 'GPL-2.0-or-later',
11321     * ];
11322     * ```
11323     *
11324     * The extensions are listed on Special:Version. This page also looks for a file
11325     * named COPYING or LICENSE (optional .txt extension) and provides a link to
11326     * view said file. When the 'license-name' key is specified, this file is
11327     * interpreted as wikitext.
11328     *
11329     * - $type: One of 'specialpage', 'parserhook', 'variable', 'media', 'antispam',
11330     *    'skin', 'api', or 'other', or any additional types as specified through the
11331     *    ExtensionTypes hook as used in SpecialVersion::getExtensionTypes().
11332     *
11333     * - name: Name of extension as an inline string instead of localizable message.
11334     *    Do not omit this even if 'namemsg' is provided, as it is used to override
11335     *    the path Special:Version uses to find extension's license info, and is
11336     *    required for backwards-compatibility with MediaWiki 1.23 and older.
11337     *
11338     * - namemsg (since MW 1.24): A message key for a message containing the
11339     *    extension's name, if the name is localizable. (For example, skin names
11340     *    usually are.)
11341     *
11342     * - author: A string or an array of strings. Authors can be linked using
11343     *    the regular wikitext link syntax. To have an internationalized version of
11344     *    "and others" show, add an element "...". This element can also be linked,
11345     *    for instance "[https://example ...]".
11346     *
11347     * - descriptionmsg: A message key or an array with message key and parameters:
11348     *    `'descriptionmsg' => 'exampleextension-desc',`
11349     *
11350     * - description: Description of extension as an inline string instead of
11351     *    localizable message (omit in favour of 'descriptionmsg').
11352     *
11353     * - license-name: Short name of the license (used as label for the link), such
11354     *   as "GPL-2.0-or-later" or "MIT" (https://spdx.org/licenses/ for a list of identifiers).
11355     *
11356     * @see \MediaWiki\Specials\SpecialVersion::getCredits
11357     */
11358    public const ExtensionCredits = [
11359        'default' => [],
11360        'type' => 'map',
11361    ];
11362
11363    /**
11364     * Global list of hooks.
11365     *
11366     * The key is one of the events made available by MediaWiki, you can find
11367     * a description for most of them in their respective hook interfaces. For
11368     * overview of the hook system see docs/Hooks.md. The array is used internally
11369     * by HookContainer::run().
11370     *
11371     * The value can be one of:
11372     *
11373     * - A function name: `$wgHooks['event_name'][] = $function;`
11374     *
11375     * - A function with some data: `$wgHooks['event_name'][] = [ $function, $data ];`
11376     *
11377     *
11378     * - A an object method: `$wgHooks['event_name'][] = [ $object, 'method' ];`
11379     *
11380     * - A closure:
11381     * ```
11382     * $wgHooks['event_name'][] = function ( $hookParam ) {
11383     *     // Handler code goes here.
11384     * };
11385     * ```
11386     *
11387     * @warning You should always append to an event array or you will end up
11388     * deleting a previous registered hook.
11389     * @warning Hook handlers should be registered at file scope. Registering
11390     * handlers after file scope can lead to unexpected results due to caching.
11391     */
11392    public const Hooks = [
11393        'default' => [],
11394        'type' => 'map',
11395        'mergeStrategy' => 'array_merge_recursive',
11396    ];
11397
11398    /**
11399     * List of service wiring files to be loaded by the default instance of MediaWikiServices. Each
11400     * file listed here is expected to return an associative array mapping service names to
11401     * instantiator functions. Extensions may add wiring files to define their own services.
11402     * However, this cannot be used to replace existing services - use the MediaWikiServices hook
11403     * for that.
11404     *
11405     * @note the default wiring file will be added automatically by Setup.php
11406     * @see \MediaWiki\MediaWikiServices
11407     * @see \Wikimedia\Services\ServiceContainer::loadWiringFiles() for details on loading
11408     *   service instantiator functions.
11409     * @see docs/Injection.md for an overview of dependency
11410     *   injection in MediaWiki.
11411     */
11412    public const ServiceWiringFiles = [
11413        'default' => [],
11414        'type' => 'list',
11415    ];
11416
11417    /**
11418     * Maps jobs to their handlers; extensions
11419     * can add to this to provide custom jobs.
11420     *
11421     * Since 1.40, job handlers can be specified as object specs
11422     * for use with ObjectFactory, using an array, a plain class name,
11423     * or a callback.
11424     *
11425     * @note The constructor signature of job classes has to follow one of two patterns:
11426     * Either it takes a parameter array as the first argument, followed by any services it
11427     * needs to have injected: ( array $params, ... ).
11428     * Or it takes a PageReference as the first parameter, followed by the parameter array,
11429     * followed by any services: ( PageReference $page, array $params, ... ).
11430     * In order to signal to the JobFactory that the $page parameter should be omitted from
11431     * the constructor arguments, the job class has to be a subclass of GenericParameterJob,
11432     * or the object specification for the job has to set the 'needsPage' key to false.
11433     * If a callback is used, its signature follows the same rules.
11434     */
11435    public const JobClasses = [
11436        'default' => [
11437            'deletePage' => DeletePageJob::class,
11438            'refreshLinks' => RefreshLinksJob::class,
11439            'deleteLinks' => DeleteLinksJob::class,
11440            'htmlCacheUpdate' => HTMLCacheUpdateJob::class,
11441            'sendMail' => [
11442                'class' => EmaillingJob::class,
11443                'services' => [
11444                    0 => 'Emailer'
11445                ]
11446            ],
11447            'enotifNotify' => EnotifNotifyJob::class,
11448            'fixDoubleRedirect' => [
11449                'class' => DoubleRedirectJob::class,
11450                'services' => [
11451                    'RevisionLookup',
11452                    'MagicWordFactory',
11453                    'WikiPageFactory',
11454                ],
11455                // This job requires a title
11456                'needsPage' => true,
11457            ],
11458            'AssembleUploadChunks' => AssembleUploadChunksJob::class,
11459            'PublishStashedFile' => PublishStashedFileJob::class,
11460            'ThumbnailRender' => ThumbnailRenderJob::class,
11461            'UploadFromUrl' => UploadFromUrlJob::class,
11462            'recentChangesUpdate' => RecentChangesUpdateJob::class,
11463            'refreshLinksPrioritized' => RefreshLinksJob::class,
11464            'refreshLinksDynamic' => RefreshLinksJob::class,
11465            'activityUpdateJob' => ActivityUpdateJob::class,
11466            'categoryMembershipChange' => CategoryMembershipChangeJob::class,
11467            'clearUserWatchlist' => ClearUserWatchlistJob::class,
11468            'watchlistExpiry' => WatchlistExpiryJob::class,
11469            'cdnPurge' => CdnPurgeJob::class,
11470            'userGroupExpiry' => UserGroupExpiryJob::class,
11471            'clearWatchlistNotifications' => ClearWatchlistNotificationsJob::class,
11472            'userOptionsUpdate' => UserOptionsUpdateJob::class,
11473            'revertedTagUpdate' => RevertedTagUpdateJob::class,
11474            'null' => NullJob::class,
11475            'userEditCountInit' => UserEditCountInitJob::class,
11476            'parsoidCachePrewarm' => [
11477                'class' => ParsoidCachePrewarmJob::class,
11478                'services' => [
11479                    'ParserOutputAccess',
11480                    'PageStore',
11481                    'RevisionLookup',
11482                    'ParsoidSiteConfig',
11483                ],
11484                // tell the JobFactory not to include the $page parameter in the constructor call
11485                'needsPage' => false
11486            ],
11487            'renameUser' => [
11488                'class' => RenameUserJob::class,
11489                'services' => [
11490                    'MainConfig',
11491                    'DBLoadBalancerFactory'
11492                ]
11493            ],
11494        ],
11495        'type' => 'map',
11496    ];
11497
11498    /**
11499     * Jobs that must be explicitly requested, i.e. aren't run by job runners unless
11500     * special flags are set. The values here are keys of $wgJobClasses.
11501     *
11502     * These can be:
11503     * - Very long-running jobs.
11504     * - Jobs that you would never want to run as part of a page rendering request.
11505     * - Jobs that you want to run on specialized machines ( like transcoding, or a particular
11506     *   machine on your cluster has 'outside' web access you could restrict uploadFromUrl )
11507     * These settings should be global to all wikis.
11508     */
11509    public const JobTypesExcludedFromDefaultQueue = [
11510        'default' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl' ],
11511        'type' => 'list',
11512    ];
11513
11514    /**
11515     * Map of job types to how many job "work items" should be run per second
11516     * on each job runner process. The meaning of "work items" varies per job,
11517     * but typically would be something like "pages to update". A single job
11518     * may have a variable number of work items, as is the case with batch jobs.
11519     *
11520     * This is used by runJobs.php and not jobs run via $wgJobRunRate.
11521     * These settings should be global to all wikis.
11522     */
11523    public const JobBackoffThrottling = [
11524        'default' => [],
11525        'type' => 'map',
11526        'additionalProperties' => [ 'type' => 'float', ],
11527    ];
11528
11529    /**
11530     * Map of job types to configuration arrays.
11531     *
11532     * This determines which queue class and storage system is used for each job type.
11533     * Job types that do not have explicit configuration will use the 'default' config.
11534     * These settings should be global to all wikis.
11535     */
11536    public const JobTypeConf = [
11537        'default' => [
11538            'default' => [
11539                'class' => JobQueueDB::class,
11540                'order' => 'random',
11541                'claimTTL' => 3600
11542            ],
11543        ],
11544        'additionalProperties' => [
11545            'type' => 'object',
11546            'properties' => [
11547                'class' => [ 'type' => 'string' ],
11548                'order' => [ 'type' => 'string' ],
11549                'claimTTL' => [ 'type' => 'int' ]
11550            ],
11551        ],
11552        'type' => 'map',
11553    ];
11554
11555    /**
11556     * Whether to include the number of jobs that are queued
11557     * for the API's maxlag parameter.
11558     *
11559     * The total number of jobs will be divided by this to get an
11560     * estimated second of maxlag. Typically bots backoff at maxlag=5,
11561     * so setting this to the max number of jobs that should be in your
11562     * queue divided by 5 should have the effect of stopping bots once
11563     * that limit is hit.
11564     *
11565     * @since 1.29
11566     */
11567    public const JobQueueIncludeInMaxLagFactor = [
11568        'default' => false,
11569    ];
11570
11571    /**
11572     * Additional functions to be performed with updateSpecialPages.
11573     *
11574     * Expensive Querypages are already updated.
11575     */
11576    public const SpecialPageCacheUpdates = [
11577        'default' => [
11578            'Statistics' => [ SiteStatsUpdate::class, 'cacheUpdate' ]
11579        ],
11580        'type' => 'map',
11581    ];
11582
11583    /**
11584     * Page property link table invalidation lists. When a page property
11585     * changes, this may require other link tables to be updated (eg
11586     * adding __HIDDENCAT__ means the hiddencat tracking category will
11587     * have been added, so the categorylinks table needs to be rebuilt).
11588     *
11589     * This array can be added to by extensions.
11590     */
11591    public const PagePropLinkInvalidations = [
11592        'default' => [ 'hiddencat' => 'categorylinks', ],
11593        'type' => 'map',
11594    ];
11595
11596    // endregion -- End extensions
11597
11598    /***************************************************************************/
11599    // region   Categories
11600    /** @name   Categories */
11601
11602    /**
11603     * On category pages, show thumbnail gallery for images belonging to that
11604     * category instead of listing them as articles.
11605     */
11606    public const CategoryMagicGallery = [
11607        'default' => true,
11608    ];
11609
11610    /**
11611     * Paging limit for categories
11612     */
11613    public const CategoryPagingLimit = [
11614        'default' => 200,
11615    ];
11616
11617    /**
11618     * Specify how category names should be sorted, when listed on a category page.
11619     *
11620     * A sorting scheme is also known as a collation.
11621     *
11622     * Available values are:
11623     *
11624     *   - uppercase: Converts the category name to upper case, and sorts by that.
11625     *
11626     *   - identity: Does no conversion. Sorts by binary value of the string.
11627     *
11628     *   - uca-default: Provides access to the Unicode Collation Algorithm with
11629     *     the default element table. This is a compromise collation which sorts
11630     *     all languages in a mediocre way. However, it is better than "uppercase".
11631     *
11632     * To use the uca-default collation, you must have PHP's intl extension
11633     * installed. See https://www.php.net/manual/en/intl.setup.php . The details of the
11634     * resulting collation will depend on the version of ICU installed on the
11635     * server.
11636     *
11637     * After you change this, you must run maintenance/updateCollation.php to fix
11638     * the sort keys in the database.
11639     *
11640     * Extensions can define there own collations by subclassing Collation
11641     * and using the Collation::factory hook.
11642     */
11643    public const CategoryCollation = [
11644        'default' => 'uppercase',
11645    ];
11646
11647    /**
11648     * Additional category collations to store during LinksUpdate. This can be used
11649     * to perform online migration of categories from one collation to another. An
11650     * array of associative arrays each having the following keys:
11651     *
11652     * - table: (string) The table name
11653     * - collation: (string) The collation to use for cl_sortkey
11654     * - fakeCollation: (string) The collation name to insert into cl_collation
11655     *
11656     * @since 1.38
11657     */
11658    public const TempCategoryCollations = [
11659        'default' => [],
11660        'type' => 'list',
11661    ];
11662
11663    /**
11664     * Whether to sort categories in OutputPage for display.
11665     *
11666     * The value of CategoryCollation is used for sorting.
11667     *
11668     * @unstable EXPERIMENTAL This feature is used for Parsoid development,
11669     * but its future as a core feature will depend on community uptake.
11670     */
11671    public const SortedCategories = [
11672        'default' => false,
11673        'type' => 'boolean',
11674    ];
11675
11676    /**
11677     * Array holding default tracking category names.
11678     *
11679     * Array contains the system messages for each tracking category.
11680     * Tracking categories allow pages with certain characteristics to be tracked.
11681     * It works by adding any such page to a category automatically.
11682     *
11683     * A message with the suffix '-desc' should be added as a description message
11684     * to have extra information on Special:TrackingCategories.
11685     *
11686     * @deprecated since 1.25 Extensions should now register tracking categories using
11687     * the new extension registration system.
11688     * @since 1.23
11689     */
11690    public const TrackingCategories = [
11691        'default' => [],
11692        'type' => 'list',
11693        'deprecated' => 'since 1.25 Extensions should now register tracking categories using ' .
11694            'the new extension registration system.',
11695    ];
11696
11697    // endregion -- End categories
11698
11699    /***************************************************************************/
11700    // region   Logging
11701    /** @name   Logging */
11702
11703    /**
11704     * The logging system has two levels: an event type, which describes the
11705     * general category and can be viewed as a named subset of all logs; and
11706     * an action, which is a specific kind of event that can exist in that
11707     * log type.
11708     *
11709     * Note that code should call LogPage::validTypes() to get a list of valid
11710     * log types instead of checking the global variable.
11711     */
11712    public const LogTypes = [
11713        'default' => [
11714            '',
11715            'block',
11716            'protect',
11717            'rights',
11718            'delete',
11719            'upload',
11720            'move',
11721            'import',
11722            'patrol',
11723            'merge',
11724            'suppress',
11725            'tag',
11726            'managetags',
11727            'contentmodel',
11728            'renameuser',
11729        ],
11730        'type' => 'list',
11731    ];
11732
11733    /**
11734     * This restricts log access to those who have a certain right
11735     * Users without this will not see it in the option menu and can not view it
11736     * Restricted logs are not added to recent changes
11737     * Logs should remain non-transcludable
11738     * Format: logtype => permissiontype
11739     */
11740    public const LogRestrictions = [
11741        'default' => [ 'suppress' => 'suppressionlog', ],
11742        'type' => 'map',
11743    ];
11744
11745    /**
11746     * Show/hide links on Special:Log will be shown for these log types.
11747     *
11748     * This is associative array of log type => boolean "hide by default"
11749     *
11750     * See $wgLogTypes for a list of available log types.
11751     *
11752     * **Example:**
11753     *
11754     * `$wgFilterLogTypes = [ 'move' => true, 'import' => false ];`
11755     *
11756     * Will display show/hide links for the move and import logs. Move logs will be
11757     * hidden by default unless the link is clicked. Import logs will be shown by
11758     * default, and hidden when the link is clicked.
11759     *
11760     * A message of the form logeventslist-[type]-log should be added, and will be
11761     * used for the link text.
11762     */
11763    public const FilterLogTypes = [
11764        'default' => [
11765            'patrol' => true,
11766            'tag' => true,
11767            'newusers' => false,
11768        ],
11769        'type' => 'map',
11770    ];
11771
11772    /**
11773     * Lists the message key string for each log type. The localized messages
11774     * will be listed in the user interface.
11775     *
11776     * Extensions with custom log types may add to this array.
11777     *
11778     * @since 1.19, if you follow the naming convention log-name-TYPE,
11779     * where TYPE is your log type, you don't need to use this array.
11780     */
11781    public const LogNames = [
11782        'default' => [
11783            '' => 'all-logs-page',
11784            'block' => 'blocklogpage',
11785            'protect' => 'protectlogpage',
11786            'rights' => 'rightslog',
11787            'delete' => 'dellogpage',
11788            'upload' => 'uploadlogpage',
11789            'move' => 'movelogpage',
11790            'import' => 'importlogpage',
11791            'patrol' => 'patrol-log-page',
11792            'merge' => 'mergelog',
11793            'suppress' => 'suppressionlog',
11794        ],
11795        'type' => 'map',
11796    ];
11797
11798    /**
11799     * Lists the message key string for descriptive text to be shown at the
11800     * top of each log type.
11801     *
11802     * Extensions with custom log types may add to this array.
11803     *
11804     * @since 1.19, if you follow the naming convention log-description-TYPE,
11805     * where TYPE is your log type, yoy don't need to use this array.
11806     */
11807    public const LogHeaders = [
11808        'default' => [
11809            '' => 'alllogstext',
11810            'block' => 'blocklogtext',
11811            'delete' => 'dellogpagetext',
11812            'import' => 'importlogpagetext',
11813            'merge' => 'mergelogpagetext',
11814            'move' => 'movelogpagetext',
11815            'patrol' => 'patrol-log-header',
11816            'protect' => 'protectlogtext',
11817            'rights' => 'rightslogtext',
11818            'suppress' => 'suppressionlogtext',
11819            'upload' => 'uploadlogpagetext',
11820        ],
11821        'type' => 'map',
11822    ];
11823
11824    /**
11825     * Maps log actions to message keys, for formatting log entries of each type
11826     * and action when displaying logs to the user.
11827     * The array keys are composed as "$type/$action".
11828     *
11829     * Extensions with custom log types may add to this array.
11830     */
11831    public const LogActions = [
11832        'default' => [],
11833        'type' => 'map',
11834    ];
11835
11836    /**
11837     * The same as above, but here values are class names or ObjectFactory specifications,
11838     * not messages. The specification must resolve to a LogFormatter subclass,
11839     * and will receive the LogEntry object as its first constructor argument.
11840     * The type can be specified as '*' (e.g. 'block/*') to handle all types.
11841     *
11842     * @see \LogPage::actionText
11843     * @see \LogFormatter
11844     */
11845    public const LogActionsHandlers = [
11846        'default' => [
11847            'block/block' => BlockLogFormatter::class,
11848            'block/reblock' => BlockLogFormatter::class,
11849            'block/unblock' => BlockLogFormatter::class,
11850            'contentmodel/change' => ContentModelLogFormatter::class,
11851            'contentmodel/new' => ContentModelLogFormatter::class,
11852            'delete/delete' => DeleteLogFormatter::class,
11853            'delete/delete_redir' => DeleteLogFormatter::class,
11854            'delete/delete_redir2' => DeleteLogFormatter::class,
11855            'delete/event' => DeleteLogFormatter::class,
11856            'delete/restore' => DeleteLogFormatter::class,
11857            'delete/revision' => DeleteLogFormatter::class,
11858            'import/interwiki' => ImportLogFormatter::class,
11859            'import/upload' => ImportLogFormatter::class,
11860            'managetags/activate' => LogFormatter::class,
11861            'managetags/create' => LogFormatter::class,
11862            'managetags/deactivate' => LogFormatter::class,
11863            'managetags/delete' => LogFormatter::class,
11864            'merge/merge' => MergeLogFormatter::class,
11865            'move/move' => MoveLogFormatter::class,
11866            'move/move_redir' => MoveLogFormatter::class,
11867            'patrol/patrol' => PatrolLogFormatter::class,
11868            'patrol/autopatrol' => PatrolLogFormatter::class,
11869            'protect/modify' => ProtectLogFormatter::class,
11870            'protect/move_prot' => ProtectLogFormatter::class,
11871            'protect/protect' => ProtectLogFormatter::class,
11872            'protect/unprotect' => ProtectLogFormatter::class,
11873            'renameuser/renameuser' => RenameuserLogFormatter::class,
11874            'rights/autopromote' => RightsLogFormatter::class,
11875            'rights/rights' => RightsLogFormatter::class,
11876            'suppress/block' => BlockLogFormatter::class,
11877            'suppress/delete' => DeleteLogFormatter::class,
11878            'suppress/event' => DeleteLogFormatter::class,
11879            'suppress/reblock' => BlockLogFormatter::class,
11880            'suppress/revision' => DeleteLogFormatter::class,
11881            'tag/update' => TagLogFormatter::class,
11882            'upload/overwrite' => UploadLogFormatter::class,
11883            'upload/revert' => UploadLogFormatter::class,
11884            'upload/upload' => UploadLogFormatter::class,
11885        ],
11886        'type' => 'map',
11887    ];
11888
11889    /**
11890     * List of log types that can be filtered by action types
11891     *
11892     * To each action is associated the list of log_action
11893     * subtypes to search for, usually one, but not necessarily so
11894     * Extensions may append to this array
11895     *
11896     * @since 1.27
11897     */
11898    public const ActionFilteredLogs = [
11899        'default' => [
11900            'block' => [
11901                'block' => [ 'block' ],
11902                'reblock' => [ 'reblock' ],
11903                'unblock' => [ 'unblock' ],
11904            ],
11905            'contentmodel' => [
11906                'change' => [ 'change' ],
11907                'new' => [ 'new' ],
11908            ],
11909            'delete' => [
11910                'delete' => [ 'delete' ],
11911                'delete_redir' => [ 'delete_redir', 'delete_redir2' ],
11912                'restore' => [ 'restore' ],
11913                'event' => [ 'event' ],
11914                'revision' => [ 'revision' ],
11915            ],
11916            'import' => [
11917                'interwiki' => [ 'interwiki' ],
11918                'upload' => [ 'upload' ],
11919            ],
11920            'managetags' => [
11921                'create' => [ 'create' ],
11922                'delete' => [ 'delete' ],
11923                'activate' => [ 'activate' ],
11924                'deactivate' => [ 'deactivate' ],
11925            ],
11926            'move' => [
11927                'move' => [ 'move' ],
11928                'move_redir' => [ 'move_redir' ],
11929            ],
11930            'newusers' => [
11931                'create' => [ 'create', 'newusers' ],
11932                'create2' => [ 'create2' ],
11933                'autocreate' => [ 'autocreate' ],
11934                'byemail' => [ 'byemail' ],
11935            ],
11936            'protect' => [
11937                'protect' => [ 'protect' ],
11938                'modify' => [ 'modify' ],
11939                'unprotect' => [ 'unprotect' ],
11940                'move_prot' => [ 'move_prot' ],
11941            ],
11942            'rights' => [
11943                'rights' => [ 'rights' ],
11944                'autopromote' => [ 'autopromote' ],
11945            ],
11946            'suppress' => [
11947                'event' => [ 'event' ],
11948                'revision' => [ 'revision' ],
11949                'delete' => [ 'delete' ],
11950                'block' => [ 'block' ],
11951                'reblock' => [ 'reblock' ],
11952            ],
11953            'upload' => [
11954                'upload' => [ 'upload' ],
11955                'overwrite' => [ 'overwrite' ],
11956                'revert' => [ 'revert' ],
11957            ],
11958        ],
11959        'type' => 'map',
11960    ];
11961
11962    /**
11963     * Maintain a log of newusers at Special:Log/newusers?
11964     */
11965    public const NewUserLog = [
11966        'default' => true,
11967    ];
11968
11969    /**
11970     * Maintain a log of page creations at Special:Log/create?
11971     *
11972     * @since 1.32
11973     */
11974    public const PageCreationLog = [
11975        'default' => true,
11976    ];
11977
11978    // endregion -- end logging
11979
11980    /***************************************************************************/
11981    // region   Special pages (general and miscellaneous)
11982    /** @name   Special pages (general and miscellaneous) */
11983
11984    /**
11985     * Allow special page inclusions such as {{Special:Allpages}}
11986     */
11987    public const AllowSpecialInclusion = [
11988        'default' => true,
11989    ];
11990
11991    /**
11992     * Set this to an array of special page names to prevent
11993     * maintenance/updateSpecialPages.php from updating those pages.
11994     *
11995     * Mapping each special page name to a run mode like 'periodical' if a cronjob is set up.
11996     */
11997    public const DisableQueryPageUpdate = [
11998        'default' => false,
11999    ];
12000
12001    /**
12002     * On Special:Unusedimages, consider images "used", if they are put
12003     * into a category. Default (false) is not to count those as used.
12004     */
12005    public const CountCategorizedImagesAsUsed = [
12006        'default' => false,
12007    ];
12008
12009    /**
12010     * Maximum number of links to a redirect page listed on
12011     * Special:Whatlinkshere/RedirectDestination
12012     */
12013    public const MaxRedirectLinksRetrieved = [
12014        'default' => 500,
12015    ];
12016
12017    /**
12018     * Shortest CIDR limits that can be checked in any individual range check
12019     * at Special:Contributions.
12020     *
12021     * @since 1.30
12022     */
12023    public const RangeContributionsCIDRLimit = [
12024        'default' => [
12025            'IPv4' => 16,
12026            'IPv6' => 32,
12027        ],
12028        'type' => 'map',
12029        'additionalProperties' => [ 'type' => 'integer', ],
12030    ];
12031
12032    // endregion -- end special pages
12033
12034    /***************************************************************************/
12035    // region   Actions
12036    /** @name   Actions */
12037
12038    /**
12039     * Map of allowed values for the "title=foo&action=<action>" parameter.
12040     * to the corresponding handler code.
12041     * See ActionFactory for the syntax. Core defaults are in ActionFactory::CORE_ACTIONS,
12042     * anything here overrides that.
12043     */
12044    public const Actions = [
12045        'default' => [],
12046        'type' => 'map',
12047    ];
12048
12049    // endregion -- end actions
12050
12051    /***************************************************************************/
12052    // region   Robot (search engine crawler) policy
12053    /** @name   Robot (search engine crawler) policy */
12054    // See also $wgNoFollowLinks.
12055
12056    /**
12057     * Default robot policy.  The default policy is to encourage indexing and fol-
12058     * lowing of links.  It may be overridden on a per-namespace and/or per-page
12059     * basis.
12060     */
12061    public const DefaultRobotPolicy = [
12062        'default' => 'index,follow',
12063    ];
12064
12065    /**
12066     * Robot policies per namespaces. The default policy is given above, the array
12067     * is made of namespace constants as defined in includes/Defines.php.  You can-
12068     * not specify a different default policy for NS_SPECIAL: it is always noindex,
12069     * nofollow.  This is because a number of special pages (e.g., ListPages) have
12070     * many permutations of options that display the same data under redundant
12071     * URLs, so search engine spiders risk getting lost in a maze of twisty special
12072     * pages, all alike, and never reaching your actual content.
12073     *
12074     * **Example:**
12075     *
12076     * ```
12077     * $wgNamespaceRobotPolicies = [ NS_TALK => 'noindex' ];
12078     * ```
12079     */
12080    public const NamespaceRobotPolicies = [
12081        'default' => [],
12082        'type' => 'map',
12083    ];
12084
12085    /**
12086     * Robot policies per article. These override the per-namespace robot policies.
12087     *
12088     * Must be in the form of an array where the key part is a properly canonicalised
12089     * text form title and the value is a robot policy.
12090     *
12091     * **Example:**
12092     *
12093     * ```
12094     * $wgArticleRobotPolicies = [
12095     *         'Main Page' => 'noindex,follow',
12096     *         'User:Bob' => 'index,follow',
12097     * ];
12098     * ```
12099     *
12100     * **Example that DOES NOT WORK because the names are not canonical text**
12101     * forms:
12102     *
12103     * ```
12104     * $wgArticleRobotPolicies = [
12105     *   // Underscore, not space!
12106     *   'Main_Page' => 'noindex,follow',
12107     *   // "Project", not the actual project name!
12108     *   'Project:X' => 'index,follow',
12109     *   // Needs to be "Abc", not "abc" (unless $wgCapitalLinks is false for that namespace)!
12110     *   'abc' => 'noindex,nofollow'
12111     * ];
12112     * ```
12113     */
12114    public const ArticleRobotPolicies = [
12115        'default' => [],
12116        'type' => 'map',
12117    ];
12118
12119    /**
12120     * An array of namespace keys in which the __INDEX__/__NOINDEX__ magic words
12121     * will not function, so users can't decide whether pages in that namespace are
12122     * indexed by search engines.  If set to null, default to $wgContentNamespaces.
12123     *
12124     * **Example:**
12125     *
12126     * ```
12127     * $wgExemptFromUserRobotsControl = [ NS_MAIN, NS_TALK, NS_PROJECT ];
12128     * ```
12129     */
12130    public const ExemptFromUserRobotsControl = [
12131        'default' => null,
12132        'type' => '?list',
12133    ];
12134
12135    // endregion End robot policy
12136
12137    /***************************************************************************/
12138    // region   Action API and REST API
12139    /** @name   Action API and REST API
12140     */
12141
12142    /**
12143     * WARNING: SECURITY THREAT - debug use only
12144     *
12145     * Disables many security checks in the API for debugging purposes.
12146     * This flag should never be used on the production servers, as it introduces
12147     * a number of potential security holes. Even when enabled, the validation
12148     * will still be performed, but instead of failing, API will return a warning.
12149     * Also, there will always be a warning notifying that this flag is set.
12150     * At this point, the flag allows GET requests to go through for modules
12151     * requiring POST.
12152     *
12153     * @since 1.21
12154     */
12155    public const DebugAPI = [
12156        'default' => false,
12157    ];
12158
12159    /**
12160     * API module extensions.
12161     *
12162     * Associative array mapping module name to modules specs;
12163     * Each module spec is an associative array containing at least
12164     * the 'class' key for the module's class, and optionally a
12165     * 'factory' key for the factory function to use for the module.
12166     *
12167     * That factory function will be called with two parameters,
12168     * the parent module (an instance of ApiBase, usually ApiMain)
12169     * and the name the module was registered under. The return
12170     * value must be an instance of the class given in the 'class'
12171     * field.
12172     *
12173     * For backward compatibility, the module spec may also be a
12174     * simple string containing the module's class name. In that
12175     * case, the class' constructor will be called with the parent
12176     * module and module name as parameters, as described above.
12177     *
12178     * Examples for registering API modules:
12179     *
12180     * ```
12181     * $wgAPIModules['foo'] = 'ApiFoo';
12182     * $wgAPIModules['bar'] = [
12183     *   'class' => ApiBar::class,
12184     *   'factory' => function( $main, $name ) { ... }
12185     * ];
12186     * $wgAPIModules['xyzzy'] = [
12187     *   'class' => ApiXyzzy::class,
12188     *   'factory' => [ XyzzyFactory::class, 'newApiModule' ]
12189     * ];
12190     * ```
12191     * Extension modules may override the core modules.
12192     * See ApiMain::MODULES for a list of the core modules.
12193     */
12194    public const APIModules = [
12195        'default' => [],
12196        'type' => 'map',
12197    ];
12198
12199    /**
12200     * API format module extensions.
12201     *
12202     * Associative array mapping format module name to module specs (see $wgAPIModules).
12203     * Extension modules may override the core modules.
12204     *
12205     * See ApiMain::FORMATS for a list of the core format modules.
12206     */
12207    public const APIFormatModules = [
12208        'default' => [],
12209        'type' => 'map',
12210    ];
12211
12212    /**
12213     * API Query meta module extensions.
12214     *
12215     * Associative array mapping meta module name to module specs (see $wgAPIModules).
12216     * Extension modules may override the core modules.
12217     *
12218     * See ApiQuery::QUERY_META_MODULES for a list of the core meta modules.
12219     */
12220    public const APIMetaModules = [
12221        'default' => [],
12222        'type' => 'map',
12223    ];
12224
12225    /**
12226     * API Query prop module extensions.
12227     *
12228     * Associative array mapping prop module name to module specs (see $wgAPIModules).
12229     * Extension modules may override the core modules.
12230     *
12231     * See ApiQuery::QUERY_PROP_MODULES for a list of the core prop modules.
12232     */
12233    public const APIPropModules = [
12234        'default' => [],
12235        'type' => 'map',
12236    ];
12237
12238    /**
12239     * API Query list module extensions.
12240     *
12241     * Associative array mapping list module name to module specs (see $wgAPIModules).
12242     * Extension modules may override the core modules.
12243     *
12244     * See ApiQuery::QUERY_LIST_MODULES for a list of the core list modules.
12245     */
12246    public const APIListModules = [
12247        'default' => [],
12248        'type' => 'map',
12249    ];
12250
12251    /**
12252     * Maximum amount of rows to scan in a DB query in the API
12253     * The default value is generally fine
12254     */
12255    public const APIMaxDBRows = [
12256        'default' => 5000,
12257    ];
12258
12259    /**
12260     * The maximum size (in bytes) of an API result.
12261     *
12262     * @warning Do not set this lower than $wgMaxArticleSize*1024
12263     */
12264    public const APIMaxResultSize = [
12265        'default' => 8_388_608,
12266    ];
12267
12268    /**
12269     * The maximum number of uncached diffs that can be retrieved in one API
12270     * request. Set this to 0 to disable API diffs altogether
12271     */
12272    public const APIMaxUncachedDiffs = [
12273        'default' => 1,
12274    ];
12275
12276    /**
12277     * Maximum amount of DB lag on a majority of DB replica DBs to tolerate
12278     * before forcing bots to retry any write requests via API errors.
12279     *
12280     * This should be lower than the 'max lag' value in $wgLBFactoryConf.
12281     */
12282    public const APIMaxLagThreshold = [
12283        'default' => 7,
12284    ];
12285
12286    /**
12287     * Log file or URL (TCP or UDP) to log API requests to, or false to disable
12288     * API request logging
12289     */
12290    public const APIRequestLog = [
12291        'default' => false,
12292        'deprecated' => 'since 1.43; use api or api-request $wgDebugLogGroups channel',
12293    ];
12294
12295    /**
12296     * Set the timeout for the API help text cache. If set to 0, caching disabled
12297     */
12298    public const APICacheHelpTimeout = [
12299        'default' => 60 * 60,
12300    ];
12301
12302    /**
12303     * The ApiQueryQueryPages module should skip pages that are redundant to true
12304     * API queries.
12305     */
12306    public const APIUselessQueryPages = [
12307        'default' => [
12308            'MIMEsearch',
12309            'LinkSearch',
12310        ],
12311        'type' => 'list',
12312    ];
12313
12314    /**
12315     * Enable previewing licences via AJAX.
12316     */
12317    public const AjaxLicensePreview = [
12318        'default' => true,
12319    ];
12320
12321    /**
12322     * Settings for incoming cross-site AJAX requests:
12323     * Newer browsers support cross-site AJAX when the target resource allows requests
12324     * from the origin domain by the Access-Control-Allow-Origin header.
12325     *
12326     * This is currently only used by the API (requests to api.php)
12327     * $wgCrossSiteAJAXdomains can be set using a wildcard syntax:
12328     *
12329     * - '*' matches any number of characters
12330     * - '?' matches any 1 character
12331     *
12332     * **Example:**
12333     *
12334     * ```
12335     * $wgCrossSiteAJAXdomains = [
12336     *     'www.mediawiki.org',
12337     *     '*.wikipedia.org',
12338     *     '*.wikimedia.org',
12339     *     '*.wiktionary.org',
12340     * ];
12341     * ```
12342     */
12343    public const CrossSiteAJAXdomains = [
12344        'default' => [],
12345        'type' => 'map',
12346    ];
12347
12348    /**
12349     * Domains that should not be allowed to make AJAX requests,
12350     * even if they match one of the domains allowed by $wgCrossSiteAJAXdomains
12351     * Uses the same syntax as $wgCrossSiteAJAXdomains
12352     */
12353    public const CrossSiteAJAXdomainExceptions = [
12354        'default' => [],
12355        'type' => 'map',
12356    ];
12357
12358    /**
12359     * List of allowed headers for cross-origin API requests.
12360     */
12361    public const AllowedCorsHeaders = [
12362        'default' => [
12363            /* simple headers (see spec) */
12364            'Accept',
12365            'Accept-Language',
12366            'Content-Language',
12367            'Content-Type',
12368            /* non-authorable headers in XHR, which are however requested by some UAs */
12369            'Accept-Encoding',
12370            'DNT',
12371            'Origin',
12372            /* MediaWiki whitelist */
12373            'User-Agent',
12374            'Api-User-Agent',
12375            /* Allowing caching preflight requests, see T269636 */
12376            'Access-Control-Max-Age',
12377            /* OAuth 2.0, see T322944 */
12378            'Authorization',
12379        ],
12380        'type' => 'list',
12381    ];
12382
12383    /**
12384     * Additional REST API Route files.
12385     *
12386     * A common usage is to enable development/experimental endpoints only on test wikis.
12387     */
12388    public const RestAPIAdditionalRouteFiles = [
12389        'default' => [],
12390        'type' => 'list',
12391    ];
12392
12393    /**
12394     * A list of OpenAPI specs to be made available for exploration on
12395     * Special:RestSandbox. If none are given, Special:RestSandbox is disabled.
12396     *
12397     * This is an associative array, arbitrary spec IDs to spec descriptions.
12398     * Each spec description is an array with the following keys:
12399     * - url: the URL that will return the OpenAPI spec.
12400     * - name: the name of the API, to be shown on Special:RestSandbox.
12401     *   Ignored if msg is given.
12402     * - msg: a message key for the name of the API, to be shown on
12403     *   Special:RestSandbox.
12404     *
12405     * @unstable Introduced in 1.43. We may want to rename or change this to
12406     * accommodate the need to list external APIs in a central discovery
12407     * document.
12408     */
12409    public const RestSandboxSpecs = [
12410        'default' => [],
12411        'type' => 'map',
12412        'additionalProperties' => [
12413            'type' => 'object',
12414            'properties' => [
12415                'url' => [ 'type' => 'string', 'format' => 'url' ],
12416                'name' => [ 'type' => 'string' ],
12417                'msg' => [ 'type' => 'string', 'description' => 'a message key' ]
12418            ],
12419            'required' => [ 'url' ]
12420        ]
12421    ];
12422
12423    // endregion -- End AJAX and API
12424
12425    /***************************************************************************/
12426    // region   Shell and process control
12427    /** @name   Shell and process control */
12428
12429    /**
12430     * Maximum amount of virtual memory available to shell processes under linux, in KiB.
12431     */
12432    public const MaxShellMemory = [
12433        'default' => 307_200,
12434    ];
12435
12436    /**
12437     * Maximum file size created by shell processes under linux, in KiB
12438     * ImageMagick convert for example can be fairly hungry for scratch space
12439     */
12440    public const MaxShellFileSize = [
12441        'default' => 102_400,
12442    ];
12443
12444    /**
12445     * Maximum CPU time in seconds for shell processes under Linux
12446     */
12447    public const MaxShellTime = [
12448        'default' => 180,
12449    ];
12450
12451    /**
12452     * Maximum wall clock time (i.e. real time, of the kind the clock on the wall
12453     * would measure) in seconds for shell processes under Linux
12454     */
12455    public const MaxShellWallClockTime = [
12456        'default' => 180,
12457    ];
12458
12459    /**
12460     * Under Linux: a cgroup directory used to constrain memory usage of shell
12461     * commands. The directory must be writable by the user which runs MediaWiki.
12462     *
12463     * If specified, this is used instead of ulimit, which is inaccurate, and
12464     * causes malloc() to return NULL, which exposes bugs in C applications, making
12465     * them segfault or deadlock.
12466     *
12467     * A wrapper script will create a cgroup for each shell command that runs, as
12468     * a subgroup of the specified cgroup. If the memory limit is exceeded, the
12469     * kernel will send a SIGKILL signal to a process in the subgroup.
12470     *
12471     * **Example:**
12472     *
12473     * ```
12474     * mkdir -p /sys/fs/cgroup/memory/mediawiki
12475     * mkdir -m 0777 /sys/fs/cgroup/memory/mediawiki/job
12476     * echo '$wgShellCgroup = "/sys/fs/cgroup/memory/mediawiki/job";' >> LocalSettings.php
12477     * ```
12478     * The reliability of cgroup cleanup can be improved by installing a
12479     * notify_on_release script in the root cgroup, see e.g.
12480     * https://gerrit.wikimedia.org/r/#/c/40784
12481     */
12482    public const ShellCgroup = [
12483        'default' => false,
12484    ];
12485
12486    /**
12487     * Executable path of the PHP cli binary. Should be set up on install.
12488     */
12489    public const PhpCli = [
12490        'default' => '/usr/bin/php',
12491    ];
12492
12493    /**
12494     * Method to use to restrict shell commands
12495     *
12496     * Supported options:
12497     * - 'autodetect': Autodetect if any restriction methods are available
12498     * - 'firejail': Use firejail <https://firejail.wordpress.com/>
12499     * - false: Don't use any restrictions
12500     *
12501     * @note If using firejail with MediaWiki running in a home directory different
12502     * from the webserver user, firejail 0.9.44+ is required.
12503     * @since 1.31
12504     */
12505    public const ShellRestrictionMethod = [
12506        'default' => 'autodetect',
12507        'type' => 'string|false',
12508    ];
12509
12510    /**
12511     * Shell commands can be run on a remote server using Shellbox. To use this
12512     * feature, set this to the URLs mapped by the service, and also configure $wgShellboxSecretKey.
12513     *
12514     * You can also disable a certain service by setting it to false or null.
12515     *
12516     * 'default' would be the default URL if no URL is defined for that service.
12517     *
12518     * For more information about installing Shellbox, see
12519     * https://www.mediawiki.org/wiki/Shellbox
12520     *
12521     * @since 1.37
12522     */
12523    public const ShellboxUrls = [
12524        'default' => [ 'default' => null, ],
12525        'type' => 'map',
12526        'additionalProperties' => [
12527            'type' => 'string|false|null',
12528        ],
12529    ];
12530
12531    /**
12532     * The secret key for HMAC verification of Shellbox requests. Set this to
12533     * a long random string.
12534     *
12535     * @since 1.36
12536     */
12537    public const ShellboxSecretKey = [
12538        'default' => null,
12539        'type' => '?string',
12540    ];
12541
12542    /**
12543     * The POSIX-compatible shell to use when running scripts. This is used by
12544     * some media handling shell commands.
12545     *
12546     * If ShellboxUrls is configured, this path should exist on the remote side.
12547     * On Windows this should be the full path to bash.exe, not git-bash.exe.
12548     *
12549     * @since 1.42
12550     */
12551    public const ShellboxShell = [
12552        'default' => '/bin/sh',
12553        'type' => '?string',
12554    ];
12555
12556    // endregion -- end Shell and process control
12557
12558    /***************************************************************************/
12559    // region   HTTP client
12560    /** @name   HTTP client */
12561
12562    /**
12563     * Timeout for HTTP requests done internally, in seconds.
12564     *
12565     * @since 1.5
12566     */
12567    public const HTTPTimeout = [
12568        'default' => 25,
12569        'type' => 'float',
12570    ];
12571
12572    /**
12573     * Timeout for connections done internally (in seconds).
12574     *
12575     * Only supported if cURL is installed, ignored otherwise.
12576     *
12577     * @since 1.22
12578     */
12579    public const HTTPConnectTimeout = [
12580        'default' => 5.0,
12581        'type' => 'float',
12582    ];
12583
12584    /**
12585     * The maximum HTTP request timeout in seconds. If any specified or configured
12586     * request timeout is larger than this, then this value will be used instead.
12587     * Zero is interpreted as "no limit".
12588     *
12589     * @since 1.35
12590     */
12591    public const HTTPMaxTimeout = [
12592        'default' => 0,
12593        'type' => 'float',
12594    ];
12595
12596    /**
12597     * The maximum HTTP connect timeout in seconds. If any specified or configured
12598     * connect timeout is larger than this, then this value will be used instead.
12599     * Zero is interpreted as "no limit".
12600     *
12601     * @since 1.35
12602     */
12603    public const HTTPMaxConnectTimeout = [
12604        'default' => 0,
12605        'type' => 'float',
12606    ];
12607
12608    /**
12609     * Timeout for HTTP requests done internally for transwiki imports, in seconds.
12610     *
12611     * @since 1.29
12612     */
12613    public const HTTPImportTimeout = [
12614        'default' => 25,
12615    ];
12616
12617    /**
12618     * Timeout for Asynchronous (background) HTTP requests, in seconds.
12619     */
12620    public const AsyncHTTPTimeout = [
12621        'default' => 25,
12622    ];
12623
12624    /**
12625     * Proxy to use for CURL requests.
12626     */
12627    public const HTTPProxy = [
12628        'default' => '',
12629    ];
12630
12631    /**
12632     * Local virtual hosts.
12633     *
12634     * This lists domains that are configured as virtual hosts on the same machine.
12635     * It is expected that each domain can be identified by its hostname alone,
12636     * without any ports.
12637     *
12638     * This affects the following:
12639     * - MWHttpRequest: If a request is to be made to a domain listed here, or any
12640     *   subdomain thereof, then $wgLocalHTTPProxy will be used.
12641     *   Command-line scripts are not affected by this setting and will always use
12642     *   the proxy if it is configured.
12643     *
12644     * @since 1.25
12645     */
12646    public const LocalVirtualHosts = [
12647        'default' => [],
12648        'type' => 'map',
12649    ];
12650
12651    /**
12652     * Reverse proxy to use for requests to domains in $wgLocalVirtualHosts
12653     *
12654     * When used, any port in the request URL will be dropped. The behavior of
12655     * redirects and cookies is dependent upon the reverse proxy actually in use,
12656     * as MediaWiki doesn't implement any special handling for them.
12657     *
12658     * If set to false, no reverse proxy will be used for local requests.
12659     *
12660     * @since 1.38
12661     */
12662    public const LocalHTTPProxy = [
12663        'default' => false,
12664        'type' => 'string|false',
12665    ];
12666
12667    /**
12668     * Whether to respect/honour
12669     *  - request ID provided by the incoming request via the `X-Request-Id`
12670     *  - trace context provided by the incoming request via the `tracestate` and `traceparent`
12671     *
12672     * Set to `true` if the entity sitting in front of MediaWiki sanitises external requests.
12673     *
12674     * Default: `false`.
12675     */
12676    public const AllowExternalReqID = [
12677        'default' => false,
12678    ];
12679
12680    // endregion -- End HTTP client
12681
12682    /***************************************************************************/
12683    // region   Job queue
12684    /** @name   Job queue */
12685
12686    /**
12687     * Number of jobs to perform per request. May be less than one in which case jobs are
12688     * performed probabilistically. If this is zero, jobs will not be done during ordinary
12689     * apache requests. In this case, maintenance/runJobs.php should be run in loop every
12690     * few seconds via a service or cron job. If using a cron job, be sure to handle the
12691     * case where the script is already running (e.g. via `/usr/bin/flock -n <lock_file>`).
12692     *
12693     * If this is set to a non-zero number, then it is highly recommended that PHP run in
12694     * fastcgi mode (php_fpm). When using a standard Apache PHP handler (mod_php), it is
12695     * recommended that output_buffering and zlib.output_compression both be set to "Off",
12696     * allowing MediaWiki to install an unlimited size output buffer on the fly. Setting
12697     * output_buffering to an integer (e.g. 4096) or enabling zlib.output_compression can
12698     * cause user-visible slowness as background tasks execute during web requests.
12699     *
12700     * Regardless of the web server engine in use, be sure to configure a sufficient number
12701     * processes/threads in order to avoid exhaustion (which will cause user-visible slowness).
12702     */
12703    public const JobRunRate = [
12704        'default' => 1,
12705    ];
12706
12707    /**
12708     * When $wgJobRunRate > 0, try to run jobs asynchronously, spawning a new process
12709     * to handle the job execution, instead of blocking the request until the job
12710     * execution finishes.
12711     *
12712     * @since 1.23
12713     */
12714    public const RunJobsAsync = [
12715        'default' => false,
12716    ];
12717
12718    /**
12719     * Number of rows to update per job
12720     */
12721    public const UpdateRowsPerJob = [
12722        'default' => 300,
12723    ];
12724
12725    /**
12726     * Number of rows to update per query
12727     */
12728    public const UpdateRowsPerQuery = [
12729        'default' => 100,
12730    ];
12731
12732    // endregion -- End job queue
12733
12734    /***************************************************************************/
12735    // region   Miscellaneous
12736    /** @name   Miscellaneous */
12737
12738    /**
12739     * Allow redirection to another page when a user logs in.
12740     *
12741     * To enable, set to a string like 'Main Page'
12742     */
12743    public const RedirectOnLogin = [
12744        'default' => null,
12745    ];
12746
12747    /**
12748     * Global configuration variable for Virtual REST Services.
12749     *
12750     * Use the 'path' key to define automatically mounted services. The value for this
12751     * key is a map of path prefixes to service configuration. The latter is an array of:
12752     *   - class : the fully qualified class name
12753     *   - options : map of arguments to the class constructor
12754     * Such services will be available to handle queries under their path from the VRS
12755     * singleton, e.g. MediaWikiServices::getInstance()->getVirtualRESTServiceClient();
12756     *
12757     * Auto-mounting example for Parsoid:
12758     *
12759     * $wgVirtualRestConfig['paths']['/parsoid/'] = [
12760     *     'class' => ParsoidVirtualRESTService::class,
12761     *     'options' => [
12762     *         'url' => 'http://localhost:8000',
12763     *         'prefix' => 'enwiki',
12764     *         'domain' => 'en.wikipedia.org'
12765     *     ]
12766     * ];
12767     *
12768     * Parameters for different services can also be declared inside the 'modules' value,
12769     * which is to be treated as an associative array. The parameters in 'global' will be
12770     * merged with service-specific ones. The result will then be passed to
12771     * VirtualRESTService::__construct() in the module.
12772     *
12773     * Example config for Parsoid:
12774     *
12775     *   $wgVirtualRestConfig['modules']['parsoid'] = [
12776     *     'url' => 'http://localhost:8000',
12777     *     'prefix' => 'enwiki',
12778     *     'domain' => 'en.wikipedia.org',
12779     *   ];
12780     *
12781     * @since 1.25
12782     */
12783    public const VirtualRestConfig = [
12784        'default' => [
12785            'paths' => [],
12786            'modules' => [],
12787            'global' => [
12788                # Timeout in seconds
12789                'timeout' => 360,
12790                # 'domain' is set to $wgCanonicalServer in Setup.php
12791                'forwardCookies' => false,
12792                'HTTPProxy' => null
12793            ]
12794        ],
12795        'mergeStrategy' => 'array_plus_2d',
12796        'type' => 'map',
12797    ];
12798
12799    /**
12800     * Mapping of event channels (or channel categories) to EventRelayer configuration.
12801     *
12802     * By setting up a PubSub system (like Kafka) and enabling a corresponding EventRelayer class
12803     * that uses it, MediaWiki can broadcast events to all subscribers. Certain features like WAN
12804     * cache purging and CDN cache purging will emit events to this system. Appropriate listeners
12805     * can subscribe to the channel and take actions based on the events. For example, a local daemon
12806     * can run on each CDN cache node and perform local purges based on the URL purge channel
12807     * events.
12808     *
12809     * Some extensions may want to use "channel categories" so that different channels can also
12810     * share the same custom relayer instance (e.g. when it's likely to be overridden). They can use
12811     * EventRelayerGroup::getRelayer() based on the category but call notify() on various different
12812     * actual channels. One reason for this would be that some systems have very different
12813     * performance vs durability needs, so one system (e.g. Kafka) may not be suitable for all
12814     * uses.
12815     *
12816     * The 'default' key is for all channels (or channel categories) without an explicit entry
12817     * here.
12818     *
12819     * @since 1.27
12820     */
12821    public const EventRelayerConfig = [
12822        'default' => [
12823            'default' => [ 'class' => EventRelayerNull::class, ],
12824        ],
12825        'type' => 'map',
12826    ];
12827
12828    /**
12829     * Share data about this installation with MediaWiki developers
12830     *
12831     * When set to true, MediaWiki will periodically ping https://www.mediawiki.org/ with basic
12832     * data about this MediaWiki instance. This data includes, for example, the type of system,
12833     * PHP version, and chosen database backend. The Wikimedia Foundation shares this data with
12834     * MediaWiki developers to help guide future development efforts.
12835     *
12836     * For details about what data is sent, see: https://www.mediawiki.org/wiki/Manual:$wgPingback
12837     *
12838     * For the pingback privacy policy, see:
12839     * https://wikimediafoundation.org/wiki/MediaWiki_Pingback_Privacy_Statement
12840     *
12841     * Aggregate pingback data is available at: https://pingback.wmflabs.org/
12842     *
12843     * @since 1.28
12844     */
12845    public const Pingback = [
12846        'default' => false,
12847        'type' => 'boolean',
12848    ];
12849
12850    /**
12851     * Origin Trials tokens.
12852     *
12853     * @since 1.33
12854     */
12855    public const OriginTrials = [
12856        'default' => [],
12857        'type' => 'list',
12858    ];
12859
12860    /**
12861     * Expiry of the endpoint definition for the Reporting API.
12862     *
12863     * @unstable EXPERIMENTAL
12864     * @since 1.34
12865     */
12866    public const ReportToExpiry = [
12867        'default' => 86400,
12868        'type' => 'integer',
12869    ];
12870
12871    /**
12872     * List of endpoints for the Reporting API.
12873     *
12874     * @unstable EXPERIMENTAL
12875     * @since 1.34
12876     */
12877    public const ReportToEndpoints = [
12878        'default' => [],
12879        'type' => 'list',
12880    ];
12881
12882    /**
12883     * List of Feature Policy Reporting types to enable.
12884     *
12885     * Each entry is turned into a Feature-Policy-Report-Only header.
12886     *
12887     * @unstable EXPERIMENTAL
12888     * @since 1.34
12889     */
12890    public const FeaturePolicyReportOnly = [
12891        'default' => [],
12892        'type' => 'list',
12893    ];
12894
12895    /**
12896     * List of preferred skins to be listed higher in Special:Preferences
12897     *
12898     * @since 1.38
12899     */
12900    public const SkinsPreferred = [
12901        'default' => [ 'vector-2022', 'vector' ],
12902        'type' => 'list',
12903    ];
12904
12905    /**
12906     * List of skins that show a link to the Special:Contribute page
12907     *
12908     * @since 1.40
12909     */
12910    public const SpecialContributeSkinsEnabled = [
12911        'default' => [],
12912        'type' => 'list',
12913    ];
12914
12915    /**
12916     * Whether to enable the client-side edit recovery feature.
12917     *
12918     * @unstable Temporary feature flag, T341844
12919     * @since 1.41
12920     */
12921    public const EnableEditRecovery = [
12922        'default' => false,
12923        'type' => 'boolean',
12924    ];
12925
12926    /**
12927     * Number of seconds to keep edit recovery data after the edit is stored.
12928     */
12929    public const EditRecoveryExpiry = [
12930        'default' => 30 * 24 * 3600,
12931        'type' => 'integer',
12932    ];
12933
12934    /**
12935     * Whether to use Codex in Special:Block form.
12936     *
12937     * @unstable Temporary feature flag, T358153
12938     * @since 1.42
12939     */
12940    public const UseCodexSpecialBlock = [
12941        'default' => false,
12942        'type' => 'boolean',
12943    ];
12944
12945    /**
12946     * Whether to display a confirmation screen during user log out.
12947     *
12948     * @unstable Temporary feature flag, T357484
12949     * @since 1.42
12950     */
12951    public const ShowLogoutConfirmation = [
12952        'default' => false,
12953        'type' => 'boolean',
12954    ];
12955
12956    /**
12957     * Whether to show indicators on a page when it is protected.
12958     *
12959     * @since 1.43
12960     */
12961    public const EnableProtectionIndicators = [
12962        'default' => false,
12963        'type' => 'boolean',
12964    ];
12965
12966    /**
12967     * OutputPipelineStages to add to the DefaultOutputPipeline.
12968     *
12969     * @unstable EXPERIMENTAL
12970     * @since 1.43
12971     */
12972    public const OutputPipelineStages = [
12973        'default' => [],
12974        'type' => 'map',
12975    ];
12976    // endregion -- End Miscellaneous
12977
12978}