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