Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
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 | |
| 7 | use MediaWiki\FileRepo\FileRepo; |
| 8 | use MediaWiki\FileRepo\ForeignAPIRepo; |
| 9 | use MediaWiki\FileRepo\ForeignDBRepo; |
| 10 | use MediaWiki\Language\LanguageCode; |
| 11 | use MediaWiki\Logging\LogFormatter; |
| 12 | use MediaWiki\Logging\NewUsersLogFormatter; |
| 13 | use MediaWiki\Logging\PageLangLogFormatter; |
| 14 | use MediaWiki\MainConfigSchema; |
| 15 | use MediaWiki\Title\NamespaceInfo; |
| 16 | use 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. |
| 21 | if ( $wgLogos !== false && isset( $wgLogos['1x'] ) ) { |
| 22 | $wgLogo = $wgLogos['1x']; |
| 23 | } |
| 24 | |
| 25 | // Back-compat |
| 26 | if ( isset( $wgFileBlacklist ) ) { |
| 27 | $wgProhibitedFileExtensions = array_merge( $wgProhibitedFileExtensions, $wgFileBlacklist ); |
| 28 | } else { |
| 29 | $wgFileBlacklist = $wgProhibitedFileExtensions; |
| 30 | } |
| 31 | if ( isset( $wgMimeTypeBlacklist ) ) { |
| 32 | $wgMimeTypeExclusions = array_merge( $wgMimeTypeExclusions, $wgMimeTypeBlacklist ); |
| 33 | } else { |
| 34 | $wgMimeTypeBlacklist = $wgMimeTypeExclusions; |
| 35 | } |
| 36 | if ( isset( $wgEnableUserEmailBlacklist ) ) { |
| 37 | $wgEnableUserEmailMuteList = $wgEnableUserEmailBlacklist; |
| 38 | } else { |
| 39 | $wgEnableUserEmailBlacklist = $wgEnableUserEmailMuteList; |
| 40 | } |
| 41 | if ( isset( $wgShortPagesNamespaceBlacklist ) ) { |
| 42 | $wgShortPagesNamespaceExclusions = $wgShortPagesNamespaceBlacklist; |
| 43 | } else { |
| 44 | $wgShortPagesNamespaceBlacklist = $wgShortPagesNamespaceExclusions; |
| 45 | } |
| 46 | |
| 47 | // Rate limits should have the same name as the corresponding permission |
| 48 | if ( 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 |
| 58 | if ( 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 |
| 72 | if ( $wgRightsIcon ) { |
| 73 | $wgRightsIcon = str_replace( |
| 74 | "{$wgStylePath}/common/images/", |
| 75 | "{$wgResourceBasePath}/resources/assets/licenses/", |
| 76 | $wgRightsIcon |
| 77 | ); |
| 78 | } |
| 79 | |
| 80 | if ( 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 | |
| 92 | if ( 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 | |
| 153 | if ( 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 | */ |
| 162 | if ( $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 | } |
| 197 | if ( $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 | } |
| 211 | foreach ( $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 | } |
| 219 | unset( $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 | ); |
| 231 | unset( $rcMaxAgeDays ); |
| 232 | |
| 233 | $wgCookiePrefix = strtr( $wgCookiePrefix, '=,; +."\'\\[', '__________' ); |
| 234 | |
| 235 | if ( !$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 | |
| 252 | if ( !$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 |
| 276 | if ( 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 |
| 290 | foreach ( 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 | } |
| 296 | unset( $code ); // no global pollution; destroy reference |
| 297 | unset( $bcp47 ); // no global pollution; destroy reference |
| 298 | if ( $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 | |
| 305 | if ( 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 | |
| 317 | if ( 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 | |
| 329 | if ( $wgInvalidateCacheOnLocalSettingsChange && defined( 'MW_CONFIG_FILE' ) ) { |
| 330 | AtEase::suppressWarnings(); |
| 331 | $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', filemtime( MW_CONFIG_FILE ) ) ); |
| 332 | AtEase::restoreWarnings(); |
| 333 | } |
| 334 | |
| 335 | if ( $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 | |
| 372 | if ( $wgPageCreationLog ) { |
| 373 | // Add page creation log type |
| 374 | $wgLogTypes[] = 'create'; |
| 375 | $wgLogActionsHandlers['create/create'] = LogFormatter::class; |
| 376 | } |
| 377 | |
| 378 | if ( $wgPageLanguageUseDB ) { |
| 379 | $wgLogTypes[] = 'pagelang'; |
| 380 | $wgLogActionsHandlers['pagelang/pagelang'] = [ |
| 381 | 'class' => PageLangLogFormatter::class, |
| 382 | 'services' => [ |
| 383 | 'LanguageNameUtils', |
| 384 | ] |
| 385 | ]; |
| 386 | } |
| 387 | |
| 388 | if ( $wgPHPSessionHandling !== 'enable' && |
| 389 | $wgPHPSessionHandling !== 'warn' && |
| 390 | $wgPHPSessionHandling !== 'disable' |
| 391 | ) { |
| 392 | $wgPHPSessionHandling = 'warn'; |
| 393 | } |
| 394 | if ( 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 |
| 401 | if ( !$wgVirtualDomainsMapping ) { |
| 402 | $wgVirtualDomainsMapping = []; |
| 403 | } |
| 404 | if ( $wgBotPasswordsCluster ) { |
| 405 | $wgVirtualDomainsMapping['virtual-botpasswords']['cluster'] = $wgBotPasswordsCluster; |
| 406 | } |
| 407 | |
| 408 | if ( $wgBotPasswordsDatabase ) { |
| 409 | $wgVirtualDomainsMapping['virtual-botpasswords']['db'] = $wgBotPasswordsDatabase; |
| 410 | } |