From 4aa72b0a58bb28cd940bb0aaafb6d97bc54527b2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jonas=20G=C3=B6tze?= Date: Sat, 5 Mar 2016 15:23:43 +0100 Subject: [PATCH] [FEATURE] Check database default charset Checks the default database charset during installation and provides Upgrade Wizard to fix default charset. Resolves: #74319 Releases: master Change-Id: I645c0dc321a719e2149b8474e4292c80811fd82c Reviewed-on: https://review.typo3.org/47103 Reviewed-by: Eugen Lang Tested-by: Eugen Lang Reviewed-by: Andreas Wolf Tested-by: Andreas Wolf --- ...ixingDefaultCharacterSetOtherThanUtf-8.rst | 21 ++++ .../Controller/Action/Step/DatabaseSelect.php | 37 +++++- .../Controller/Action/Tool/UpgradeWizard.php | 9 +- .../SystemEnvironment/DatabaseCheck.php | 36 ++++++ .../Classes/Updates/DatabaseCharsetUpdate.php | 109 ++++++++++++++++++ 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-74319-CheckDefaultDatabaseCharacterSetDuringInstallationAndProvideUpdateWizardForFixingDefaultCharacterSetOtherThanUtf-8.rst create mode 100644 typo3/sysext/install/Classes/Updates/DatabaseCharsetUpdate.php diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-74319-CheckDefaultDatabaseCharacterSetDuringInstallationAndProvideUpdateWizardForFixingDefaultCharacterSetOtherThanUtf-8.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-74319-CheckDefaultDatabaseCharacterSetDuringInstallationAndProvideUpdateWizardForFixingDefaultCharacterSetOtherThanUtf-8.rst new file mode 100644 index 000000000000..03bb219dffcf --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-74319-CheckDefaultDatabaseCharacterSetDuringInstallationAndProvideUpdateWizardForFixingDefaultCharacterSetOtherThanUtf-8.rst @@ -0,0 +1,21 @@ +====================================================================================================================================================== +Feature: #74319 - check default database character set during Installation and provide Update wizard for fixing default character set other than utf-8 +====================================================================================================================================================== + + +Description +=========== + +If you install TYPO3 to an existing database with a default charset other than utf-8, TYPO3 will create tables with the default charset of that database. +The install tool should check the default charset and notify the user if it is not utf-8. + +Furthermore the install tool should check for this issue too and provide an update wizard to fix this (=set the default charset to utf-8 and NOT convert existing tables to utf-8). +A default charset set other than utf-8 leads to non-utf-8 tables when updating the database via the install tool or installing extensions. + + +Impact +====== + +During installation on database select the default charset of the database is checked. If it is not utf-8 the installation will not proceed and the user is notified of the issue. + +For existing installations the install tool also provides an environment check and an upgrade wizard which changes the default database character set. The update wizard will NOT convert any existing tables though! \ No newline at end of file diff --git a/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseSelect.php b/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseSelect.php index e892f0be22d6..99c630205308 100644 --- a/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseSelect.php +++ b/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseSelect.php @@ -41,6 +41,7 @@ class DatabaseSelect extends AbstractStepAction $localConfigurationPathValuePairs = array(); /** @var $configurationManager \TYPO3\CMS\Core\Configuration\ConfigurationManager */ $configurationManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class); + $canProceed = true; if ($postValues['type'] === 'new') { $newDatabaseName = $postValues['new']; if ($this->isValidDatabaseName($newDatabaseName)) { @@ -79,6 +80,19 @@ class DatabaseSelect extends AbstractStepAction if (!$isInitialInstallation || empty($existingTables)) { $localConfigurationPathValuePairs['DB/database'] = $postValues['existing']; } + // check if database charset is utf-8 + $defaultDatabaseCharset = $this->getDefaultDatabaseCharset(); + // also allow utf8mb4 + if (substr($defaultDatabaseCharset, 0, 4) !== 'utf8') { + $errorStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class); + $errorStatus->setTitle('Invalid Charset'); + $errorStatus->setMessage( + 'Your database uses character set "' . $defaultDatabaseCharset . '", ' . + 'but only "utf8" is supported with TYPO3. You probably want to change this before proceeding.' + ); + $result[] = $errorStatus; + $canProceed = false; + } } else { /** @var $errorStatus \TYPO3\CMS\Install\Status\ErrorStatus */ $errorStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class); @@ -87,7 +101,7 @@ class DatabaseSelect extends AbstractStepAction $result[] = $errorStatus; } - if (!empty($localConfigurationPathValuePairs)) { + if ($canProceed && !empty($localConfigurationPathValuePairs)) { $configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs); } @@ -192,4 +206,25 @@ class DatabaseSelect extends AbstractStepAction { return strlen($databaseName) <= 50 && preg_match('/^[a-zA-Z0-9\$_]*$/', $databaseName); } + + /** + * Retrieves the default character set of the database. + * + * @return string + */ + protected function getDefaultDatabaseCharset() + { + $result = $this->databaseConnection->admin_query('SHOW VARIABLES LIKE "character_set_database"'); + $row = $this->databaseConnection->sql_fetch_assoc($result); + + $key = $row['Variable_name']; + $value = $row['Value']; + $databaseCharset = ''; + + if ($key == 'character_set_database') { + $databaseCharset = $value; + } + + return $databaseCharset; + } } diff --git a/typo3/sysext/install/Classes/Controller/Action/Tool/UpgradeWizard.php b/typo3/sysext/install/Classes/Controller/Action/Tool/UpgradeWizard.php index 1f96ee58dcce..ca48e92664e4 100644 --- a/typo3/sysext/install/Classes/Controller/Action/Tool/UpgradeWizard.php +++ b/typo3/sysext/install/Classes/Controller/Action/Tool/UpgradeWizard.php @@ -45,7 +45,14 @@ class UpgradeWizard extends Action\AbstractAction $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = []; } - // To make sure initialUpdateDatabaseSchema is first wizard, it is added here instead of ext_localconf.php + // To make sure DatabaseCharsetUpdate and initialUpdateDatabaseSchema are first wizards, they are added here instead of ext_localconf.php + $databaseCharsetUpdateObject = $this->getUpdateObjectInstance(\TYPO3\CMS\Install\Updates\DatabaseCharsetUpdate::class, 'databaseCharsetUpdate'); + if ($databaseCharsetUpdateObject->shouldRenderWizard()) { + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = array_merge( + array('databaseCharsetUpdate' => \TYPO3\CMS\Install\Updates\DatabaseCharsetUpdate::class), + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] + ); + } $initialUpdateDatabaseSchemaUpdateObject = $this->getUpdateObjectInstance(\TYPO3\CMS\Install\Updates\InitialDatabaseSchemaUpdate::class, 'initialUpdateDatabaseSchema'); if ($initialUpdateDatabaseSchemaUpdateObject->shouldRenderWizard()) { $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = array_merge( diff --git a/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php index e283c1400c79..7ec87f5d8cb5 100644 --- a/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php +++ b/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php @@ -50,6 +50,7 @@ class DatabaseCheck } $statusArray[] = $this->checkMysqlVersion(); $statusArray[] = $this->checkInvalidSqlModes(); + $statusArray[] = $this->checkMysqlDatabaseUtf8Status(); return $statusArray; } @@ -110,6 +111,41 @@ class DatabaseCheck return $status; } + /** + * Checks the character set of the database and reports an error if it is not utf-8. + * + * @return Status\StatusInterface + */ + protected function checkMysqlDatabaseUtf8Status() + { + $result = $this->getDatabaseConnection()->admin_query('SHOW VARIABLES LIKE "character_set_database"'); + $row = $this->getDatabaseConnection()->sql_fetch_assoc($result); + + $key = $row['Variable_name']; + $value = $row['Value']; + + if ($key !== 'character_set_database') { + $status = new Status\ErrorStatus(); + $status->setTitle('MySQL database character set check failed'); + $status->setMessage( + 'Checking database character set failed, got key "' . $key . '" instead of "character_set_database"' + ); + } + // also allow utf8mb4 + if (substr($value, 0, 4) !== 'utf8') { + $status = new Status\ErrorStatus(); + $status->setTitle('MySQL database character set wrong'); + $status->setMessage( + 'Your database uses character set "' . $value . '", but only "utf8" is supported with TYPO3.' + ); + } else { + $status = new Status\OkStatus(); + $status->setTitle('Your database uses utf-8. All good.'); + } + + return $status; + } + /** * Returns an array with the current sql mode settings * diff --git a/typo3/sysext/install/Classes/Updates/DatabaseCharsetUpdate.php b/typo3/sysext/install/Classes/Updates/DatabaseCharsetUpdate.php new file mode 100644 index 000000000000..2e75ec03d586 --- /dev/null +++ b/typo3/sysext/install/Classes/Updates/DatabaseCharsetUpdate.php @@ -0,0 +1,109 @@ +isDbalEnabled()) { + return $result; + } + // check if database charset is utf-8 + $defaultDatabaseCharset = $this->getDefaultDatabaseCharset(); + // also allow utf8mb4 + if (substr($defaultDatabaseCharset, 0, 4) !== 'utf8') { + $result = true; + } + + return $result; + } + + /** + * Performs the accordant updates. + * + * @param array &$dbQueries Queries done in this update + * @param mixed &$customMessages Custom messages + * @return bool Whether everything went smoothly or not + */ + public function performUpdate(array &$dbQueries, &$customMessages) + { + $result = true; + $db = $this->getDatabaseConnection(); + $query = 'ALTER DATABASE `' . $GLOBALS['TYPO3_CONF_VARS']['DB']['database'] . '` DEFAULT CHARACTER SET utf8'; + $db->admin_query($query); + $dbQueries[] = $query; + if ($db->sql_error()) { + $customMessages = 'SQL-ERROR: ' . htmlspecialchars($db->sql_error()); + $result = false; + } + return $result; + } + + /** + * Return TRUE if dbal and adodb extension is loaded + * + * @return bool TRUE if dbal and adodb is loaded + */ + protected function isDbalEnabled() + { + if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('adodb') + && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dbal') + ) { + return true; + } + return false; + } + + /** + * Retrieves the default character set of the database. + * + * @return string + */ + protected function getDefaultDatabaseCharset() + { + $db = $this->getDatabaseConnection(); + $result = $db->admin_query('SHOW VARIABLES LIKE "character_set_database"'); + $row = $db->sql_fetch_assoc($result); + + $key = $row['Variable_name']; + $value = $row['Value']; + $databaseCharset = ''; + + if ($key == 'character_set_database') { + $databaseCharset = $value; + } + + return $databaseCharset; + } +} -- 2.20.1