[FEATURE] Check for incompatible MySQL modes in install tool 87/41787/6
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Tue, 21 Jul 2015 18:18:56 +0000 (20:18 +0200)
committerAndreas Wolf <andreas.wolf@typo3.org>
Wed, 5 Aug 2015 09:11:53 +0000 (11:11 +0200)
Detect MySQL modes that are incompatible with TYPO3 CMS and report them
in the Install Tool. The warning will appear after the initial database
setup has been done and the install tool is fully operational.

The system environment status report has also been extended to include
the checks for the MySQL modes.

Resolves: #68407
Releases: master
Change-Id: Ibbd2d5f86cad5de46153edfa7c118e2423c16579
Reviewed-on: http://review.typo3.org/41787
Reviewed-by: Alexander Opitz <opitz.alexander@googlemail.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Andreas Wolf <andreas.wolf@typo3.org>
Tested-by: Sascha Wilking <sascha.wilking@hmmh.de>
Tested-by: Andreas Wolf <andreas.wolf@typo3.org>
typo3/sysext/core/Classes/Database/DatabaseConnection.php
typo3/sysext/install/Classes/Controller/Action/Ajax/EnvironmentStatus.php
typo3/sysext/install/Classes/Controller/Action/Tool/SystemEnvironment.php
typo3/sysext/install/Classes/Report/EnvironmentStatusReport.php
typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php [new file with mode: 0644]

index d16a929..d3816e7 100644 (file)
@@ -1214,7 +1214,6 @@ class DatabaseConnection {
                                        );
                                }
                        }
-                       $this->setSqlMode();
                        $this->checkConnectionCharset();
                } else {
                        // @todo This should raise an exception. Would be useful especially to work during installation.
@@ -1230,28 +1229,6 @@ class DatabaseConnection {
        }
 
        /**
-        * Fixes the SQL mode by unsetting NO_BACKSLASH_ESCAPES if found.
-        *
-        * @return void
-        */
-       protected function setSqlMode() {
-               $resource = $this->sql_query('SELECT @@SESSION.sql_mode;');
-               if ($resource) {
-                       $result = $this->sql_fetch_row($resource);
-                       if (isset($result[0]) && $result[0] && strpos($result[0], 'NO_BACKSLASH_ESCAPES') !== FALSE) {
-                               $modes = array_diff(GeneralUtility::trimExplode(',', $result[0]), array('NO_BACKSLASH_ESCAPES'));
-                               $query = 'SET sql_mode=\'' . $this->link->real_escape_string(implode(',', $modes)) . '\';';
-                               $this->sql_query($query);
-                               GeneralUtility::sysLog(
-                                       'NO_BACKSLASH_ESCAPES could not be removed from SQL mode: ' . $this->sql_error(),
-                                       'core',
-                                       GeneralUtility::SYSLOG_SEVERITY_ERROR
-                               );
-                       }
-               }
-       }
-
-       /**
         * Select a SQL database
         *
         * @return bool Returns TRUE on success or FALSE on failure.
index 0922a2c..901f516 100644 (file)
@@ -28,10 +28,15 @@ class EnvironmentStatus extends AbstractAjaxAction {
                /** @var \TYPO3\CMS\Install\Status\StatusUtility $statusUtility */
                $statusUtility = $this->objectManager->get(\TYPO3\CMS\Install\Status\StatusUtility::class);
 
-               // Count of failed environment checks are displayed in the left navigation menu
+               // Count of failed environment checks to be displayed in the left navigation menu
                $environmentStatus = $this->objectManager->get(\TYPO3\CMS\Install\SystemEnvironment\Check::class)->getStatus();
                $environmentErrors = $statusUtility->filterBySeverity($environmentStatus, 'error');
-               return count($environmentErrors);
+
+               // Count of failed database checks to be displayed in the left navigation menu
+               $databaseStatus = $this->objectManager->get(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class)->getStatus();
+               $databaseErrors = $statusUtility->filterBySeverity($databaseStatus, 'error');
+
+               return count($environmentErrors) + count($databaseErrors);
        }
 
-}
\ No newline at end of file
+}
index 42d7317..823a792 100644 (file)
@@ -31,6 +31,10 @@ class SystemEnvironment extends Action\AbstractAction {
                $statusCheck = $this->objectManager->get(\TYPO3\CMS\Install\SystemEnvironment\Check::class);
                $statusObjects = $statusCheck->getStatus();
 
+               /** @var $statusCheck \TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck */
+               $databaseStatusCheck = $this->objectManager->get(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class);
+               $statusObjects = array_merge($statusObjects, $databaseStatusCheck->getStatus());
+
                /** @var $statusUtility \TYPO3\CMS\Install\Status\StatusUtility */
                $statusUtility = $this->objectManager->get(\TYPO3\CMS\Install\Status\StatusUtility::class);
                $sortedStatusObjects = $statusUtility->sortBySeverity($statusObjects);
index c202dac..0c62120 100644 (file)
@@ -50,6 +50,10 @@ class EnvironmentStatusReport implements StatusProviderInterface, ExtendedStatus
                $statusCheck = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\Check::class);
                $statusObjects = $statusCheck->getStatus();
 
