wikimedia/mediawiki-core

View on GitHub
includes/SetupDynamicConfig.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
/**
 * This is included by Setup.php to adjust the values of globals before services are initialized.
 * It's split into a separate file so it can be tested.
 */

use MediaWiki\MainConfigSchema;
use MediaWiki\Title\NamespaceInfo;
use Wikimedia\AtEase\AtEase;

// For backwards compatibility, the value of wgLogos is copied to wgLogo.
// This is because some extensions/skins may be using $config->get('Logo')
// to access the value.
if ( $wgLogos !== false && isset( $wgLogos['1x'] ) ) {
    $wgLogo = $wgLogos['1x'];
}

// Back-compat
if ( isset( $wgFileBlacklist ) ) {
    $wgProhibitedFileExtensions = array_merge( $wgProhibitedFileExtensions, $wgFileBlacklist );
} else {
    $wgFileBlacklist = $wgProhibitedFileExtensions;
}
if ( isset( $wgMimeTypeBlacklist ) ) {
    $wgMimeTypeExclusions = array_merge( $wgMimeTypeExclusions, $wgMimeTypeBlacklist );
} else {
    $wgMimeTypeBlacklist = $wgMimeTypeExclusions;
}
if ( isset( $wgEnableUserEmailBlacklist ) ) {
    $wgEnableUserEmailMuteList = $wgEnableUserEmailBlacklist;
} else {
    $wgEnableUserEmailBlacklist = $wgEnableUserEmailMuteList;
}
if ( isset( $wgShortPagesNamespaceBlacklist ) ) {
    $wgShortPagesNamespaceExclusions = $wgShortPagesNamespaceBlacklist;
} else {
    $wgShortPagesNamespaceBlacklist = $wgShortPagesNamespaceExclusions;
}

// Rate limits should have the same name as the corresponding permission
if ( isset( $wgRateLimits['emailuser'] ) ) {
    // If the deprecated field is set, use it.
    // Note that we can't know whether the new field has been set explicitly, since it has a default value.
    $wgSettings->warning(
        'RateLimit: The "emailuser" limit is deprecated, use "sendemail" instead.'
    );
    $wgRateLimits['sendemail'] = $wgRateLimits['emailuser'];
}

// Rate limits should have the same name as the corresponding permission
if ( isset( $wgRateLimits['changetag'] ) ) {
    // If the deprecated field is set, use it.
    // Note that we can't know whether the new field has been set explicitly, since it has a default value.
    $wgSettings->warning(
        'RateLimit: The "changetag" limit is deprecated, use "changetags" instead.'
    );
    $wgRateLimits['changetags'] = $wgRateLimits['changetag'];
}

// Prohibited file extensions shouldn't appear on the "allowed" list
// @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal False positive
$wgFileExtensions = array_values( array_diff( $wgFileExtensions, $wgProhibitedFileExtensions ) );

// Fix path to icon images after they were moved in 1.24
if ( $wgRightsIcon ) {
    $wgRightsIcon = str_replace(
        "{$wgStylePath}/common/images/",
        "{$wgResourceBasePath}/resources/assets/licenses/",
        $wgRightsIcon
    );
}

if ( isset( $wgFooterIcons['copyright']['copyright'] )
    && $wgFooterIcons['copyright']['copyright'] === []
) {
    if ( $wgRightsIcon || $wgRightsText ) {
        $wgFooterIcons['copyright']['copyright'] = [
            'url' => $wgRightsUrl,
            'src' => $wgRightsIcon,
            'alt' => $wgRightsText,
        ];
    }
}

if ( isset( $wgFooterIcons['poweredby'] )
    && isset( $wgFooterIcons['poweredby']['mediawiki'] )
    && is_array( $wgFooterIcons['poweredby']['mediawiki'] )
    && $wgFooterIcons['poweredby']['mediawiki']['src'] === null
) {
    $wgFooterIcons['poweredby']['mediawiki']['src'] =
        "$wgResourceBasePath/resources/assets/poweredby_mediawiki.svg";
}

