[TASK] Refactor install tool enable file checks
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / ToolController.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller;
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 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Install\Service\EnableFileService;
31
32 /**
33 * Install tool controller, dispatcher class of the install tool.
34 *
35 * Handles install tool session, login and login form rendering,
36 * calls actions that need authentication and handles form tokens.
37 */
38 class ToolController extends AbstractController {
39
40 /**
41 * @var array List of valid action names that need authentication
42 */
43 protected $authenticationActions = array(
44 'welcome',
45 'importantActions',
46 'systemEnvironment',
47 'configuration',
48 'folderStructure',
49 'testSetup',
50 'upgradeWizard',
51 'allConfiguration',
52 'cleanUp',
53 'loadExtensions',
54 );
55
56 /**
57 * Main dispatch method
58 *
59 * @return void
60 */
61 public function execute() {
62 $this->loadBaseExtensions();
63 $this->initializeObjectManager();
64
65 // Warning: Order of these methods is security relevant and interferes with different access
66 // conditions (new/existing installation). See the single method comments for details.
67 $this->outputInstallToolNotEnabledMessageIfNeeded();
68 $this->outputInstallToolPasswordNotSetMessageIfNeeded();
69 $this->initializeSession();
70 $this->checkSessionToken();
71 $this->checkSessionLifetime();
72 $this->logoutIfRequested();
73 $this->loginIfRequested();
74 $this->outputLoginFormIfNotAuthorized();
75 $this->registerExtensionConfigurationErrorHandler();
76 $this->dispatchAuthenticationActions();
77 }
78
79 /**
80 * Logout user if requested
81 *
82 * @return void
83 */
84 protected function logoutIfRequested() {
85 $action = $this->getAction();
86 if ($action === 'logout') {
87 if (!EnableFileService::isInstallToolEnableFilePermanent()) {
88 EnableFileService::removeInstallToolEnableFile();
89 }
90
91 /** @var $formProtection \TYPO3\CMS\Core\FormProtection\InstallToolFormProtection */
92 $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get(
93 'TYPO3\\CMS\\Core\\FormProtection\\InstallToolFormProtection'
94 );
95 $formProtection->clean();
96 $this->session->destroySession();
97 $this->redirect();
98 }
99 }
100
101 /**
102 * This function registers a shutdown function, which is called even if a fatal error occurs.
103 * The request either gets redirected to an action where all extension configurations are checked for compatibility or
104 * an information with a link to that action.
105 *
106 * @return void
107 */
108 protected function registerExtensionConfigurationErrorHandler() {
109 register_shutdown_function(function() {
110 $error = error_get_last();
111 if ($error !== NULL) {
112 $errorType = $error["type"];
113
114 if ($errorType & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
115 $getPostValues = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('install');
116
117 $parameters = array();
118
119 // Add context parameter in case this script was called within backend scope
120 $context = 'install[context]=standalone';
121 if (isset($getPostValues['context']) && $getPostValues['context'] === 'backend') {
122 $context = 'install[context]=backend';
123 }
124 $parameters[] = $context;
125
126 // Add controller parameter
127 $parameters[] = 'install[controller]=tool';
128
129 // Add action if specified
130 $parameters[] = 'install[action]=loadExtensions';
131
132 // Add error to display a message what triggered the check
133 $errorEncoded = json_encode($error);
134 $parameters[] = 'install[lastError]=' . rawurlencode($errorEncoded);
135 // We do not use GeneralUtility here to be sure that hash generation works even if that class might not exist any more.
136 $parameters[] = 'install[lastErrorHash]=' . hash_hmac('sha1', $errorEncoded, $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . 'InstallToolError');
137
138 $redirectLocation = 'Install.php?' . implode('&', $parameters);
139
140 if (!headers_sent()) {
141 \TYPO3\CMS\Core\Utility\HttpUtility::redirect(
142 $redirectLocation,
143 \TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_303
144 );
145 } else {
146 echo '
147 <p><strong>
148 The system detected a fatal error during script execution.
149 Please use the <a href="' . $redirectLocation . '">extension check tool</a> to find incompatible extensions.
150 </strong></p>';
151 }
152 }
153 }
154 });
155 }
156
157 /**
158 * Get last error values of install tool.
159 *
160 * @return array
161 */
162 protected function getLastError() {
163 $getVars = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('install');
164 $lastError = array();
165 if (isset($getVars['lastError']) && isset($getVars['lastErrorHash']) && !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
166 $calculatedHash = hash_hmac('sha1', $getVars['lastError'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . 'InstallToolError');
167 if ($calculatedHash === $getVars['lastErrorHash']) {
168 $lastError = json_decode($getVars['lastError'], TRUE);
169 }
170 }
171 return $lastError;
172 }
173
174 /**
175 * Call an action that needs authentication
176 *
177 * @throws Exception
178 * @return string Rendered content
179 */
180 protected function dispatchAuthenticationActions() {
181 $action = $this->getAction();
182 if ($action === '') {
183 $action = 'welcome';
184 }
185 $this->validateAuthenticationAction($action);
186 $actionClass = ucfirst($action);
187 /** @var \TYPO3\CMS\Install\Controller\Action\ActionInterface $toolAction */
188 $toolAction = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Tool\\' . $actionClass);
189 if (!($toolAction instanceof Action\ActionInterface)) {
190 throw new Exception(
191 $action . ' does not implement ActionInterface',
192 1369474309
193 );
194 }
195 $toolAction->setController('tool');
196 $toolAction->setAction($action);
197 $toolAction->setToken($this->generateTokenForAction($action));
198 $toolAction->setPostValues($this->getPostValues());
199 $toolAction->setLastError($this->getLastError());
200 $this->output($toolAction->handle());
201 }
202 }