+               /** @var $statusCheck \TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck */
+               $databaseStatusCheck = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck::class);
+               $statusObjects = array_merge($statusObjects, $databaseStatusCheck->getStatus());
+
                $reportStatusTypes = array(
                        'error' => array(),
                        'warning' => array(),
diff --git a/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php
new file mode 100644 (file)
index 0000000..95c4c39
--- /dev/null
@@ -0,0 +1,128 @@
+<?php
+namespace TYPO3\CMS\Install\SystemEnvironment;
+
+/*
+ * 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!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status;
+
+/**
+ * Check database configuration status
+ *
+ * This class is a hardcoded requirement check for the database server.
+ *
+ * The status messages and title *must not* include HTML, use plain
+ * text only. The return values of this class are not bound to HTML
+ * and can be used in different scopes (eg. as json array).
+ */
+class DatabaseCheck {
+       /**
+        * List of MySQL modes that are incompatible with TYPO3 CMS
+        *
+        * @var array
+        */
+       protected $incompatibleSqlModes = array(
+               'STRICT_ALL_TABLES',
+               'STRICT_TRANS_TABLES',
+               'NO_BACKSLASH_ESCAPES'
+       );
+
+       /**
+        * Get all status information as array with status objects
+        *
+        * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
+        */
+       public function getStatus() {
+               $statusArray = array();
+               if ($this->isDbalEnabled() || !$this->getDatabaseConnection()) {
+                       return $statusArray;
+               }
+               $statusArray[] = $this->checkInvalidSqlModes();
+               return $statusArray;
+       }
+
+       /**
+        * Check if any SQL mode is set which is not compatible with TYPO3
+        *
+        * @return Status\StatusInterface
+        */
+       protected function checkInvalidSqlModes() {
+               $detectedIncompatibleSqlModes = $this->getIncompatibleSqlModes();
+               if (!empty($detectedIncompatibleSqlModes)) {
+                       $status = new Status\ErrorStatus();
+                       $status->setTitle('Incompatible SQL modes found!');
+                       $status->setMessage(
+                               'Incompatible SQL modes have been detected:' .
+                               ' ' . implode(', ', $detectedIncompatibleSqlModes) . '.' .
+                               ' The listed modes are not compatible with TYPO3 CMS.' .
+                               ' You have to change that setting in your MySQL environment' .
+                               ' or in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\']'
+                       );
+               } else {
+                       $status = new Status\OkStatus();
+                       $status->setTitle('No incompatible SQL modes found.');
+               }
+
+               return $status;
+       }
+
+       /**
+        * Returns an array with the current sql mode settings
+        *
+        * @return array Contains all configured SQL modes that are incompatible
+        */
+       protected function getIncompatibleSqlModes() {
+               $sqlModes = array();
+               $resource = $this->getDatabaseConnection()->sql_query('SELECT @@SESSION.sql_mode;');
+               if ($resource !== FALSE) {
+                       $result = $this->getDatabaseConnection()->sql_fetch_row($resource);
+                       if (isset($result[0])) {
+                               $sqlModes = explode(',', $result[0]);
+                       }
+               }
+               return array_intersect($this->incompatibleSqlModes, $sqlModes);
+       }
+
+       /**
+        * Get database instance.
+        * Will be initialized if it does not exist yet.
+        *
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               static $database;
+               if (!is_object($database)) {
+                       /** @var \TYPO3\CMS\Core\Database\DatabaseConnection $database */
+                       $database = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
+                       $database->setDatabaseUsername($GLOBALS['TYPO3_CONF_VARS']['DB']['username']);
+                       $database->setDatabasePassword($GLOBALS['TYPO3_CONF_VARS']['DB']['password']);
+                       $database->setDatabaseHost($GLOBALS['TYPO3_CONF_VARS']['DB']['host']);
+                       $database->setDatabasePort($GLOBALS['TYPO3_CONF_VARS']['DB']['port']);
+                       $database->setDatabaseSocket($GLOBALS['TYPO3_CONF_VARS']['DB']['socket']);
+                       $database->setDatabaseName($GLOBALS['TYPO3_CONF_VARS']['DB']['database']);
+                       $database->initialize();
+                       $database->connectDB();
+               }
+               return $database;
+       }
+
+       /**
+        * Checks if DBAL is enabled for the database connection
+        *
+        * @return bool
+        */
+       protected function isDbalEnabled() {
+               return \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dbal');
+       }
+}