// Unconditional protection for NS_MEDIAWIKI since otherwise it's too easy for a
// sysadmin to set $wgNamespaceProtection incorrectly and leave the wiki insecure.
//
// Note that this is the definition of editinterface and it can be granted to
// all users if desired.
$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';

// Initialise $wgLockManagers to include basic FS version
$wgLockManagers[] = [
    'name' => 'fsLockManager',
    'class' => FSLockManager::class,
    'lockDirectory' => "{$wgUploadDirectory}/lockdir",
];
$wgLockManagers[] = [
    'name' => 'nullLockManager',
    'class' => NullLockManager::class,
];

// Default parameters for the "<gallery>" tag.
// See \MediaWiki\MainConfigSchema::GalleryOptions
$wgGalleryOptions += [
    'imagesPerRow' => 0,
    'imageWidth' => 120,
    'imageHeight' => 120,
    'captionLength' => true,
    'showBytes' => true,
    'showDimensions' => true,
    'mode' => 'traditional',
];

if ( isset( $wgLocalFileRepo['name'] ) && !isset( $wgLocalFileRepo['backend'] ) ) {
    // Create a default FileBackend name.
    // FileBackendGroup will register a default, if absent from $wgFileBackends.
    $wgLocalFileRepo['backend'] = $wgLocalFileRepo['name'] . '-backend';
}

/**
 * Shortcuts for $wgForeignFileRepos
 */
if ( $wgUseSharedUploads ) {
    if ( $wgSharedUploadDBname ) {
        $wgForeignFileRepos[] = [
            'class' => ForeignDBRepo::class,
            'name' => 'shared',
            'directory' => $wgSharedUploadDirectory,
            'url' => $wgSharedUploadPath,
            'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
            'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
            'transformVia404' => !$wgGenerateThumbnailOnParse,
            'dbType' => $wgDBtype,
            'dbServer' => $wgDBserver,
            'dbUser' => $wgDBuser,
            'dbPassword' => $wgDBpassword,
            'dbName' => $wgSharedUploadDBname,
            'dbFlags' => ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT,
            'tablePrefix' => $wgSharedUploadDBprefix,
            'hasSharedCache' => $wgCacheSharedUploads,
            'descBaseUrl' => $wgRepositoryBaseUrl,
            'fetchDescription' => $wgFetchCommonsDescriptions,
        ];
    } else {
        $wgForeignFileRepos[] = [
            'class' => FileRepo::class,
            'name' => 'shared',
            'directory' => $wgSharedUploadDirectory,
            'url' => $wgSharedUploadPath,
            'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
            'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
            'transformVia404' => !$wgGenerateThumbnailOnParse,
            'descBaseUrl' => $wgRepositoryBaseUrl,
            'fetchDescription' => $wgFetchCommonsDescriptions,
        ];
    }
}
if ( $wgUseInstantCommons ) {
    $wgForeignFileRepos[] = [
        'class' => ForeignAPIRepo::class,
        'name' => 'wikimediacommons',
        'apibase' => 'https://commons.wikimedia.org/w/api.php',
        'url' => 'https://upload.wikimedia.org/wikipedia/commons',
        'thumbUrl' => 'https://upload.wikimedia.org/wikipedia/commons/thumb',
        'hashLevels' => 2,
        'transformVia404' => true,
        'fetchDescription' => true,
        'descriptionCacheExpiry' => 43200,
        'apiThumbCacheExpiry' => 0,
    ];
}
foreach ( $wgForeignFileRepos as &$repo ) {
    if ( !isset( $repo['directory'] ) && $repo['class'] === ForeignAPIRepo::class ) {
        $repo['directory'] = $wgUploadDirectory; // b/c
    }
    if ( !isset( $repo['backend'] ) ) {
        $repo['backend'] = $repo['name'] . '-backend';
    }
}
unset( $repo ); // no global pollution; destroy reference

