[CLEANUP] Replace strlen() with === for zero length check
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Tool / ImportantActions.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Tool;
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\Install\Controller\Action;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\OpcodeCacheUtility;
20
21 /**
22 * Handle important actions
23 */
24 class ImportantActions extends Action\AbstractAction {
25
26 /**
27 * Executes the tool
28 *
29 * @return string Rendered content
30 */
31 protected function executeAction() {
32 if (isset($this->postValues['set']['changeEncryptionKey'])) {
33 $this->setNewEncryptionKeyAndLogOut();
34 }
35
36 $actionMessages = array();
37 if (isset($this->postValues['set']['changeInstallToolPassword'])) {
38 $actionMessages[] = $this->changeInstallToolPassword();
39 }
40 if (isset($this->postValues['set']['changeSiteName'])) {
41 $actionMessages[] = $this->changeSiteName();
42 }
43 if (isset($this->postValues['set']['createAdministrator'])) {
44 $actionMessages[] = $this->createAdministrator();
45 }
46 if (isset($this->postValues['set']['clearAllCache'])) {
47 $actionMessages[] = $this->clearAllCache();
48 }
49 if (isset($this->postValues['set']['clearOpcodeCache'])) {
50 $actionMessages[] = $this->clearOpcodeCache();
51 }
52
53 // Database analyzer handling
54 if (isset($this->postValues['set']['databaseAnalyzerExecute'])
55 || isset($this->postValues['set']['databaseAnalyzerAnalyze'])
56 ) {
57 $this->loadExtLocalconfDatabaseAndExtTables();
58 }
59 if (isset($this->postValues['set']['databaseAnalyzerExecute'])) {
60 $actionMessages = array_merge($actionMessages, $this->databaseAnalyzerExecute());
61 }
62 if (isset($this->postValues['set']['databaseAnalyzerAnalyze'])) {
63 $actionMessages[] = $this->databaseAnalyzerAnalyze();
64 }
65
66 $this->view->assign('actionMessages', $actionMessages);
67
68 $operatingSystem = TYPO3_OS === 'WIN' ? 'Windows' : 'Unix';
69
70 /** @var \TYPO3\CMS\Install\Service\CoreUpdateService $coreUpdateService */
71 $coreUpdateService = $this->objectManager->get(\TYPO3\CMS\Install\Service\CoreUpdateService::class);
72 $this->view
73 ->assign('enableCoreUpdate', $coreUpdateService->isCoreUpdateEnabled())
74 ->assign('operatingSystem', $operatingSystem)
75 ->assign('cgiDetected', GeneralUtility::isRunningOnCgiServerApi())
76 ->assign('databaseName', $GLOBALS['TYPO3_CONF_VARS']['DB']['database'])
77 ->assign('databaseUsername', $GLOBALS['TYPO3_CONF_VARS']['DB']['username'])
78 ->assign('databaseHost', $GLOBALS['TYPO3_CONF_VARS']['DB']['host'])
79 ->assign('databasePort', $GLOBALS['TYPO3_CONF_VARS']['DB']['port'])
80 ->assign('databaseSocket', $GLOBALS['TYPO3_CONF_VARS']['DB']['socket'])
81 ->assign('databaseNumberOfTables', count($this->getDatabaseConnection()->admin_get_tables()))
82 ->assign('extensionCompatibilityTesterProtocolFile', GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'typo3temp/ExtensionCompatibilityTester.txt')
83 ->assign('extensionCompatibilityTesterErrorProtocolFile', GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'typo3temp/ExtensionCompatibilityTesterErrors.json')
84 ->assign('listOfOpcodeCaches', OpcodeCacheUtility::getAllActive());
85
86 return $this->view->render();
87 }
88
89 /**
90 * Set new password if requested
91 *
92 * @return \TYPO3\CMS\Install\Status\StatusInterface
93 */
94 protected function changeInstallToolPassword() {
95 $values = $this->postValues['values'];
96 if ($values['newInstallToolPassword'] !== $values['newInstallToolPasswordCheck']) {
97 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
98 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
99 $message->setTitle('Install tool password not changed');
100 $message->setMessage('Given passwords do not match.');
101 } elseif (strlen($values['newInstallToolPassword']) < 8) {
102 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
103 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
104 $message->setTitle('Install tool password not changed');
105 $message->setMessage('Given password must be at least eight characters long.');
106 } else {
107 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
108 $configurationManager = $this->objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
109 $configurationManager->setLocalConfigurationValueByPath(
110 'BE/installToolPassword',
111 $this->getHashedPassword($values['newInstallToolPassword'])
112 );
113 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
114 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
115 $message->setTitle('Install tool password changed');
116 }
117 return $message;
118 }
119
120 /**
121 * Set new site name
122 *
123 * @return \TYPO3\CMS\Install\Status\StatusInterface
124 */
125 protected function changeSiteName() {
126 $values = $this->postValues['values'];
127 if (isset($values['newSiteName']) && $values['newSiteName'] !== '') {
128 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
129 $configurationManager = $this->objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
130 $configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $values['newSiteName']);
131 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
132 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
133 $message->setTitle('Site name changed');
134 $this->view->assign('siteName', $values['newSiteName']);
135 } else {
136 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
137 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
138 $message->setTitle('Site name not changed');
139 $message->setMessage('Site name must be at least one character long.');
140 }
141 return $message;
142 }
143
144 /**
145 * Clear all caches
146 *
147 * @return \TYPO3\CMS\Install\Status\StatusInterface
148 */
149 protected function clearAllCache() {
150 /** @var \TYPO3\CMS\Install\Service\ClearCacheService $clearCacheService */
151 $clearCacheService = $this->objectManager->get(\TYPO3\CMS\Install\Service\ClearCacheService::class);
152 $clearCacheService->clearAll();
153 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
154 $message->setTitle('Successfully cleared all caches');
155 return $message;
156 }
157
158 /**
159 * Clear PHP opcode cache
160 *
161 * @return \TYPO3\CMS\Install\Status\StatusInterface
162 */
163 protected function clearOpcodeCache() {
164 /** @var \TYPO3\CMS\Install\Service\ClearCacheService $clearCacheService */
165 OpcodeCacheUtility::clearAllActive();
166 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
167 $message->setTitle('Successfully cleared all available opcode caches');
168 return $message;
169 }
170
171 /**
172 * Set new encryption key
173 *
174 * @return void
175 */
176 protected function setNewEncryptionKeyAndLogOut() {
177 $newKey = \TYPO3\CMS\Core\Utility\GeneralUtility::getRandomHexString(96);
178 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
179 $configurationManager = $this->objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
180 $configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $newKey);
181 /** @var $formProtection \TYPO3\CMS\Core\FormProtection\InstallToolFormProtection */
182 $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get(
183 \TYPO3\CMS\Core\FormProtection\InstallToolFormProtection::class
184 );
185 $formProtection->clean();
186 /** @var \TYPO3\CMS\Install\Service\SessionService $session */
187 $session = $this->objectManager->get(\TYPO3\CMS\Install\Service\SessionService::class);
188 $session->destroySession();
189 \TYPO3\CMS\Core\Utility\HttpUtility::redirect('Install.php?install[context]=' . $this->getContext());
190 }
191
192 /**
193 * Create administrator user
194 *
195 * @return \TYPO3\CMS\Install\Status\StatusInterface
196 */
197 protected function createAdministrator() {
198 $values = $this->postValues['values'];
199 $username = preg_replace('/[^\\da-z._]/i', '', trim($values['newUserUsername']));
200 $password = $values['newUserPassword'];
201 $passwordCheck = $values['newUserPasswordCheck'];
202
203 if (strlen($username) < 1) {
204 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
205 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
206 $message->setTitle('Administrator user not created');
207 $message->setMessage('No valid username given.');
208 } elseif ($password !== $passwordCheck) {
209 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
210 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
211 $message->setTitle('Administrator user not created');
212 $message->setMessage('Passwords do not match.');
213 } elseif (strlen($password) < 8) {
214 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
215 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
216 $message->setTitle('Administrator user not created');
217 $message->setMessage('Password must be at least eight characters long.');
218 } else {
219 $database = $this->getDatabaseConnection();
220 $userExists = $database->exec_SELECTcountRows(
221 'uid',
222 'be_users',
223 'username=' . $database->fullQuoteStr($username, 'be_users')
224 );
225 if ($userExists) {
226 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
227 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
228 $message->setTitle('Administrator user not created');
229 $message->setMessage('A user with username ' . $username . ' exists already.');
230 } else {
231 $hashedPassword = $this->getHashedPassword($password);
232 $adminUserFields = array(
233 'username' => $username,
234 'password' => $hashedPassword,
235 'admin' => 1,
236 'tstamp' => $GLOBALS['EXEC_TIME'],
237 'crdate' => $GLOBALS['EXEC_TIME']
238 );
239 $database->exec_INSERTquery('be_users', $adminUserFields);
240 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
241 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
242 $message->setTitle('Administrator created');
243 }
244 }
245
246 return $message;
247 }
248
249 /**
250 * Execute database migration
251 *
252 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
253 */
254 protected function databaseAnalyzerExecute() {
255 $messages = array();
256
257 // Early return in case no update was selected
258 if (empty($this->postValues['values'])) {
259 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
260 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\WarningStatus::class);
261 $message->setTitle('No database changes selected');
262 $messages[] = $message;
263 return $messages;
264 }
265
266 /** @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $schemaMigrationService */
267 $schemaMigrationService = $this->objectManager->get(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class);
268 /** @var \TYPO3\CMS\Install\Service\SqlExpectedSchemaService $expectedSchemaService */
269 $expectedSchemaService = $this->objectManager->get(\TYPO3\CMS\Install\Service\SqlExpectedSchemaService::class);
270 $expectedSchema = $expectedSchemaService->getExpectedDatabaseSchema();
271 $currentSchema = $schemaMigrationService->getFieldDefinitions_database();
272
273 $statementHashesToPerform = $this->postValues['values'];
274
275 $results = array();
276
277 // Difference from expected to current
278 $addCreateChange = $schemaMigrationService->getDatabaseExtra($expectedSchema, $currentSchema);
279 $addCreateChange = $schemaMigrationService->getUpdateSuggestions($addCreateChange);
280 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['add'], $statementHashesToPerform);
281 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['change'], $statementHashesToPerform);
282 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['create_table'], $statementHashesToPerform);
283
284 // Difference from current to expected
285 $dropRename = $schemaMigrationService->getDatabaseExtra($currentSchema, $expectedSchema);
286 $dropRename = $schemaMigrationService->getUpdateSuggestions($dropRename, 'remove');
287 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['change'], $statementHashesToPerform);
288 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['drop'], $statementHashesToPerform);
289 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['change_table'], $statementHashesToPerform);
290 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['drop_table'], $statementHashesToPerform);
291
292 // Create error flash messages if any
293 foreach ($results as $resultSet) {
294 if (is_array($resultSet)) {
295 foreach ($resultSet as $errorMessage) {
296 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
297 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
298 $message->setTitle('Database update failed');
299 $message->setMessage('Error: ' . $errorMessage);
300 $messages[] = $message;
301 }
302 }
303 }
304
305 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
306 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
307 $message->setTitle('Executed database updates');
308 $messages[] = $message;
309
310 return $messages;
311 }
312
313 /**
314 * "Compare" action of analyzer
315 *
316 * @TODO: The SchemaMigration API is a mess and should be refactored
317 * @TODO: Refactoring this should aim to make EM and dbal independent from ext:install by moving SchemaMigration to ext:core
318 * @return \TYPO3\CMS\Install\Status\StatusInterface
319 */
320 protected function databaseAnalyzerAnalyze() {
321 /** @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $schemaMigrationService */
322 $schemaMigrationService = $this->objectManager->get(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class);
323 /** @var \TYPO3\CMS\Install\Service\SqlExpectedSchemaService $expectedSchemaService */
324 $expectedSchemaService = $this->objectManager->get(\TYPO3\CMS\Install\Service\SqlExpectedSchemaService::class);
325 $expectedSchema = $expectedSchemaService->getExpectedDatabaseSchema();
326
327 $currentSchema = $schemaMigrationService->getFieldDefinitions_database();
328
329 $databaseAnalyzerSuggestion = array();
330
331 // Difference from expected to current
332 $addCreateChange = $schemaMigrationService->getDatabaseExtra($expectedSchema, $currentSchema);
333 $addCreateChange = $schemaMigrationService->getUpdateSuggestions($addCreateChange);
334 if (isset($addCreateChange['create_table'])) {
335 $databaseAnalyzerSuggestion['addTable'] = array();
336 foreach ($addCreateChange['create_table'] as $hash => $statement) {
337 $databaseAnalyzerSuggestion['addTable'][$hash] = array(
338 'hash' => $hash,
339 'statement' => $statement,
340 );
341 }
342 }
343 if (isset($addCreateChange['add'])) {
344 $databaseAnalyzerSuggestion['addField'] = array();
345 foreach ($addCreateChange['add'] as $hash => $statement) {
346 $databaseAnalyzerSuggestion['addField'][$hash] = array(
347 'hash' => $hash,
348 'statement' => $statement,
349 );
350 }
351 }
352 if (isset($addCreateChange['change'])) {
353 $databaseAnalyzerSuggestion['change'] = array();
354 foreach ($addCreateChange['change'] as $hash => $statement) {
355 $databaseAnalyzerSuggestion['change'][$hash] = array(
356 'hash' => $hash,
357 'statement' => $statement,
358 );
359 if (isset($addCreateChange['change_currentValue'][$hash])) {
360 $databaseAnalyzerSuggestion['change'][$hash]['current'] = $addCreateChange['change_currentValue'][$hash];
361 }
362 }
363 }
364
365 // Difference from current to expected
366 $dropRename = $schemaMigrationService->getDatabaseExtra($currentSchema, $expectedSchema);
367 $dropRename = $schemaMigrationService->getUpdateSuggestions($dropRename, 'remove');
368 if (isset($dropRename['change_table'])) {
369 $databaseAnalyzerSuggestion['renameTableToUnused'] = array();
370 foreach ($dropRename['change_table'] as $hash => $statement) {
371 $databaseAnalyzerSuggestion['renameTableToUnused'][$hash] = array(
372 'hash' => $hash,
373 'statement' => $statement,
374 );
375 if (!empty($dropRename['tables_count'][$hash])) {
376 $databaseAnalyzerSuggestion['renameTableToUnused'][$hash]['count'] = $dropRename['tables_count'][$hash];
377 }
378 }
379 }
380 if (isset($dropRename['change'])) {
381 $databaseAnalyzerSuggestion['renameTableFieldToUnused'] = array();
382 foreach ($dropRename['change'] as $hash => $statement) {
383 $databaseAnalyzerSuggestion['renameTableFieldToUnused'][$hash] = array(
384 'hash' => $hash,
385 'statement' => $statement,
386 );
387 }
388 }
389 if (isset($dropRename['drop'])) {
390 $databaseAnalyzerSuggestion['deleteField'] = array();
391 foreach ($dropRename['drop'] as $hash => $statement) {
392 $databaseAnalyzerSuggestion['deleteField'][$hash] = array(
393 'hash' => $hash,
394 'statement' => $statement,
395 );
396 }
397 }
398 if (isset($dropRename['drop_table'])) {
399 $databaseAnalyzerSuggestion['deleteTable'] = array();
400 foreach ($dropRename['drop_table'] as $hash => $statement) {
401 $databaseAnalyzerSuggestion['deleteTable'][$hash] = array(
402 'hash' => $hash,
403 'statement' => $statement,
404 );
405 if (!empty($dropRename['tables_count'][$hash])) {
406 $databaseAnalyzerSuggestion['deleteTable'][$hash]['count'] = $dropRename['tables_count'][$hash];
407 }
408 }
409 }
410
411 $this->view->assign('databaseAnalyzerSuggestion', $databaseAnalyzerSuggestion);
412
413 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
414 $message = $this->objectManager->get(\TYPO3\CMS\Install\Status\OkStatus::class);
415 $message->setTitle('Analyzed current database');
416 return $message;
417 }
418
419 }