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