Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 260
n/a
0 / 0
CRAP
n/a
0 / 0
1<?php
2/**
3 * This is included by Setup.php to adjust the values of globals before services are initialized.
4 * It's split into a separate file so it can be tested.
5 */
6
7use MediaWiki\FileRepo\FileRepo;
8use MediaWiki\FileRepo\ForeignAPIRepo;
9use MediaWiki\FileRepo\ForeignDBRepo;
10use MediaWiki\Language\LanguageCode;
11use MediaWiki\Logging\LogFormatter;
12use MediaWiki\Logging\NewUsersLogFormatter;
13use MediaWiki\Logging\PageLangLogFormatter;
14use MediaWiki\MainConfigSchema;
15use MediaWiki\Title\NamespaceInfo;
16use Wikimedia\AtEase\AtEase;
17
18// For backwards compatibility, the value of wgLogos is copied to wgLogo.
19// This is because some extensions/skins may be using $config->get('Logo')
20// to access the value.
21if ( $wgLogos !== false && isset( $wgLogos['1x'] ) ) {
22    $wgLogo = $wgLogos['1x'];
23}
24
25// Back-compat
26if ( isset( $wgFileBlacklist ) ) {
27    $wgProhibitedFileExtensions = array_merge( $wgProhibitedFileExtensions, $wgFileBlacklist );
28} else {
29    $wgFileBlacklist = $wgProhibitedFileExtensions;
30}
31if ( isset( $wgMimeTypeBlacklist ) ) {
32    $wgMimeTypeExclusions = array_merge( $wgMimeTypeExclusions, $wgMimeTypeBlacklist );
33} else {
34    $wgMimeTypeBlacklist = $wgMimeTypeExclusions;
35}
36if ( isset( $wgEnableUserEmailBlacklist ) ) {
37    $wgEnableUserEmailMuteList = $wgEnableUserEmailBlacklist;
38} else {
39    $wgEnableUserEmailBlacklist = $wgEnableUserEmailMuteList;
40}
41if ( isset( $wgShortPagesNamespaceBlacklist ) ) {
42    $wgShortPagesNamespaceExclusions = $wgShortPagesNamespaceBlacklist;
43} else {
44    $wgShortPagesNamespaceBlacklist = $wgShortPagesNamespaceExclusions;
45}
46
47// Rate limits should have the same name as the corresponding permission
48if ( isset( $wgRateLimits['emailuser'] ) ) {
49    // If the deprecated field is set, use it.
50    // Note that we can't know whether the new field has been set explicitly, since it has a default value.
51    $wgSettings->warning(
52        'RateLimit: The "emailuser" limit is deprecated, use "sendemail" instead.'
53    );
54    $wgRateLimits['sendemail'] = $wgRateLimits['emailuser'];
55}
56
57// Rate limits should have the same name as the corresponding permission
58if ( isset( $wgRateLimits['changetag'] ) ) {
59    // If the deprecated field is set, use it.
60    // Note that we can't know whether the new field has been set explicitly, since it has a default value.
61    $wgSettings->warning(
62        'RateLimit: The "changetag" limit is deprecated, use "changetags" instead.'
63    );
64    $wgRateLimits['changetags'] = $wgRateLimits['changetag'];
65}
66
67// Prohibited file extensions shouldn't appear on the "allowed" list
68// @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal False positive
69$wgFileExtensions = array_values( array_diff( $wgFileExtensions, $wgProhibitedFileExtensions ) );
70
71// Fix path to icon images after they were moved in 1.24
72if ( $wgRightsIcon ) {
73    $wgRightsIcon = str_replace(
74        "{$wgStylePath}/common/images/",
75        "{$wgResourceBasePath}/resources/assets/licenses/",
76        $wgRightsIcon
77    );
78}
79
80if ( isset( $wgFooterIcons['copyright']['copyright'] )
81    && $wgFooterIcons['copyright']['copyright'] === []
82) {
83    if ( $wgRightsIcon || $wgRightsText ) {
84        $wgFooterIcons['copyright']['copyright'] = [
85            'url' => $wgRightsUrl,
86            'src' => $wgRightsIcon,
87            'alt' => $wgRightsText,
88        ];
89    }
90}
91
92if ( isset( $wgFooterIcons['poweredby'] )
93    && isset( $wgFooterIcons['poweredby']['mediawiki'] )
94    && is_array( $wgFooterIcons['poweredby']['mediawiki'] )
95    && $wgFooterIcons['poweredby']['mediawiki']['src'] === null
96) {
97    $compactLogo = "$wgResourceBasePath/resources/assets/mediawiki_compact.svg";
98    $wgFooterIcons['poweredby']['mediawiki']['sources'] = [
99        [
100            "media" => "(min-width: 500px)",
101            "srcset" => "$wgResourceBasePath/resources/assets/poweredby_mediawiki.svg",
102            "width" => 88,
103            "height" => 31,
104        ]
105    ];
106    $wgFooterIcons['poweredby']['mediawiki']['src'] = $compactLogo;
107    $wgFooterIcons['poweredby']['mediawiki']['width'] = 25;
108    $wgFooterIcons['poweredby']['mediawiki']['height'] = 25;
109}
110
111// Unconditional protection for NS_MEDIAWIKI since otherwise it's too easy for a
112// sysadmin to set $wgNamespaceProtection incorrectly and leave the wiki insecure.
113//
114// Note that this is the definition of editinterface and it can be granted to
115// all users if desired.
116$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
117
118// Initialise $wgLockManagers to include basic FS version
119$wgLockManagers[] = [
120    'name' => 'fsLockManager',
121    'class' => FSLockManager::class,
122    'lockDirectory' => "{$wgUploadDirectory}/lockdir",
123];
124$wgLockManagers[] = [
125    'name' => 'nullLockManager',
126    'class' => NullLockManager::class,
127];
128
129// Default parameters for the "<gallery>" tag.
130// See \MediaWiki\MainConfigSchema::GalleryOptions
131$wgGalleryOptions += [
132    'imagesPerRow' => 0,
133    'imageWidth' => 120,
134    'imageHeight' => 120,
135    'captionLength' => true,
136    'showBytes' => true,
137    'showDimensions' => true,
138    'mode' => 'traditional',
139];
140
141$wgLocalFileRepo['directory'] ??= $wgUploadDirectory;
142$wgLocalFileRepo['scriptDirUrl'] ??= $wgScriptPath;
143$wgLocalFileRepo['favicon'] ??= $wgFavicon;
144$wgLocalFileRepo['url'] ??= ( $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath );
145$wgLocalFileRepo['hashLevels'] ??= ( $wgHashedUploadDirectory ? 2 : 0 );
146$wgLocalFileRepo['thumbScriptUrl'] ??= $wgThumbnailScriptPath;
147$wgLocalFileRepo['transformVia404'] ??= !$wgGenerateThumbnailOnParse;
148$wgLocalFileRepo['deletedDir'] ??= $wgDeletedDirectory;
149$wgLocalFileRepo['deletedHashLevels'] ??= ( $wgHashedUploadDirectory ? 3 : 0 );
150$wgLocalFileRepo['updateCompatibleMetadata'] ??= $wgUpdateCompatibleMetadata;
151$wgLocalFileRepo['reserializeMetadata'] ??= $wgUpdateCompatibleMetadata;
152
153if ( isset( $wgLocalFileRepo['name'] ) && !isset( $wgLocalFileRepo['backend'] ) ) {
154    // Create a default FileBackend name.
155    // FileBackendGroup will register a default, if absent from $wgFileBackends.
156    $wgLocalFileRepo['backend'] = $wgLocalFileRepo['name'] . '-backend';
157}
158
159/**
160 * Shortcuts for $wgForeignFileRepos
161 */
162if ( $wgUseSharedUploads ) {
163    if ( $wgSharedUploadDBname ) {
164        $wgForeignFileRepos[] = [
165            'class' => ForeignDBRepo::class,
166            'name' => 'shared',
167            'directory' => $wgSharedUploadDirectory,
168            'url' => $wgSharedUploadPath,
169            'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
170            'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
171            'transformVia404' => !$wgGenerateThumbnailOnParse,
172            'dbType' => $wgDBtype,
173            'dbServer' => $wgDBserver,
174            'dbUser' => $wgDBuser,
175            'dbPassword' => $wgDBpassword,
176            'dbName' => $wgSharedUploadDBname,
177            'dbFlags' => ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT,
178            'tablePrefix' => $wgSharedUploadDBprefix,
179            'hasSharedCache' => $wgCacheSharedUploads,
180            'descBaseUrl' => $wgRepositoryBaseUrl,
181            'fetchDescription' => $wgFetchCommonsDescriptions,
182        ];
183    } else {
184        $wgForeignFileRepos[] = [
185            'class' => FileRepo::class,
186            'name' => 'shared',
187            'directory' => $wgSharedUploadDirectory,
188            'url' => $wgSharedUploadPath,
189            'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
190            'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
191            'transformVia404' => !$wgGenerateThumbnailOnParse,
192            'descBaseUrl' => $wgRepositoryBaseUrl,
193            'fetchDescription' => $wgFetchCommonsDescriptions,
194        ];
195    }
196}
197if ( $wgUseInstantCommons ) {
198    $wgForeignFileRepos[] = [
199        'class' => ForeignAPIRepo::class,
200        'name' => 'wikimediacommons',
201        'apibase' => 'https://commons.wikimedia.org/w/api.php',
202        'url' => 'https://upload.wikimedia.org/wikipedia/commons',
203        'thumbUrl' => 'https://upload.wikimedia.org/wikipedia/commons/thumb',
204        'hashLevels' => 2,
205        'transformVia404' => true,
206        'fetchDescription' => true,
207        'descriptionCacheExpiry' => 43200,
208        'apiThumbCacheExpiry' => 0,
209    ];
210}
211foreach ( $wgForeignFileRepos as &$repo ) {
212    if ( !isset( $repo['directory'] ) && $repo['class'] === ForeignAPIRepo::class ) {
213        $repo['directory'] = $wgUploadDirectory; // b/c
214    }
215    if ( !isset( $repo['backend'] ) ) {
216        $repo['backend'] = $repo['name'] . '-backend';
217    }
218}
219unset( $repo ); // no global pollution; destroy reference
220
221$rcMaxAgeDays = $wgRCMaxAge / ( 3600 * 24 );
222// Ensure that default user options are not invalid, since that breaks Special:Preferences
223$wgDefaultUserOptions['rcdays'] = min(
224    $wgDefaultUserOptions['rcdays'],
225    ceil( $rcMaxAgeDays )
226);
227$wgDefaultUserOptions['watchlistdays'] = min(
228    $wgDefaultUserOptions['watchlistdays'],
229    ceil( $rcMaxAgeDays )
230);
231unset( $rcMaxAgeDays );
232
233$wgCookiePrefix = strtr( $wgCookiePrefix, '=,; +."\'\\[', '__________' );
234
235if ( !$wgEnableEmail ) {
236    // Disable all other email settings automatically if $wgEnableEmail
237    // is set to false. - T65678
238    $wgAllowHTMLEmail = false;
239    $wgEmailAuthentication = false; // do not require auth if you're not sending email anyway
240    $wgEnableUserEmail = false;
241    $wgEnotifFromEditor = false;
242    $wgEnotifMinorEdits = false;
243    $wgEnotifRevealEditorAddress = false;
244    $wgEnotifUseRealName = false;
245    $wgEnotifUserTalk = false;
246    $wgEnotifWatchlist = false;
247    unset( $wgGroupPermissions['user']['sendemail'] );
248    $wgUserEmailUseReplyTo = false;
249    $wgUsersNotifiedOnAllChanges = [];
250}
251
252if ( !$wgLocaltimezone ) {
253    // NOTE: The automatic dynamic default only kicks in if $wgLocaltimezone is null,
254    //       but the installer writes $wgLocaltimezone into LocalSettings, and may
255    //       produce (or may have produced historically) an empty string for some
256    //       reason. To be compatible with existing LocalSettings.php files, we need
257    //       to gracefully handle the case of $wgLocaltimezone being the empty string.
258    //       See T305093#8063451.
259    $wgLocaltimezone = MainConfigSchema::getDefaultLocaltimezone();
260    $wgSettings->warning(
261        'The Localtimezone setting must a valid timezone string or null. '
262        . 'It must not be an empty string or false.'
263    );
264}
265
266// The part after the System| is ignored, but rest of MW fills it out as the local offset.
267$wgDefaultUserOptions['timecorrection'] = "System|$wgLocalTZoffset";
268
269/**
270 * Definitions of the NS_ constants are in Defines.php
271 * @internal
272 */
273$wgCanonicalNamespaceNames = NamespaceInfo::CANONICAL_NAMES;
274
275// Hard-deprecate setting $wgDummyLanguageCodes in LocalSettings.php
276if ( count( $wgDummyLanguageCodes ) !== 0 ) {
277    $wgSettings->warning(
278        'Do not add to DummyLanguageCodes directly, ' .
279        'add to ExtraLanguageCodes instead.'
280    );
281}
282// Merge in the legacy language codes, incorporating overrides from the config
283$wgDummyLanguageCodes += [
284    // Internal language codes of the private-use area which get mapped to
285    // themselves.
286    'qqq' => 'qqq', // Used for message documentation
287    'qqx' => 'qqx', // Used for viewing message keys
288] + $wgExtraLanguageCodes + LanguageCode::getDeprecatedCodeMapping();
289// Merge in (inverted) BCP 47 mappings
290foreach ( LanguageCode::getNonstandardLanguageCodeMapping() as $code => $bcp47 ) {
291    $bcp47 = strtolower( $bcp47 ); // force case-insensitivity
292    if ( !isset( $wgDummyLanguageCodes[$bcp47] ) ) {
293        $wgDummyLanguageCodes[$bcp47] = $wgDummyLanguageCodes[$code] ?? $code;
294    }
295}
296unset( $code ); // no global pollution; destroy reference
297unset( $bcp47 ); // no global pollution; destroy reference
298if ( $wgUseXssLanguage ) {
299    $wgDummyLanguageCodes['x-xss'] = 'x-xss'; // Used for testing
300}
301
302// Temporary backwards-compatibility reading of old replica lag settings as of MediaWiki 1.36,
303// to support sysadmins who fail to update their settings immediately:
304
305if ( isset( $wgSlaveLagWarning ) ) {
306    // If the old value is set to something other than the default, use it.
307    if ( $wgDatabaseReplicaLagWarning === 10 && $wgSlaveLagWarning !== 10 ) {
308        $wgDatabaseReplicaLagWarning = $wgSlaveLagWarning;
309        $wgSettings->warning( 'SlaveLagWarning is no longer supported, ' .
310            'use DatabaseReplicaLagWarning instead!' );
311    }
312} else {
313    // Backwards-compatibility for extensions that read this value.
314    $wgSlaveLagWarning = $wgDatabaseReplicaLagWarning;
315}
316
317if ( isset( $wgSlaveLagCritical ) ) {
318    // If the old value is set to something other than the default, use it.
319    if ( $wgDatabaseReplicaLagCritical === 30 && $wgSlaveLagCritical !== 30 ) {
320        $wgDatabaseReplicaLagCritical = $wgSlaveLagCritical;
321        $wgSettings->warning( 'SlaveLagCritical is no longer supported, ' .
322            'use DatabaseReplicaLagCritical instead!' );
323    }
324} else {
325    // Backwards-compatibility for extensions that read this value.
326    $wgSlaveLagCritical = $wgDatabaseReplicaLagCritical;
327}
328
329if ( $wgInvalidateCacheOnLocalSettingsChange && defined( 'MW_CONFIG_FILE' ) ) {
330    AtEase::suppressWarnings();
331    $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', filemtime( MW_CONFIG_FILE ) ) );
332    AtEase::restoreWarnings();
333}
334
335if ( $wgNewUserLog ) {
336    // Add new user log type
337    $wgLogTypes[] = 'newusers';
338    $wgLogNames['newusers'] = 'newuserlogpage';
339    $wgLogHeaders['newusers'] = 'newuserlogpagetext';
340    $wgLogActionsHandlers['newusers/newusers'] = [
341        'class' => NewUsersLogFormatter::class,
342        'services' => [
343            'NamespaceInfo',
344        ]
345    ];
346    $wgLogActionsHandlers['newusers/create'] = [
347        'class' => NewUsersLogFormatter::class,
348        'services' => [
349            'NamespaceInfo',
350        ]
351    ];
352    $wgLogActionsHandlers['newusers/create2'] = [
353        'class' => NewUsersLogFormatter::class,
354        'services' => [
355            'NamespaceInfo',
356        ]
357    ];
358    $wgLogActionsHandlers['newusers/byemail'] = [
359        'class' => NewUsersLogFormatter::class,
360        'services' => [
361            'NamespaceInfo',
362        ]
363    ];
364    $wgLogActionsHandlers['newusers/autocreate'] = [
365        'class' => NewUsersLogFormatter::class,
366        'services' => [
367            'NamespaceInfo',
368        ]
369    ];
370}
371
372if ( $wgPageCreationLog ) {
373    // Add page creation log type
374    $wgLogTypes[] = 'create';
375    $wgLogActionsHandlers['create/create'] = LogFormatter::class;
376}
377
378if ( $wgPageLanguageUseDB ) {
379    $wgLogTypes[] = 'pagelang';
380    $wgLogActionsHandlers['pagelang/pagelang'] = [
381        'class' => PageLangLogFormatter::class,
382        'services' => [
383            'LanguageNameUtils',
384        ]
385    ];
386}
387
388if ( $wgPHPSessionHandling !== 'enable' &&
389    $wgPHPSessionHandling !== 'warn' &&
390    $wgPHPSessionHandling !== 'disable'
391) {
392    $wgPHPSessionHandling = 'warn';
393}
394if ( defined( 'MW_NO_SESSION' ) ) {
395    // If the entry point wants no session, force 'disable' here unless they
396    // specifically set it to the (undocumented) 'warn'.
397    $wgPHPSessionHandling = MW_NO_SESSION === 'warn' ? 'warn' : 'disable';
398}
399
400// Backwards compatibility with old bot passwords storage configs
401if ( !$wgVirtualDomainsMapping ) {
402    $wgVirtualDomainsMapping = [];
403}
404if ( $wgBotPasswordsCluster ) {
405    $wgVirtualDomainsMapping['virtual-botpasswords']['cluster'] = $wgBotPasswordsCluster;
406}
407
408if ( $wgBotPasswordsDatabase ) {
409    $wgVirtualDomainsMapping['virtual-botpasswords']['db'] = $wgBotPasswordsDatabase;
410}