$rcMaxAgeDays = $wgRCMaxAge / ( 3600 * 24 );
// Ensure that default user options are not invalid, since that breaks Special:Preferences
$wgDefaultUserOptions['rcdays'] = min(
    $wgDefaultUserOptions['rcdays'],
    ceil( $rcMaxAgeDays )
);
$wgDefaultUserOptions['watchlistdays'] = min(
    $wgDefaultUserOptions['watchlistdays'],
    ceil( $rcMaxAgeDays )
);
unset( $rcMaxAgeDays );

$wgCookiePrefix = strtr( $wgCookiePrefix, '=,; +."\'\\[', '__________' );

if ( !$wgEnableEmail ) {
    // Disable all other email settings automatically if $wgEnableEmail
    // is set to false. - T65678
    $wgAllowHTMLEmail = false;
    $wgEmailAuthentication = false; // do not require auth if you're not sending email anyway
    $wgEnableUserEmail = false;
    $wgEnotifFromEditor = false;
    $wgEnotifImpersonal = false;
    $wgEnotifMaxRecips = 0;
    $wgEnotifMinorEdits = false;
    $wgEnotifRevealEditorAddress = false;
    $wgEnotifUseRealName = false;
    $wgEnotifUserTalk = false;
    $wgEnotifWatchlist = false;
    unset( $wgGroupPermissions['user']['sendemail'] );
    $wgUserEmailUseReplyTo = false;
    $wgUsersNotifiedOnAllChanges = [];
}

if ( !$wgLocaltimezone ) {
    // NOTE: The automatic dynamic default only kicks in if $wgLocaltimezone is null,
    //       but the installer writes $wgLocaltimezone into LocalSettings, and may
    //       produce (or may have produced historically) an empty string for some
    //       reason. To be compatible with existing LocalSettings.php files, we need
    //       to gracefully handle the case of $wgLocaltimezone being the empty string.
    //       See T305093#8063451.
    $wgLocaltimezone = MainConfigSchema::getDefaultLocaltimezone();
    $wgSettings->warning(
        'The Localtimezone setting must a valid timezone string or null. '
        . 'It must not be an empty string or false.'
    );
}

// The part after the System| is ignored, but rest of MW fills it out as the local offset.
$wgDefaultUserOptions['timecorrection'] = "System|$wgLocalTZoffset";

/**
 * Definitions of the NS_ constants are in Defines.php
 * @internal
 */
$wgCanonicalNamespaceNames = NamespaceInfo::CANONICAL_NAMES;

// Hard-deprecate setting $wgDummyLanguageCodes in LocalSettings.php
if ( count( $wgDummyLanguageCodes ) !== 0 ) {
    $wgSettings->warning(
        'Do not add to DummyLanguageCodes directly, ' .
        'add to ExtraLanguageCodes instead.'
    );
}
// Merge in the legacy language codes, incorporating overrides from the config
$wgDummyLanguageCodes += [
    // Internal language codes of the private-use area which get mapped to
    // themselves.
    'qqq' => 'qqq', // Used for message documentation
    'qqx' => 'qqx', // Used for viewing message keys
] + $wgExtraLanguageCodes + LanguageCode::getDeprecatedCodeMapping();
// Merge in (inverted) BCP 47 mappings
foreach ( LanguageCode::getNonstandardLanguageCodeMapping() as $code => $bcp47 ) {
    $bcp47 = strtolower( $bcp47 ); // force case-insensitivity
    if ( !isset( $wgDummyLanguageCodes[$bcp47] ) ) {
        $wgDummyLanguageCodes[$bcp47] = $wgDummyLanguageCodes[$code] ?? $code;
    }
}
unset( $code ); // no global pollution; destroy reference
unset( $bcp47 ); // no global pollution; destroy reference
if ( $wgUseXssLanguage ) {
    $wgDummyLanguageCodes['x-xss'] = 'x-xss'; // Used for testing
}

