1209 lines
48 KiB
PHP
1209 lines
48 KiB
PHP
<?php
|
||
|
||
/*
|
||
* This file is part of the TYPO3 CMS project.
|
||
*
|
||
* It is free software; you can redistribute it and/or modify it under
|
||
* the terms of the GNU General Public License, either version 2
|
||
* of the License, or any later version.
|
||
*
|
||
* For the full copyright and license information, please read the
|
||
* LICENSE.txt file that was distributed with this source code.
|
||
*
|
||
* The TYPO3 project - inspiring people to share!
|
||
*/
|
||
|
||
namespace TYPO3\CMS\Core\Service;
|
||
|
||
use TYPO3\CMS\Core\Configuration\ConfigurationManager;
|
||
use TYPO3\CMS\Core\Configuration\Exception\SettingsWriteException;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\Pbkdf2PasswordHash;
|
||
use TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash;
|
||
use TYPO3\CMS\Core\Crypto\Random;
|
||
use TYPO3\CMS\Core\Service\Exception\ConfigurationChangedException;
|
||
use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
|
||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||
|
||
/**
|
||
* Execute "silent" LocalConfiguration upgrades if needed.
|
||
*
|
||
* Some LocalConfiguration settings are obsolete or changed over time.
|
||
* This class handles upgrades of these settings. It is called by
|
||
* the step controller at an early point.
|
||
*
|
||
* Every change is encapsulated in one method and must throw a ConfigurationChangedException
|
||
* if new data is written to LocalConfiguration. This is caught by above
|
||
* step controller to initiate a redirect and start again with adapted configuration.
|
||
*
|
||
* @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
|
||
*/
|
||
class SilentConfigurationUpgradeService
|
||
{
|
||
/**
|
||
* List of obsolete configuration options in LocalConfiguration to be removed
|
||
* Example:
|
||
* // #forge-ticket
|
||
* 'BE/somesetting',
|
||
*/
|
||
protected array $obsoleteLocalConfigurationSettings = [
|
||
// #72400
|
||
'BE/spriteIconGenerator_handler',
|
||
// #72417
|
||
'SYS/lockingMode',
|
||
// #72473
|
||
'FE/secureFormmail',
|
||
'FE/strictFormmail',
|
||
'FE/formmailMaxAttachmentSize',
|
||
// #72337
|
||
'SYS/t3lib_cs_utils',
|
||
'SYS/t3lib_cs_convMethod',
|
||
// #72604
|
||
'SYS/maxFileNameLength',
|
||
// #72602
|
||
'BE/unzip_path',
|
||
// #72615
|
||
'BE/notificationPrefix',
|
||
// #72616
|
||
'BE/XCLASS',
|
||
'FE/XCLASS',
|
||
// #43085
|
||
'GFX/image_processing',
|
||
// #70056
|
||
'SYS/curlUse',
|
||
'SYS/curlProxyNTLM',
|
||
'SYS/curlProxyServer',
|
||
'SYS/curlProxyTunnel',
|
||
'SYS/curlProxyUserPass',
|
||
'SYS/curlTimeout',
|
||
// #75355
|
||
'BE/niceFlexFormXMLtags',
|
||
'BE/compactFlexFormXML',
|
||
// #75625
|
||
'SYS/clearCacheSystem',
|
||
// #77411
|
||
'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_tablecolumns',
|
||
// #77460
|
||
'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_queries',
|
||
// #79513
|
||
'FE/lockHashKeyWords',
|
||
'BE/lockHashKeyWords',
|
||
// #78835
|
||
'SYS/cookieHttpOnly',
|
||
// #71095
|
||
'BE/lang',
|
||
// #80050
|
||
'FE/cHashIncludePageId',
|
||
// #80711
|
||
'FE/noPHPscriptInclude',
|
||
'FE/maxSessionDataSize',
|
||
// #82162
|
||
'SYS/enable_errorDLOG',
|
||
'SYS/enable_exceptionDLOG',
|
||
// #82377
|
||
'EXT/allowSystemInstall',
|
||
// #82421
|
||
'SYS/sqlDebug',
|
||
'SYS/no_pconnect',
|
||
'SYS/setDBinit',
|
||
'SYS/dbClientCompress',
|
||
// #82430
|
||
'SYS/syslogErrorReporting',
|
||
// #82639
|
||
'SYS/enable_DLOG',
|
||
'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLog',
|
||
'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogBE',
|
||
'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogFE',
|
||
// #82438
|
||
'SYS/enableDeprecationLog',
|
||
// #82680
|
||
'GFX/png_truecolor',
|
||
// #82803
|
||
'FE/content_doktypes',
|
||
// #83081
|
||
'BE/fileExtensions',
|
||
// #83768
|
||
'SYS/doNotCheckReferer',
|
||
// #83878
|
||
'SYS/isInitialInstallationInProgress',
|
||
'SYS/isInitialDatabaseImportDone',
|
||
// #84810
|
||
'BE/explicitConfirmationOfTranslation',
|
||
// #87482
|
||
'EXT/extConf',
|
||
// #87767
|
||
'SYS/recursiveDomainSearch',
|
||
// #88376
|
||
'FE/pageNotFound_handling',
|
||
'FE/pageNotFound_handling_statheader',
|
||
'FE/pageNotFound_handling_accessdeniedheader',
|
||
'FE/pageUnavailable_handling',
|
||
'FE/pageUnavailable_handling_statheader',
|
||
// #88458
|
||
'FE/get_url_id_token',
|
||
// #88500
|
||
'BE/RTE_imageStorageDir',
|
||
// #89645
|
||
'SYS/systemLog',
|
||
'SYS/systemLogLevel',
|
||
// #91974
|
||
'FE/IPmaskMountGroups',
|
||
// #87301
|
||
'SYS/cookieSecure',
|
||
// #92940
|
||
'BE/lockBeUserToDBmounts',
|
||
// #92941
|
||
'BE/enabledBeUserIPLock',
|
||
// #94312
|
||
'BE/loginSecurityLevel',
|
||
'FE/loginSecurityLevel',
|
||
// #94871
|
||
'SYS/features/form.legacyUploadMimeTypes',
|
||
// #96550
|
||
'SYS/USdateFormat',
|
||
// #96982
|
||
'EXT/allowGlobalInstall',
|
||
// #96988
|
||
'EXT/allowLocalInstall',
|
||
// #97265
|
||
'BE/explicitADmode',
|
||
// #98179
|
||
'BE/interfaces',
|
||
// Please note that further migrations in this file are kept in order to remove the setting at the very end
|
||
// #97797
|
||
'GFX/processor_path_lzw',
|
||
// #98503
|
||
'SYS/caching/cacheConfigurations/pagesection',
|
||
// #99075
|
||
'FE/defaultUserTSconfig',
|
||
// #101037
|
||
'BE/languageDebug',
|
||
'BE/lang/debug',
|
||
// #101793
|
||
'BE/checkStoredRecords',
|
||
'BE/checkStoredRecordsLoose',
|
||
// #101941
|
||
'GFX/thumbnails_png',
|
||
'GFX/gif_compress',
|
||
// #101950
|
||
'GFX/processor_allowTemporaryMasksAsPng',
|
||
// #102020
|
||
'GFX/gdlib_png',
|
||
// #102023
|
||
'SYS/features/security.usePasswordPolicyForFrontendUsers',
|
||
// #102113
|
||
'GFX/gdlib',
|
||
// #102146
|
||
'BE/flexformForceCDATA',
|
||
// #103752
|
||
'FE/addRootLineFields',
|
||
// #104104
|
||
'EXTENSIONS/indexed_search/debugMode',
|
||
// #101807
|
||
'BE/defaultUserTSconfig',
|
||
// #101799
|
||
'BE/defaultPageTSconfig',
|
||
// #107436
|
||
// symfony/translation loaders used now
|
||
'SYS/lang/parser',
|
||
// #107943
|
||
'BE/compressionLevel',
|
||
// #108055
|
||
'FE/compressionLevel',
|
||
// #108114
|
||
'FE/additionalAbsRefPrefixDirectories',
|
||
// #109959
|
||
'FE/cacheHash/fallbackToLegacyHash',
|
||
// #109986
|
||
'FE/addAllowedPaths',
|
||
];
|
||
|
||
public function __construct(private readonly ConfigurationManager $configurationManager) {}
|
||
|
||
/**
|
||
* Executed configuration upgrades. Single upgrade methods must throw a
|
||
* ConfigurationChangedException if something was written to LocalConfiguration.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
* @throws SettingsWriteException
|
||
*/
|
||
public function execute(): void
|
||
{
|
||
$this->generateEncryptionKeyIfNeeded();
|
||
$this->migrateImageProcessorSetting();
|
||
$this->transferHttpSettings();
|
||
$this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
|
||
$this->setImageMagickDetailSettings();
|
||
$this->removeDefaultColorspaceSettings();
|
||
$this->migrateLockSslSetting();
|
||
$this->migrateDatabaseConnectionSettings();
|
||
$this->migrateDatabaseConnectionCharset();
|
||
$this->migrateDatabaseDriverOptions();
|
||
$this->migrateCacheHashOptions();
|
||
$this->migrateExceptionErrors();
|
||
$this->migrateDisplayErrorsSetting();
|
||
$this->migrateSaltedPasswordsSettings();
|
||
$this->migrateCachingFrameworkCaches();
|
||
$this->migrateMailSettingsToSendmail();
|
||
$this->migrateMailSmtpEncryptSetting();
|
||
$this->migrateVersionNumberInFileNameSetting();
|
||
$this->migrateLanguageSettings();
|
||
|
||
// Should run at the end to prevent obsolete settings are removed before migration
|
||
$this->removeObsoleteLocalConfigurationSettings();
|
||
}
|
||
|
||
/**
|
||
* Throw exception after configuration change to trigger a redirect.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function throwConfigurationChangedException(): void
|
||
{
|
||
throw new ConfigurationChangedException(
|
||
'Configuration updated, reload needed',
|
||
1379024938
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Some settings in LocalConfiguration vanished in DefaultConfiguration
|
||
* and have no impact on the core anymore.
|
||
* To keep the configuration clean, those old settings are just silently
|
||
* removed from LocalConfiguration if set.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function removeObsoleteLocalConfigurationSettings(): void
|
||
{
|
||
$removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
|
||
|
||
// If something was changed: Trigger reload to have new values in next request
|
||
if ($removed) {
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* The encryption key is crucial for securing form tokens
|
||
* and the whole TYPO3 link rendering later on. A random key is set here in
|
||
* LocalConfiguration if it does not exist yet. This might happen
|
||
* during upgrading and will happen during first install.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function generateEncryptionKeyIfNeeded(): void
|
||
{
|
||
try {
|
||
$currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
|
||
} catch (MissingArrayPathException) {
|
||
// If an exception is thrown, the value is not set in LocalConfiguration
|
||
$currentValue = '';
|
||
}
|
||
|
||
if (empty($currentValue)) {
|
||
$randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96);
|
||
$this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Parse old curl and HTTP options and set new HTTP options, related to Guzzle
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function transferHttpSettings(): void
|
||
{
|
||
$changed = false;
|
||
$newParameters = [];
|
||
$obsoleteParameters = [];
|
||
|
||
// Remove / migrate options to new options
|
||
try {
|
||
// Check if the adapter option is set, if so, set it to the parameters that are obsolete
|
||
$this->configurationManager->getLocalConfigurationValueByPath('HTTP/adapter');
|
||
$obsoleteParameters[] = 'HTTP/adapter';
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
try {
|
||
$newParameters['HTTP/version'] = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/protocol_version');
|
||
$obsoleteParameters[] = 'HTTP/protocol_version';
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
try {
|
||
$this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_host');
|
||
$obsoleteParameters[] = 'HTTP/ssl_verify_host';
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
try {
|
||
$legacyUserAgent = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/userAgent');
|
||
$newParameters['HTTP/headers/User-Agent'] = $legacyUserAgent;
|
||
$obsoleteParameters[] = 'HTTP/userAgent';
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
|
||
// Redirects
|
||
try {
|
||
$legacyFollowRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/follow_redirects');
|
||
$obsoleteParameters[] = 'HTTP/follow_redirects';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyFollowRedirects = '';
|
||
}
|
||
try {
|
||
$legacyMaximumRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/max_redirects');
|
||
$obsoleteParameters[] = 'HTTP/max_redirects';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyMaximumRedirects = '';
|
||
}
|
||
try {
|
||
$legacyStrictRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/strict_redirects');
|
||
$obsoleteParameters[] = 'HTTP/strict_redirects';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyStrictRedirects = '';
|
||
}
|
||
|
||
// Check if redirects have been disabled
|
||
if ($legacyFollowRedirects !== '' && (bool)$legacyFollowRedirects === false) {
|
||
$newParameters['HTTP/allow_redirects'] = false;
|
||
} elseif ($legacyMaximumRedirects !== '' || $legacyStrictRedirects !== '') {
|
||
$newParameters['HTTP/allow_redirects'] = [];
|
||
if ($legacyMaximumRedirects !== '' && (int)$legacyMaximumRedirects !== 5) {
|
||
$newParameters['HTTP/allow_redirects']['max'] = (int)$legacyMaximumRedirects;
|
||
}
|
||
if ($legacyStrictRedirects !== '' && (bool)$legacyStrictRedirects === true) {
|
||
$newParameters['HTTP/allow_redirects']['strict'] = true;
|
||
}
|
||
// defaults are used, no need to set the option in system/settings.php
|
||
if (empty($newParameters['HTTP/allow_redirects'])) {
|
||
unset($newParameters['HTTP/allow_redirects']);
|
||
}
|
||
}
|
||
|
||
// Migrate Proxy settings
|
||
try {
|
||
// Currently without protocol or port
|
||
$legacyProxyHost = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_host');
|
||
$obsoleteParameters[] = 'HTTP/proxy_host';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyProxyHost = '';
|
||
}
|
||
try {
|
||
$legacyProxyPort = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_port');
|
||
$obsoleteParameters[] = 'HTTP/proxy_port';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyProxyPort = '';
|
||
}
|
||
try {
|
||
$legacyProxyUser = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_user');
|
||
$obsoleteParameters[] = 'HTTP/proxy_user';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyProxyUser = '';
|
||
}
|
||
try {
|
||
$legacyProxyPassword = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_password');
|
||
$obsoleteParameters[] = 'HTTP/proxy_password';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyProxyPassword = '';
|
||
}
|
||
// Auth Scheme: Basic, digest etc.
|
||
try {
|
||
$legacyProxyAuthScheme = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
|
||
$obsoleteParameters[] = 'HTTP/proxy_auth_scheme';
|
||
} catch (MissingArrayPathException) {
|
||
$legacyProxyAuthScheme = '';
|
||
}
|
||
|
||
if ($legacyProxyHost !== '') {
|
||
$proxy = 'http://';
|
||
if ($legacyProxyAuthScheme !== '' && $legacyProxyUser !== '' && $legacyProxyPassword !== '') {
|
||
$proxy .= $legacyProxyUser . ':' . $legacyProxyPassword . '@';
|
||
}
|
||
$proxy .= $legacyProxyHost;
|
||
if ($legacyProxyPort !== '') {
|
||
$proxy .= ':' . $legacyProxyPort;
|
||
}
|
||
$newParameters['HTTP/proxy'] = $proxy;
|
||
}
|
||
|
||
// Verify peers
|
||
// see http://docs.guzzlephp.org/en/latest/request-options.html#verify
|
||
try {
|
||
$legacySslVerifyPeer = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_peer');
|
||
$obsoleteParameters[] = 'HTTP/ssl_verify_peer';
|
||
} catch (MissingArrayPathException) {
|
||
$legacySslVerifyPeer = '';
|
||
}
|
||
|
||
// Directory holding multiple Certificate Authority files
|
||
try {
|
||
$legacySslCaPath = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_capath');
|
||
$obsoleteParameters[] = 'HTTP/ssl_capath';
|
||
} catch (MissingArrayPathException) {
|
||
$legacySslCaPath = '';
|
||
}
|
||
// Certificate Authority file to verify the peer with (use when ssl_verify_peer is TRUE)
|
||
try {
|
||
$legacySslCaFile = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_cafile');
|
||
$obsoleteParameters[] = 'HTTP/ssl_cafile';
|
||
} catch (MissingArrayPathException) {
|
||
$legacySslCaFile = '';
|
||
}
|
||
if ($legacySslVerifyPeer !== '') {
|
||
if ($legacySslCaFile !== '' && $legacySslCaPath !== '') {
|
||
$newParameters['HTTP/verify'] = $legacySslCaPath . $legacySslCaFile;
|
||
} elseif ((bool)$legacySslVerifyPeer === false) {
|
||
$newParameters['HTTP/verify'] = false;
|
||
}
|
||
}
|
||
|
||
// SSL Key + Passphrase
|
||
// Name of a file containing local certificate
|
||
try {
|
||
$legacySslLocalCert = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_local_cert');
|
||
$obsoleteParameters[] = 'HTTP/ssl_local_cert';
|
||
} catch (MissingArrayPathException) {
|
||
$legacySslLocalCert = '';
|
||
}
|
||
|
||
// Passphrase with which local certificate was encoded
|
||
try {
|
||
$legacySslPassphrase = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_passphrase');
|
||
$obsoleteParameters[] = 'HTTP/ssl_passphrase';
|
||
} catch (MissingArrayPathException) {
|
||
$legacySslPassphrase = '';
|
||
}
|
||
|
||
if ($legacySslLocalCert !== '') {
|
||
if ($legacySslPassphrase !== '') {
|
||
$newParameters['HTTP/ssl_key'] = [
|
||
$legacySslLocalCert,
|
||
$legacySslPassphrase,
|
||
];
|
||
} else {
|
||
$newParameters['HTTP/ssl_key'] = $legacySslLocalCert;
|
||
}
|
||
}
|
||
|
||
// Update the LocalConfiguration file if obsolete parameters or new parameters are set
|
||
if (!empty($obsoleteParameters)) {
|
||
$this->configurationManager->removeLocalConfigurationKeysByPath($obsoleteParameters);
|
||
$changed = true;
|
||
}
|
||
if (!empty($newParameters)) {
|
||
$this->configurationManager->setLocalConfigurationValuesByPathValuePairs($newParameters);
|
||
$changed = true;
|
||
}
|
||
if ($changed) {
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Detail configuration of Image Magick settings must be cleared
|
||
* if Image Magick handling is disabled.
|
||
*
|
||
* "Configuration presets" in install tool is not type safe, so value
|
||
* comparisons here are not type safe too, to not trigger changes to
|
||
* LocalConfiguration again.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled(): void
|
||
{
|
||
$changedValues = [];
|
||
try {
|
||
$currentEnabledValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_enabled');
|
||
} catch (MissingArrayPathException) {
|
||
$currentEnabledValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_enabled');
|
||
}
|
||
|
||
try {
|
||
$currentPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path');
|
||
} catch (MissingArrayPathException) {
|
||
$currentPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path');
|
||
}
|
||
|
||
try {
|
||
$currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
|
||
} catch (MissingArrayPathException) {
|
||
$currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
|
||
}
|
||
|
||
try {
|
||
$currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
|
||
} catch (MissingArrayPathException) {
|
||
$currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
|
||
}
|
||
|
||
if (!$currentEnabledValue) {
|
||
if ($currentPathValue != '') {
|
||
$changedValues['GFX/processor_path'] = '';
|
||
}
|
||
if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
|
||
$changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
|
||
}
|
||
if ($currentThumbnailsValue != 0) {
|
||
$changedValues['GFX/thumbnails'] = 0;
|
||
}
|
||
}
|
||
if (!empty($changedValues)) {
|
||
$this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Detail configuration of Image Magick and Graphics Magick settings
|
||
* depending on main values.
|
||
*
|
||
* "Configuration presets" in install tool is not type safe, so value
|
||
* comparisons here are not type safe too, to not trigger changes to
|
||
* LocalConfiguration again.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function setImageMagickDetailSettings(): void
|
||
{
|
||
$changedValues = [];
|
||
try {
|
||
$currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor');
|
||
} catch (MissingArrayPathException) {
|
||
$currentProcessorValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor');
|
||
}
|
||
|
||
try {
|
||
$currentProcessorEffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_effects');
|
||
} catch (MissingArrayPathException) {
|
||
$currentProcessorEffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_effects');
|
||
}
|
||
|
||
if ((string)$currentProcessorValue !== '') {
|
||
if (!is_bool($currentProcessorEffectsValue)) {
|
||
$changedValues['GFX/processor_effects'] = (int)$currentProcessorEffectsValue > 0;
|
||
}
|
||
}
|
||
if (!empty($changedValues)) {
|
||
$this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate the definition of the image processor from the configuration value
|
||
* im_version_5 to the setting processor.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateImageProcessorSetting(): void
|
||
{
|
||
$changedSettings = [];
|
||
$settingsToRename = [
|
||
'GFX/im' => 'GFX/processor_enabled',
|
||
'GFX/im_version_5' => 'GFX/processor',
|
||
'GFX/im_v5effects' => 'GFX/processor_effects',
|
||
'GFX/im_path' => 'GFX/processor_path',
|
||
'GFX/im_path_lzw' => 'GFX/processor_path_lzw',
|
||
'GFX/im_mask_temp_ext_gif' => 'GFX/processor_allowTemporaryMasksAsPng',
|
||
'GFX/im_noScaleUp' => 'GFX/processor_allowUpscaling',
|
||
'GFX/im_noFramePrepended' => 'GFX/processor_allowFrameSelection',
|
||
'GFX/im_stripProfileCommand' => 'GFX/processor_stripColorProfileCommand',
|
||
'GFX/im_useStripProfileByDefault' => 'GFX/processor_stripColorProfileByDefault',
|
||
'GFX/colorspace' => 'GFX/processor_colorspace',
|
||
];
|
||
|
||
foreach ($settingsToRename as $oldPath => $newPath) {
|
||
try {
|
||
$value = $this->configurationManager->getLocalConfigurationValueByPath($oldPath);
|
||
$this->configurationManager->setLocalConfigurationValueByPath($newPath, $value);
|
||
$changedSettings[$oldPath] = true;
|
||
} catch (MissingArrayPathException) {
|
||
// If an exception is thrown, the value is not set in LocalConfiguration
|
||
$changedSettings[$oldPath] = false;
|
||
}
|
||
}
|
||
|
||
if (!empty($changedSettings['GFX/im_version_5'])) {
|
||
$currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
|
||
$newProcessorValue = $currentProcessorValue === 'gm' ? 'GraphicsMagick' : 'ImageMagick';
|
||
$this->configurationManager->setLocalConfigurationValueByPath('GFX/processor', $newProcessorValue);
|
||
}
|
||
|
||
if (!empty($changedSettings['GFX/im_noScaleUp'])) {
|
||
$currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noScaleUp');
|
||
$newProcessorValue = !$currentProcessorValue;
|
||
$this->configurationManager->setLocalConfigurationValueByPath(
|
||
'GFX/processor_allowUpscaling',
|
||
$newProcessorValue
|
||
);
|
||
}
|
||
|
||
if (!empty($changedSettings['GFX/im_noFramePrepended'])) {
|
||
$currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noFramePrepended');
|
||
$newProcessorValue = !$currentProcessorValue;
|
||
$this->configurationManager->setLocalConfigurationValueByPath(
|
||
'GFX/processor_allowFrameSelection',
|
||
$newProcessorValue
|
||
);
|
||
}
|
||
|
||
if (!empty($changedSettings['GFX/im_mask_temp_ext_gif'])) {
|
||
$currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
|
||
$newProcessorValue = !$currentProcessorValue;
|
||
$this->configurationManager->setLocalConfigurationValueByPath(
|
||
'GFX/processor_allowTemporaryMasksAsPng',
|
||
$newProcessorValue
|
||
);
|
||
}
|
||
|
||
if (!empty(array_filter($changedSettings))) {
|
||
$this->configurationManager->removeLocalConfigurationKeysByPath(array_keys($changedSettings));
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate the configuration setting BE/lockSSL to boolean if set in the system/settings.php file
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateLockSslSetting(): void
|
||
{
|
||
try {
|
||
$currentOption = $this->configurationManager->getLocalConfigurationValueByPath('BE/lockSSL');
|
||
// check if the current option is an integer/string and if it is active
|
||
if (!is_bool($currentOption) && (int)$currentOption > 0) {
|
||
$this->configurationManager->setLocalConfigurationValueByPath('BE/lockSSL', true);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Move the database connection settings to a "Default" connection
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateDatabaseConnectionSettings(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
|
||
$newSettings = [];
|
||
$removeSettings = [];
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/username');
|
||
$removeSettings[] = 'DB/username';
|
||
$newSettings['DB/Connections/Default/user'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/password');
|
||
$removeSettings[] = 'DB/password';
|
||
$newSettings['DB/Connections/Default/password'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/host');
|
||
$removeSettings[] = 'DB/host';
|
||
$newSettings['DB/Connections/Default/host'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/port');
|
||
$removeSettings[] = 'DB/port';
|
||
$newSettings['DB/Connections/Default/port'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/socket');
|
||
$removeSettings[] = 'DB/socket';
|
||
// Remove empty socket connects
|
||
if (!empty($value)) {
|
||
$newSettings['DB/Connections/Default/unix_socket'] = $value;
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('DB/database');
|
||
$removeSettings[] = 'DB/database';
|
||
$newSettings['DB/Connections/Default/dbname'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/dbClientCompress');
|
||
$removeSettings[] = 'SYS/dbClientCompress';
|
||
if ($value) {
|
||
$newSettings['DB/Connections/Default/driverOptions'] = [
|
||
'flags' => MYSQLI_CLIENT_COMPRESS,
|
||
];
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/no_pconnect');
|
||
$removeSettings[] = 'SYS/no_pconnect';
|
||
if (!$value) {
|
||
$newSettings['DB/Connections/Default/persistentConnection'] = true;
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('SYS/setDBinit');
|
||
$removeSettings[] = 'SYS/setDBinit';
|
||
$newSettings['DB/Connections/Default/initCommands'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
try {
|
||
$confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
|
||
} catch (MissingArrayPathException) {
|
||
// If there is no charset option yet, add it.
|
||
$newSettings['DB/Connections/Default/charset'] = 'utf8';
|
||
}
|
||
|
||
try {
|
||
$confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
|
||
} catch (MissingArrayPathException) {
|
||
// Use the mysqli driver by default if no value has been provided yet
|
||
$newSettings['DB/Connections/Default/driver'] = 'mysqli';
|
||
}
|
||
|
||
// Add new settings and remove old ones
|
||
if (!empty($newSettings)) {
|
||
$confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
|
||
}
|
||
if (!empty($removeSettings)) {
|
||
$confManager->removeLocalConfigurationKeysByPath($removeSettings);
|
||
}
|
||
|
||
// Throw redirect if something was changed
|
||
if (!empty($newSettings) || !empty($removeSettings)) {
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate the configuration setting DB/Connections/Default/charset to 'utf8' as
|
||
* 'utf-8' is not supported by all MySQL versions.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateDatabaseConnectionCharset(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$driver = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
|
||
$charset = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
|
||
if (in_array($driver, ['mysqli', 'pdo_mysql', 'drizzle_pdo_mysql'], true) && $charset === 'utf-8') {
|
||
$confManager->setLocalConfigurationValueByPath('DB/Connections/Default/charset', 'utf8');
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no incompatible charset configuration found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate the configuration setting DB/Connections/Default/driverOptions to array type.
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateDatabaseDriverOptions(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$options = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driverOptions');
|
||
if (!is_array($options)) {
|
||
$confManager->setLocalConfigurationValueByPath(
|
||
'DB/Connections/Default/driverOptions',
|
||
['flags' => (int)$options]
|
||
);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no driver options found, nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate single cache hash related options under "FE" into "FE/cacheHash"
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateCacheHashOptions(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
$removeSettings = [];
|
||
$newSettings = [];
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('FE/cHashOnlyForParameters');
|
||
$removeSettings[] = 'FE/cHashOnlyForParameters';
|
||
$newSettings['FE/cacheHash/cachedParametersWhiteList'] = GeneralUtility::trimExplode(',', $value, true);
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParameters');
|
||
$removeSettings[] = 'FE/cHashExcludedParameters';
|
||
$newSettings['FE/cacheHash/excludedParameters'] = GeneralUtility::trimExplode(',', $value, true);
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('FE/cHashRequiredParameters');
|
||
$removeSettings[] = 'FE/cHashRequiredParameters';
|
||
$newSettings['FE/cacheHash/requireCacheHashPresenceParameters'] = GeneralUtility::trimExplode(',', $value, true);
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParametersIfEmpty');
|
||
$removeSettings[] = 'FE/cHashExcludedParametersIfEmpty';
|
||
if (trim($value) === '*') {
|
||
$newSettings['FE/cacheHash/excludeAllEmptyParameters'] = true;
|
||
} else {
|
||
$newSettings['FE/cacheHash/excludedParametersIfEmpty'] = GeneralUtility::trimExplode(',', $value, true);
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// Migration done already
|
||
}
|
||
|
||
// Add new settings and remove old ones
|
||
if (!empty($newSettings)) {
|
||
$confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
|
||
}
|
||
if (!empty($removeSettings)) {
|
||
$confManager->removeLocalConfigurationKeysByPath($removeSettings);
|
||
}
|
||
|
||
// Throw redirect if something was changed
|
||
if (!empty($newSettings) || !empty($removeSettings)) {
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate SYS/exceptionalErrors to not contain E_USER_DEPRECATED
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateExceptionErrors(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/exceptionalErrors');
|
||
// make sure E_USER_DEPRECATED is not part of the exceptionalErrors
|
||
if ($currentOption & E_USER_DEPRECATED) {
|
||
$confManager->setLocalConfigurationValueByPath('SYS/exceptionalErrors', $currentOption & ~E_USER_DEPRECATED);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate SYS/displayErrors to not contain 2
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateDisplayErrorsSetting(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/displayErrors');
|
||
// make sure displayErrors is set to 2
|
||
if ($currentOption === 2) {
|
||
$confManager->setLocalConfigurationValueByPath('SYS/displayErrors', -1);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate salted passwords extension configuration settings to BE/passwordHashing and FE/passwordHashing
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateSaltedPasswordsSettings(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
$configsToRemove = [];
|
||
try {
|
||
$extensionConfiguration = (array)$confManager->getLocalConfigurationValueByPath('EXTENSIONS/saltedpasswords');
|
||
$configsToRemove[] = 'EXTENSIONS/saltedpasswords';
|
||
} catch (MissingArrayPathException) {
|
||
$extensionConfiguration = [];
|
||
}
|
||
// Migration already done
|
||
if (empty($extensionConfiguration)) {
|
||
return;
|
||
}
|
||
// Upgrade to the best available hash method. This is only done once since that code will no longer be reached
|
||
// after first migration because extConf and EXTENSIONS array entries are gone then. Thus, a manual selection
|
||
// to some different hash mechanism will not be touched again after first upgrade.
|
||
// Phpass is always available, so we have some last fallback if the others don't kick in
|
||
$okHashMethods = [
|
||
Argon2iPasswordHash::class,
|
||
Argon2idPasswordHash::class,
|
||
BcryptPasswordHash::class,
|
||
Pbkdf2PasswordHash::class,
|
||
PhpassPasswordHash::class,
|
||
];
|
||
$newMethods = [];
|
||
foreach (['BE', 'FE'] as $mode) {
|
||
foreach ($okHashMethods as $className) {
|
||
/** @var PasswordHashInterface $instance */
|
||
$instance = GeneralUtility::makeInstance($className);
|
||
if ($instance->isAvailable()) {
|
||
$newMethods[$mode] = $className;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
// We only need to write to LocalConfiguration if method is different from Argon2i in DefaultConfiguration
|
||
$newConfig = [];
|
||
if ($newMethods['BE'] !== Argon2iPasswordHash::class) {
|
||
$newConfig['BE/passwordHashing/className'] = $newMethods['BE'];
|
||
}
|
||
if ($newMethods['FE'] !== Argon2iPasswordHash::class) {
|
||
$newConfig['FE/passwordHashing/className'] = $newMethods['FE'];
|
||
}
|
||
if (!empty($newConfig)) {
|
||
$confManager->setLocalConfigurationValuesByPathValuePairs($newConfig);
|
||
}
|
||
$confManager->removeLocalConfigurationKeysByPath($configsToRemove);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
|
||
/**
|
||
* Renames all SYS[caching][cache] configuration names to names without the prefix "cache_".
|
||
* see #88366
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateCachingFrameworkCaches(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$cacheConfigurations = (array)$confManager->getLocalConfigurationValueByPath('SYS/caching/cacheConfigurations');
|
||
$newConfig = [];
|
||
$hasBeenModified = false;
|
||
foreach ($cacheConfigurations as $identifier => $cacheConfiguration) {
|
||
if (str_starts_with($identifier, 'cache_')) {
|
||
$identifier = substr($identifier, 6);
|
||
$hasBeenModified = true;
|
||
}
|
||
$newConfig[$identifier] = $cacheConfiguration;
|
||
}
|
||
|
||
if ($hasBeenModified) {
|
||
$confManager->setLocalConfigurationValueByPath('SYS/caching/cacheConfigurations', $newConfig);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrates "mail" to "sendmail" as "mail" (PHP's built-in mail() method) is not supported anymore
|
||
* with Symfony components.
|
||
* See #88643
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateMailSettingsToSendmail(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$transport = $confManager->getLocalConfigurationValueByPath('MAIL/transport');
|
||
if ($transport === 'mail') {
|
||
$confManager->setLocalConfigurationValueByPath('MAIL/transport', 'sendmail');
|
||
$confManager->setLocalConfigurationValueByPath('MAIL/transport_sendmail_command', (string)@ini_get('sendmail_path'));
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrates MAIL/transport_smtp_encrypt to a boolean value
|
||
* See #91070, #90295, #88643 and https://github.com/symfony/symfony/commit/5b8c4676d059
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateMailSmtpEncryptSetting(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
try {
|
||
$transport = $confManager->getLocalConfigurationValueByPath('MAIL/transport');
|
||
if ($transport === 'smtp') {
|
||
$encrypt = $confManager->getLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt');
|
||
if (is_string($encrypt)) {
|
||
// SwiftMailer used 'tls' as identifier to connect with STARTTLS via SMTP (as usually used with port 587).
|
||
// See https://github.com/swiftmailer/swiftmailer/blob/v5.4.10/lib/classes/Swift/Transport/EsmtpTransport.php#L144
|
||
if ($encrypt === 'tls') {
|
||
// With TYPO3 v10 the MAIL/transport_smtp_encrypt option is passed as constructor parameter $tls to
|
||
// Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport
|
||
// $tls = true instructs to start a SMTPS connection – that means SSL/TLS via SMTPS, not STARTTLS via SMTP.
|
||
// That means symfony/mailer will use STARTTLS when $tls = false or ($tls = null with port != 465) is passed.
|
||
// Actually symfony/mailer will use STARTTLS by default now.
|
||
// Due to the misleading name (transport_smtp_encrypt) we avoid to set the option to false, but rather remove it.
|
||
// Note: symfony/mailer provides no way to enforce STARTTLS usage, see https://github.com/symfony/symfony/commit/5b8c4676d059
|
||
$confManager->removeLocalConfigurationKeysByPath(['MAIL/transport_smtp_encrypt']);
|
||
} elseif ($encrypt === '') {
|
||
$confManager->setLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt', false);
|
||
} else {
|
||
$confManager->setLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt', true);
|
||
}
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate [FE][versionNumberInFilename] to become a boolean flag
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateVersionNumberInFileNameSetting(): void
|
||
{
|
||
try {
|
||
$confManager = $this->configurationManager;
|
||
$currentOption = $confManager->getLocalConfigurationValueByPath('FE/versionNumberInFilename');
|
||
if ($currentOption === true) {
|
||
return;
|
||
}
|
||
if ($currentOption === 'embed') {
|
||
$confManager->setLocalConfigurationValueByPath('FE/versionNumberInFilename', true);
|
||
} else {
|
||
$confManager->removeLocalConfigurationKeysByPath(['FE/versionNumberInFilename']);
|
||
}
|
||
$this->throwConfigurationChangedException();
|
||
} catch (MissingArrayPathException) {
|
||
// no flag set, so nothing to be configured
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Remove the colorspace setting if it's already the recommended default for a given processor
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function removeDefaultColorspaceSettings(): void
|
||
{
|
||
try {
|
||
$confManager = $this->configurationManager;
|
||
$currentProcessor = $confManager->getLocalConfigurationValueByPath('GFX/processor');
|
||
$currentColorspace = $confManager->getLocalConfigurationValueByPath('GFX/processor_colorspace');
|
||
|
||
if ($currentProcessor === 'ImageMagick' && $currentColorspace === 'sRGB'
|
||
|| $currentProcessor === 'GraphicsMagick' && $currentColorspace === 'RGB') {
|
||
$confManager->removeLocalConfigurationKeysByPath(['GFX/processor_colorspace']);
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
} catch (MissingArrayPathException) {
|
||
// no change inside the system/settings.php found, so nothing needs to be modified
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Migrate 'SYS'/'lang' related configuration settings to 'LANG'
|
||
*
|
||
* @throws ConfigurationChangedException
|
||
*/
|
||
protected function migrateLanguageSettings(): void
|
||
{
|
||
$confManager = $this->configurationManager;
|
||
$newSettings = [];
|
||
$removeSettings = [];
|
||
|
||
// Migrate SYS/lang/requireApprovedLocalizations => LANG/requireApprovedLocalizations
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('SYS/lang/requireApprovedLocalizations');
|
||
$removeSettings[] = 'SYS/lang/requireApprovedLocalizations';
|
||
$newSettings['LANG/requireApprovedLocalizations'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
// Migrate SYS/lang/format => LANG/format
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('SYS/lang/format');
|
||
$removeSettings[] = 'SYS/lang/format';
|
||
$newSettings['LANG/format'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
// Migrate EXTCONF/lang/availableLanguages => LANG/availableLocales
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('EXTCONF/lang/availableLanguages');
|
||
$removeSettings[] = 'EXTCONF/lang/availableLanguages';
|
||
$newSettings['LANG/availableLocales'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
// Migrate SYS/locallangXMLOverride => LANG/resourceOverrides
|
||
try {
|
||
$value = $confManager->getLocalConfigurationValueByPath('SYS/locallangXMLOverride');
|
||
$removeSettings[] = 'SYS/locallangXMLOverride';
|
||
$newSettings['LANG/resourceOverrides'] = $value;
|
||
} catch (MissingArrayPathException) {
|
||
// Old setting does not exist, do nothing
|
||
}
|
||
|
||
// Add new settings and remove old ones
|
||
if (!empty($newSettings)) {
|
||
$confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
|
||
}
|
||
if (!empty($removeSettings)) {
|
||
$confManager->removeLocalConfigurationKeysByPath($removeSettings);
|
||
}
|
||
|
||
// Throw redirect if something was changed
|
||
if (!empty($newSettings) || !empty($removeSettings)) {
|
||
$this->throwConfigurationChangedException();
|
||
}
|
||
}
|
||
}
|