From 9c905d15d15e240035e0942ebbffd3f295d2eef5 Mon Sep 17 00:00:00 2001 From: Alexander Stehlik <alexander.stehlik@googlemail.com> Date: Tue, 14 Jan 2014 18:12:10 +0100 Subject: [PATCH] [TASK][CONF] Accept other settings in [SYS][setDBinit] Since the mysqli interface recommends setting the charset using the mysqli API the utf8 charset will be initialized when establishing the database connection using mysqli_set_charset(). Additionally [SYS][setDBinit] can now be set to any value or can totally be removed. To make sure the database connection still uses the correct encoding an additional check is added to the database connection process that checks the MySQL character set session variables. Finally the old default value of [SYS][setDBinit] will automatically be removed if it is set to the old default value. Resolves: #41596 Releases: 6.2 Change-Id: I8d0a9eba50495d52accb59627147c1c87b6a9bb5 Reviewed-on: https://review.typo3.org/15369 Reviewed-by: Wouter Wolters Reviewed-by: Alexander Opitz Tested-by: Alexander Opitz Reviewed-by: Michael Stucki Tested-by: Michael Stucki Reviewed-by: Markus Klein Tested-by: Markus Klein --- typo3/sysext/core/Classes/Core/Bootstrap.php | 30 ----- .../Classes/Database/DatabaseConnection.php | 108 ++++++++++++++++++ .../Configuration/DefaultConfiguration.php | 1 + .../Configuration/FactoryConfiguration.php | 1 - .../SilentConfigurationUpgradeService.php | 8 ++ 5 files changed, 117 insertions(+), 31 deletions(-) diff --git a/typo3/sysext/core/Classes/Core/Bootstrap.php b/typo3/sysext/core/Classes/Core/Bootstrap.php index a431086da5ae..99fe760bcbbb 100644 --- a/typo3/sysext/core/Classes/Core/Bootstrap.php +++ b/typo3/sysext/core/Classes/Core/Bootstrap.php @@ -238,7 +238,6 @@ class Bootstrap { $this->defineDatabaseConstants() ->defineUserAgentConstant() ->registerExtDirectComponents() - ->checkUtf8DatabaseSettingsOrDie() ->transferDeprecatedCurlSettings() ->setCacheHashOptions() ->setDefaultTimezone() @@ -487,35 +486,6 @@ class Bootstrap { return $this; } - /** - * Checking for UTF-8 in the settings since TYPO3 4.5 - * - * Since TYPO3 4.5, everything other than UTF-8 is deprecated. - * - * [SYS][setDBinit] is used to set the DB connection - * and both settings need to be adjusted for UTF-8 in order to work properly - * - * @return Bootstrap - */ - protected function checkUtf8DatabaseSettingsOrDie() { - if (isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']) && - $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'] !== '-1' && - preg_match('/SET NAMES [\'"]?utf8[\'"]?/i', $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']) === FALSE && - TYPO3_enterInstallScript !== '1') { - - // Only accept "SET NAMES utf8" for this setting, otherwise die with a nice error - die('This TYPO3 installation is using the $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\'] property with the following value:' . chr(10) . - $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'] . chr(10) . chr(10) . - 'It looks like UTF-8 is not used for this connection.' . chr(10) . chr(10) . - 'Everything other than UTF-8 is unsupported since TYPO3 4.7.' . chr(10) . - 'The DB, its connection and TYPO3 should be migrated to UTF-8 therefore. Please check your setup.' - ); - } else { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'] = 'SET NAMES utf8;'; - } - return $this; - } - /** * Parse old curl options and set new http ones instead * diff --git a/typo3/sysext/core/Classes/Database/DatabaseConnection.php b/typo3/sysext/core/Classes/Database/DatabaseConnection.php index 640c2c3a605a..f23c109436d1 100644 --- a/typo3/sysext/core/Classes/Database/DatabaseConnection.php +++ b/typo3/sysext/core/Classes/Database/DatabaseConnection.php @@ -136,6 +136,14 @@ class DatabaseConnection { */ protected $connectionCompression = FALSE; + /** + * The charset for the connection; will be passed on to + * mysqli_set_charset during connection initialization. + * + * @var string + */ + protected $connectionCharset = 'utf8'; + /** * @var array List of commands executed after connection was established */ @@ -1194,6 +1202,15 @@ class DatabaseConnection { if ($connected) { $this->isConnected = TRUE; + + if ($this->link->set_charset($this->connectionCharset) === FALSE) { + \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog( + 'Error setting connection charset to "' . $this->connectionCharset . '"', + 'Core', + \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR + ); + } + foreach ($this->initializeCommandsAfterConnect as $command) { if ($this->link->query($command) === FALSE) { \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog( @@ -1204,6 +1221,7 @@ class DatabaseConnection { } } $this->setSqlMode(); + $this->checkConnectionCharset(); } else { // @TODO: This should raise an exception. Would be useful especially to work during installation. $error_msg = $this->link->connect_error; @@ -1523,6 +1541,20 @@ class DatabaseConnection { $this->initializeCommandsAfterConnect = $commands; } + /** + * Set the charset that should be used for the MySQL connection. + * The given value will be passed on to mysqli_set_charset(). + * + * The default value of this setting is utf8. + * + * @param string $connectionCharset The connection charset that will be passed on to mysqli_set_charset() when connecting the database. Default is utf8. + * @return void + */ + public function setConnectionCharset($connectionCharset = 'utf8') { + $this->disconnectIfConnected(); + $this->connectionCharset = $connectionCharset; + } + /** * Connects to database for TYPO3 sites: * @@ -1600,6 +1632,82 @@ class DatabaseConnection { return $this->isConnected; } + /** + * Checks if the current connection character set has the same value + * as the connectionCharset variable. + * + * To determine the character set these MySQL session variables are + * checked: character_set_client, character_set_results and + * character_set_connection. + * + * If the character set does not match or if the session variables + * can not be read a RuntimeException is thrown. + * + * @return void + * @throws \RuntimeException + */ + protected function checkConnectionCharset() { + $sessionResult = $this->sql_query('SHOW SESSION VARIABLES LIKE \'character_set%\''); + + if ($sessionResult === FALSE) { + \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog( + 'Error while retrieving the current charset session variables from the database: ' . $this->sql_error(), + 'Core', + \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR + ); + throw new \RuntimeException( + 'TYPO3 Fatal Error: Could not determine the current charset of the database.', + 1381847136 + ); + } + + $charsetVariables = array(); + while (($row = $this->sql_fetch_row($sessionResult)) !== FALSE) { + $variableName = $row[0]; + $variableValue = $row[1]; + $charsetVariables[$variableName] = $variableValue; + } + $this->sql_free_result($sessionResult); + + // These variables are set with the "Set names" command which was + // used in the past. This is why we check them. + $charsetRequiredVariables = array( + 'character_set_client', + 'character_set_results', + 'character_set_connection', + ); + + $hasValidCharset = TRUE; + foreach ($charsetRequiredVariables as $variableName) { + if (empty($charsetVariables[$variableName])) { + \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog( + 'A required session variable is missing in the current MySQL connection: ' . $variableName, + 'Core', + \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR + ); + throw new \RuntimeException( + 'TYPO3 Fatal Error: Could not determine the value of the database session variable: ' . $variableName, + 1381847779 + ); + } + + if ($charsetVariables[$variableName] !== $this->connectionCharset) { + $hasValidCharset = FALSE; + break; + } + } + + if (!$hasValidCharset) { + throw new \RuntimeException( + 'It looks like the character set ' . $this->connectionCharset . ' is not used for this connection even though it is configured as connection charset. ' . + 'This TYPO3 installation is using the $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\'] property with the following value: "' . + $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'] . '". Please make sure that this command does not overwrite the configured charset. ' . + 'Please note that for the TYPO3 database everything other than utf8 is unsupported since version 4.7.', + 1389697515 + ); + } + } + /** * Disconnect from database if connected * diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php index 2c6f3ace8026..0586978a6887 100644 --- a/typo3/sysext/core/Configuration/DefaultConfiguration.php +++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php @@ -110,6 +110,7 @@ return array( 't3lib_cs_utils' => '', // String (values: "iconv", "mbstring", default is homemade PHP-code). Defines which of these PHP-features to use for various charset processing functions in t3lib_cs. Will speed up charset functions radically. 'no_pconnect' => TRUE, // Boolean: If TRUE, "connect" is used to connect to the database. If FALSE, a persistent connection using "pconnect" will be established! 'dbClientCompress' => FALSE, // Boolean: if TRUE, data exchange between TYPO3 and database server will be compressed. This may improve performance if (1) database serever is on the different server and (2) network connection speed to database server is 100mbps or less. CPU usage will be higher if this option is used but database operations will be executed faster due to much less (up to 3 times) database network traffic. This option has no effect if MySQL server is localhost. + 'setDBinit' => '', // String (textarea): These commands are executed after the database connection was established. Hint: The previous default "SET NAMES utf8;" is not required any more and will be removed automatically if set! 'setMemoryLimit' => 0, // Integer: memory_limit in MB: If more than 16, TYPO3 will try to use ini_set() to set the memory limit of PHP to the value. This works only if the function ini_set() is not disabled by your sysadmin. 'serverTimeZone' => 1, // Integer: GMT offset of servers time (from time()). Default is "1" which is "GMT+1" (central european time). This value can be used in extensions that are GMT aware and wants to convert times to/from other timezones. 'phpTimeZone' => '', // String: timezone to force for all date() and mktime() functions. A list of supported values can be found at <a href="http://php.net/manual/en/timezones.php" target="_blank">php.net</a>. If this is not set, a valid fallback will be searched for by PHP (php.ini's <a href="http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone" target="_blank">date.timezone</a> setting, server defaults, etc); and if no fallback is found, the value of "UTC" is used instead. diff --git a/typo3/sysext/core/Configuration/FactoryConfiguration.php b/typo3/sysext/core/Configuration/FactoryConfiguration.php index 910c24ebcfbb..0a1f3133d4c0 100644 --- a/typo3/sysext/core/Configuration/FactoryConfiguration.php +++ b/typo3/sysext/core/Configuration/FactoryConfiguration.php @@ -77,7 +77,6 @@ return array( 'SYS' => array( 'compat_version' => '6.2', 'isInitialInstallationInProgress' => TRUE, - 'setDBinit' => 'SET NAMES utf8;', 'sitename' => 'New TYPO3 site', ), ); diff --git a/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php b/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php index 27702e76d419..532cd8726dcd 100644 --- a/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php +++ b/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php @@ -141,6 +141,14 @@ class SilentConfigurationUpgradeService { */ protected function removeObsoleteLocalConfigurationSettings() { $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings); + + // The old default value is not needed anymore. So if the user + // did not set a different value we can remove it. + $currentSetDbInitValue = $this->configurationManager->getConfigurationValueByPath('SYS/setDBinit'); + if (preg_match('/^\s*SET\s+NAMES\s+[\'"]?utf8[\'"]?\s*[;]?\s*$/i', $currentSetDbInitValue) === 1) { + $removed = $removed || $this->configurationManager->removeLocalConfigurationKeysByPath(array('SYS/setDBinit')); + } + // If something was changed: Trigger a reload to have new values in next request if ($removed) { $this->throwRedirectException(); -- GitLab