// Temporary backwards-compatibility reading of old replica lag settings as of MediaWiki 1.36,
// to support sysadmins who fail to update their settings immediately:

if ( isset( $wgSlaveLagWarning ) ) {
    // If the old value is set to something other than the default, use it.
    if ( $wgDatabaseReplicaLagWarning === 10 && $wgSlaveLagWarning !== 10 ) {
        $wgDatabaseReplicaLagWarning = $wgSlaveLagWarning;
        $wgSettings->warning( 'SlaveLagWarning is no longer supported, ' .
            'use DatabaseReplicaLagWarning instead!' );
    }
} else {
    // Backwards-compatibility for extensions that read this value.
    $wgSlaveLagWarning = $wgDatabaseReplicaLagWarning;
}

if ( isset( $wgSlaveLagCritical ) ) {
    // If the old value is set to something other than the default, use it.
    if ( $wgDatabaseReplicaLagCritical === 30 && $wgSlaveLagCritical !== 30 ) {
        $wgDatabaseReplicaLagCritical = $wgSlaveLagCritical;
        $wgSettings->warning( 'SlaveLagCritical is no longer supported, ' .
            'use DatabaseReplicaLagCritical instead!' );
    }
} else {
    // Backwards-compatibility for extensions that read this value.
    $wgSlaveLagCritical = $wgDatabaseReplicaLagCritical;
}

if ( $wgInvalidateCacheOnLocalSettingsChange && defined( 'MW_CONFIG_FILE' ) ) {
    AtEase::suppressWarnings();
    $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', filemtime( MW_CONFIG_FILE ) ) );
    AtEase::restoreWarnings();
}

if ( $wgNewUserLog ) {
    // Add new user log type
    $wgLogTypes[] = 'newusers';
    $wgLogNames['newusers'] = 'newuserlogpage';
    $wgLogHeaders['newusers'] = 'newuserlogpagetext';
    $wgLogActionsHandlers['newusers/newusers'] = NewUsersLogFormatter::class;
    $wgLogActionsHandlers['newusers/create'] = NewUsersLogFormatter::class;
    $wgLogActionsHandlers['newusers/create2'] = NewUsersLogFormatter::class;
    $wgLogActionsHandlers['newusers/byemail'] = NewUsersLogFormatter::class;
    $wgLogActionsHandlers['newusers/autocreate'] = NewUsersLogFormatter::class;
}

if ( $wgPageCreationLog ) {
    // Add page creation log type
    $wgLogTypes[] = 'create';
    $wgLogActionsHandlers['create/create'] = LogFormatter::class;
}

if ( $wgPageLanguageUseDB ) {
    $wgLogTypes[] = 'pagelang';
    $wgLogActionsHandlers['pagelang/pagelang'] = [
        'class' => PageLangLogFormatter::class,
        'services' => [
            'LanguageNameUtils',
        ]
    ];
}

if ( $wgPHPSessionHandling !== 'enable' &&
    $wgPHPSessionHandling !== 'warn' &&
    $wgPHPSessionHandling !== 'disable'
) {
    $wgPHPSessionHandling = 'warn';
}
if ( defined( 'MW_NO_SESSION' ) ) {
    // If the entry point wants no session, force 'disable' here unless they
    // specifically set it to the (undocumented) 'warn'.
    $wgPHPSessionHandling = MW_NO_SESSION === 'warn' ? 'warn' : 'disable';
}

// Backwards compatibility with old bot passwords storage configs
if ( !$wgVirtualDomainsMapping ) {
    $wgVirtualDomainsMapping = [];
}
if ( $wgBotPasswordsCluster ) {
    $wgVirtualDomainsMapping['virtual-botpasswords']['cluster'] = $wgBotPasswordsCluster;
}

if ( $wgBotPasswordsDatabase ) {
    $wgVirtualDomainsMapping['virtual-botpasswords']['db'] = $wgBotPasswordsDatabase;
}