d955e18dab4cb2b445e28545265eae18845b793b
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Step / DatabaseData.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Step;
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 Doctrine\DBAL\DBALException;
18 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
19 use TYPO3\CMS\Core\Database\ConnectionPool;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Install\Status\ErrorStatus;
22
23 /**
24 * Populate base tables, insert admin user, set install tool password
25 */
26 class DatabaseData extends AbstractStepAction
27 {
28 /**
29 * Import tables and data, create admin user, create install tool password
30 *
31 * @return \TYPO3\CMS\Install\Status\StatusInterface[]
32 */
33 public function execute()
34 {
35 $result = [];
36
37 /** @var ConfigurationManager $configurationManager */
38 $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
39
40 $postValues = $this->postValues['values'];
41
42 $username = (string)$postValues['username'] !== '' ? $postValues['username'] : 'admin';
43
44 // Check password and return early if not good enough
45 $password = $postValues['password'];
46 if (strlen($password) < 8) {
47 $errorStatus = GeneralUtility::makeInstance(ErrorStatus::class);
48 $errorStatus->setTitle('Administrator password not secure enough!');
49 $errorStatus->setMessage(
50 'You are setting an important password here! It gives an attacker full control over your instance if cracked.' .
51 ' It should be strong (include lower and upper case characters, special characters and numbers) and must be at least eight characters long.'
52 );
53 $result[] = $errorStatus;
54 return $result;
55 }
56
57 // Set site name
58 if (!empty($postValues['sitename'])) {
59 $configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $postValues['sitename']);
60 }
61
62 $result = $this->importDatabaseData();
63 if (!empty($result)) {
64 return $result;
65 }
66
67 // Insert admin user
68 $adminUserFields = [
69 'username' => $username,
70 'password' => $this->getHashedPassword($password),
71 'admin' => 1,
72 'tstamp' => $GLOBALS['EXEC_TIME'],
73 'crdate' => $GLOBALS['EXEC_TIME']
74 ];
75 $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)
76 ->getConnectionForTable('be_users');
77 try {
78 $databaseConnection->insert('be_users', $adminUserFields);
79 } catch (DBALException $exception) {
80 $errorStatus = GeneralUtility::makeInstance(ErrorStatus::class);
81 $errorStatus->setTitle('Administrator account not created!');
82 $errorStatus->setMessage(
83 'The administrator account could not be created. The following error occurred:' . LF .
84 $exception->getPrevious()->getMessage()
85 );
86 $result[] = $errorStatus;
87 return $result;
88 }
89
90 // Set password as install tool password
91 $configurationManager->setLocalConfigurationValueByPath('BE/installToolPassword', $this->getHashedPassword($password));
92
93 // Mark the initial import as done
94 $this->markImportDatabaseDone();
95
96 return $result;
97 }
98
99 /**
100 * Step needs to be executed if there are no tables in database
101 *
102 * @return bool
103 */
104 public function needsExecution()
105 {
106 $existingTables = $this->getDatabaseConnection()->admin_get_tables();
107 if (empty($existingTables)) {
108 $result = true;
109 } else {
110 $result = !$this->isImportDatabaseDone();
111 }
112 return $result;
113 }
114
115 /**
116 * Executes the step
117 *
118 * @return string Rendered content
119 */
120 protected function executeAction()
121 {
122 $this->assignSteps();
123 return $this->view->render();
124 }
125
126 /**
127 * Create tables and import static rows
128 *
129 * @return \TYPO3\CMS\Install\Status\StatusInterface[]
130 */
131 protected function importDatabaseData()
132 {
133 $result = [];
134 // Will load ext_localconf and ext_tables. This is pretty safe here since we are
135 // in first install (database empty), so it is very likely that no extension is loaded
136 // that could trigger a fatal at this point.
137 $this->loadExtLocalconfDatabaseAndExtTables();
138
139 // Import database data
140 $database = $this->getDatabaseConnection();
141 /** @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $schemaMigrationService */
142 $schemaMigrationService = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class);
143 /** @var \TYPO3\CMS\Install\Service\SqlExpectedSchemaService $expectedSchemaService */
144 $expectedSchemaService = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Service\SqlExpectedSchemaService::class);
145
146 // Raw concatenated ext_tables.sql and friends string
147 $expectedSchemaString = $expectedSchemaService->getTablesDefinitionString(true);
148 $statements = $schemaMigrationService->getStatementArray($expectedSchemaString, true);
149 list($_, $insertCount) = $schemaMigrationService->getCreateTables($statements, true);
150 $fieldDefinitionsFile = $schemaMigrationService->getFieldDefinitions_fileContent($expectedSchemaString);
151 $fieldDefinitionsDatabase = $schemaMigrationService->getFieldDefinitions_database();
152 $difference = $schemaMigrationService->getDatabaseExtra($fieldDefinitionsFile, $fieldDefinitionsDatabase);
153 $updateStatements = $schemaMigrationService->getUpdateSuggestions($difference);
154
155 foreach (['add', 'change', 'create_table'] as $action) {
156 $updateStatus = $schemaMigrationService->performUpdateQueries($updateStatements[$action], $updateStatements[$action]);
157 if ($updateStatus !== true) {
158 foreach ($updateStatus as $statementIdentifier => $errorMessage) {
159 $result[$updateStatements[$action][$statementIdentifier]] = $errorMessage;
160 }
161 }
162 }
163
164 if (empty($result)) {
165 foreach ($insertCount as $table => $count) {
166 $insertStatements = $schemaMigrationService->getTableInsertStatements($statements, $table);
167 foreach ($insertStatements as $insertQuery) {
168 $insertQuery = rtrim($insertQuery, ';');
169 $database->admin_query($insertQuery);
170 if ($database->sql_error()) {
171 $result[$insertQuery] = $database->sql_error();
172 }
173 }
174 }
175 }
176
177 foreach ($result as $statement => &$message) {
178 $errorStatus = GeneralUtility::makeInstance(ErrorStatus::class);
179 $errorStatus->setTitle('Database query failed!');
180 $errorStatus->setMessage(
181 'Query:' . LF .
182 ' ' . $statement . LF .
183 'Error:' . LF .
184 ' ' . $message
185 );
186 $message = $errorStatus;
187 }
188
189 return array_values($result);
190 }
191
192 /**
193 * Persist the information that the initial import has been performed
194 */
195 protected function markImportDatabaseDone()
196 {
197 GeneralUtility::makeInstance(ConfigurationManager::class)
198 ->setLocalConfigurationValueByPath('SYS/isInitialDatabaseImportDone', true);
199 }
200
201 /**
202 * Checks if the initial import has been performed
203 *
204 * @return bool
205 */
206 protected function isImportDatabaseDone()
207 {
208 return GeneralUtility::makeInstance(ConfigurationManager::class)
209 ->getConfigurationValueByPath('SYS/isInitialDatabaseImportDone');
210 }
211 }