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