[FEATURE] Check database default charset
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / SystemEnvironment / DatabaseCheck.php
1 <?php
2 namespace TYPO3\CMS\Install\SystemEnvironment;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Install\Status;
19
20 /**
21 * Check database configuration status
22 *
23 * This class is a hardcoded requirement check for the database server.
24 *
25 * The status messages and title *must not* include HTML, use plain
26 * text only. The return values of this class are not bound to HTML
27 * and can be used in different scopes (eg. as json array).
28 */
29 class DatabaseCheck
30 {
31 /**
32 * List of MySQL modes that are incompatible with TYPO3 CMS
33 *
34 * @var array
35 */
36 protected $incompatibleSqlModes = array(
37 'NO_BACKSLASH_ESCAPES'
38 );
39
40 /**
41 * Get all status information as array with status objects
42 *
43 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
44 */
45 public function getStatus()
46 {
47 $statusArray = array();
48 if ($this->isDbalEnabled() || !$this->getDatabaseConnection()) {
49 return $statusArray;
50 }
51 $statusArray[] = $this->checkMysqlVersion();
52 $statusArray[] = $this->checkInvalidSqlModes();
53 $statusArray[] = $this->checkMysqlDatabaseUtf8Status();
54 return $statusArray;
55 }
56
57 /**
58 * Check if any SQL mode is set which is not compatible with TYPO3
59 *
60 * @return Status\StatusInterface
61 */
62 protected function checkInvalidSqlModes()
63 {
64 $detectedIncompatibleSqlModes = $this->getIncompatibleSqlModes();
65 if (!empty($detectedIncompatibleSqlModes)) {
66 $status = new Status\ErrorStatus();
67 $status->setTitle('Incompatible SQL modes found!');
68 $status->setMessage(
69 'Incompatible SQL modes have been detected:' .
70 ' ' . implode(', ', $detectedIncompatibleSqlModes) . '.' .
71 ' The listed modes are not compatible with TYPO3 CMS.' .
72 ' You have to change that setting in your MySQL environment' .
73 ' or in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\']'
74 );
75 } else {
76 $status = new Status\OkStatus();
77 $status->setTitle('No incompatible SQL modes found.');
78 }
79
80 return $status;
81 }
82
83 /**
84 * Check minimum MySQL version
85 *
86 * @return Status\StatusInterface
87 */
88 protected function checkMysqlVersion()
89 {
90 $minimumMysqlVersion = '5.5.0';
91 $currentMysqlVersion = '';
92 $resource = $this->getDatabaseConnection()->sql_query('SHOW VARIABLES LIKE \'version\';');
93 if ($resource !== false) {
94 $result = $this->getDatabaseConnection()->sql_fetch_row($resource);
95 if (isset($result[1])) {
96 $currentMysqlVersion = $result[1];
97 }
98 }
99 if (version_compare($currentMysqlVersion, $minimumMysqlVersion) < 0) {
100 $status = new Status\ErrorStatus();
101 $status->setTitle('MySQL version too low');
102 $status->setMessage(
103 'Your MySQL version ' . $currentMysqlVersion . ' is too old. TYPO3 CMS does not run' .
104 ' with this version. Update to at least MySQL ' . $minimumMysqlVersion
105 );
106 } else {
107 $status = new Status\OkStatus();
108 $status->setTitle('MySQL version is fine');
109 }
110
111 return $status;
112 }
113
114 /**
115 * Checks the character set of the database and reports an error if it is not utf-8.
116 *
117 * @return Status\StatusInterface
118 */
119 protected function checkMysqlDatabaseUtf8Status()
120 {
121 $result = $this->getDatabaseConnection()->admin_query('SHOW VARIABLES LIKE "character_set_database"');
122 $row = $this->getDatabaseConnection()->sql_fetch_assoc($result);
123
124 $key = $row['Variable_name'];
125 $value = $row['Value'];
126
127 if ($key !== 'character_set_database') {
128 $status = new Status\ErrorStatus();
129 $status->setTitle('MySQL database character set check failed');
130 $status->setMessage(
131 'Checking database character set failed, got key "' . $key . '" instead of "character_set_database"'
132 );
133 }
134 // also allow utf8mb4
135 if (substr($value, 0, 4) !== 'utf8') {
136 $status = new Status\ErrorStatus();
137 $status->setTitle('MySQL database character set wrong');
138 $status->setMessage(
139 'Your database uses character set "' . $value . '", but only "utf8" is supported with TYPO3.'
140 );
141 } else {
142 $status = new Status\OkStatus();
143 $status->setTitle('Your database uses utf-8. All good.');
144 }
145
146 return $status;
147 }
148
149 /**
150 * Returns an array with the current sql mode settings
151 *
152 * @return array Contains all configured SQL modes that are incompatible
153 */
154 protected function getIncompatibleSqlModes()
155 {
156 $sqlModes = array();
157 $resource = $this->getDatabaseConnection()->sql_query('SELECT @@SESSION.sql_mode;');
158 if ($resource !== false) {
159 $result = $this->getDatabaseConnection()->sql_fetch_row($resource);
160 if (isset($result[0])) {
161 $sqlModes = explode(',', $result[0]);
162 }
163 }
164 return array_intersect($this->incompatibleSqlModes, $sqlModes);
165 }
166
167 /**
168 * Get database instance.
169 * Will be initialized if it does not exist yet.
170 *
171 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
172 */
173 protected function getDatabaseConnection()
174 {
175 static $database;
176 if (!is_object($database)) {
177 /** @var \TYPO3\CMS\Core\Database\DatabaseConnection $database */
178 $database = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
179 $database->setDatabaseUsername($GLOBALS['TYPO3_CONF_VARS']['DB']['username']);
180 $database->setDatabasePassword($GLOBALS['TYPO3_CONF_VARS']['DB']['password']);
181 $database->setDatabaseHost($GLOBALS['TYPO3_CONF_VARS']['DB']['host']);
182 $database->setDatabasePort($GLOBALS['TYPO3_CONF_VARS']['DB']['port']);
183 $database->setDatabaseSocket($GLOBALS['TYPO3_CONF_VARS']['DB']['socket']);
184 $database->setDatabaseName($GLOBALS['TYPO3_CONF_VARS']['DB']['database']);
185 $database->initialize();
186 $database->connectDB();
187 }
188 return $database;
189 }
190
191 /**
192 * Checks if DBAL is enabled for the database connection
193 *
194 * @return bool
195 */
196 protected function isDbalEnabled()
197 {
198 return \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('dbal');
199 }
200 }