[TASK] Remove last bits of forceCharset handling
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / StepController.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 *
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\Core\Utility\GeneralUtility;
28
29 /**
30 * Install step controller, dispatcher class of step actions.
31 */
32 class StepController extends AbstractController {
33
34 /**
35 * @var array List of valid action names that need authentication. Order is important!
36 */
37 protected $authenticationActions = array(
38 'environmentAndFolders',
39 'databaseConnect',
40 'databaseSelect',
41 'databaseData',
42 'defaultConfiguration',
43 );
44
45 /**
46 * @var array List of obsolete configuration options in LocalConfiguration to be removed
47 */
48 protected $obsoleteLocalConfigurationSettings = array(
49 // #34092
50 'BE/forceCharset',
51 // #26519
52 'BE/loginLabels',
53 // #44506
54 'BE/loginNews',
55 // #30613
56 'BE/useOnContextMenuHandler',
57 // #48179
58 'EXT/em_mirrorListURL',
59 'EXT/em_wsdlURL',
60 // #43094
61 'EXT/extList',
62 // #35877
63 'EXT/extList_FE',
64 // #41813
65 'EXT/noEdit',
66 // #26090
67 'FE/defaultTypoScript_editorcfg',
68 'FE/defaultTypoScript_editorcfg.',
69 // #25099
70 'FE/simulateStaticDocuments',
71 // #22687
72 'GFX/gdlib_2',
73 // #18431
74 'GFX/noIconProc',
75 // #17606
76 'GFX/TTFLocaleConv',
77 // #39164
78 'SYS/additionalAllowedClassPrefixes',
79 // #27689
80 'SYS/caching/cacheBackends',
81 'SYS/caching/cacheFrontends',
82 // #38414
83 'SYS/extCache',
84 // #35923
85 'SYS/multiplyDBfieldSize',
86 // #46993
87 'SYS/T3instID',
88 );
89
90 /**
91 * Index action acts a a dispatcher to different steps
92 *
93 * @throws Exception
94 * @return void
95 */
96 public function execute() {
97 $this->loadBaseExtensions();
98 $this->initializeObjectManager();
99
100 // Warning: Order of these methods is security relevant and interferes with different access
101 // conditions (new/existing installation). See the single method comments for details.
102 $this->outputInstallToolNotEnabledMessageIfNeeded();
103 $this->migrateLocalconfToLocalConfigurationIfNeeded();
104 $this->outputInstallToolPasswordNotSetMessageIfNeeded();
105 $this->removeObsoleteLocalConfigurationSettings();
106 $this->executeOrOutputFirstInstallStepIfNeeded();
107 $this->generateEncryptionKeyIfNeeded();
108 $this->initializeSession();
109 $this->checkSessionToken();
110 $this->checkSessionLifetime();
111 $this->loginIfRequested();
112 $this->outputLoginFormIfNotAuthorized();
113 $this->executeSpecificStep();
114 $this->outputSpecificStep();
115 $this->redirectToTool();
116 }
117
118 /**
119 * Execute a step action if requested. If executed, a redirect is done, so
120 * the next request will render step one again if needed or initiate a
121 * request to test the next step.
122 *
123 * @throws Exception
124 * @return void
125 */
126 protected function executeSpecificStep() {
127 $action = $this->getAction();
128 $postValues = $this->getPostValues();
129 if ($action && isset($postValues['set']) && $postValues['set'] === 'execute') {
130 $stepAction = $this->getActionInstance($action);
131 $stepAction->setAction($action);
132 $stepAction->setToken($this->generateTokenForAction($action));
133 $stepAction->setPostValues($this->getPostValues());
134 $messages = $stepAction->execute();
135 $this->addSessionMessages($messages);
136 $this->redirect();
137 }
138 }
139
140 /**
141 * Render a specific step. Fallback to first step if none is given.
142 * The according step is instantiated and 'needsExecution' is called. If
143 * it needs execution, the step will be rendered, otherwise a redirect
144 * to test the next step is initiated.
145 *
146 * @return void
147 */
148 protected function outputSpecificStep() {
149 $action = $this->getAction();
150 if ($action === '') {
151 // First step action
152 list($action) = $this->authenticationActions;
153 }
154 $stepAction = $this->getActionInstance($action);
155 $stepAction->setAction($action);
156 $stepAction->setController('step');
157 $stepAction->setToken($this->generateTokenForAction($action));
158 $stepAction->setPostValues($this->getPostValues());
159
160 if ($stepAction->needsExecution()) {
161 $stepAction->setMessages($this->session->getMessagesAndFlush());
162 $this->output($stepAction->handle());
163 } else {
164 // Redirect to next step if there are any
165 $currentPosition = array_keys($this->authenticationActions, $action, TRUE);
166 $nextAction = array_slice($this->authenticationActions, $currentPosition[0] + 1, 1);
167 if (!empty($nextAction)) {
168 $this->redirect('', $nextAction[0]);
169 }
170 }
171 }
172
173 /**
174 * Instantiate a specific action class
175 *
176 * @param string $action Action to instantiate
177 * @throws Exception
178 * @return \TYPO3\CMS\Install\Controller\Action\Step\StepInterface
179 */
180 protected function getActionInstance($action) {
181 $this->validateAuthenticationAction($action);
182 $actionClass = ucfirst($action);
183 /** @var \TYPO3\CMS\Install\Controller\Action\Step\StepInterface $stepAction */
184 $stepAction = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Step\\' . $actionClass);
185 if (!($stepAction instanceof Action\Step\StepInterface)) {
186 throw new Exception(
187 $action . ' does non implement StepInterface',
188 1371303903
189 );
190 }
191 return $stepAction;
192 }
193
194 /**
195 * If the last step was reached and none needs execution, a redirect
196 * to call the tool controller is initiated.
197 *
198 * @return void
199 */
200 protected function redirectToTool() {
201 $this->redirect('tool');
202 }
203
204 /**
205 * "Silent" upgrade very early in step installer, before rendering step 1:
206 * If typo3conf and typo3conf/localconf.php exist, but no typo3conf/LocalConfiguration,
207 * create LocalConfiguration.php / AdditionalConfiguration.php from localconf.php
208 * Might throw exception if typo3conf directory is not writable.
209 *
210 * @return void
211 */
212 protected function migrateLocalconfToLocalConfigurationIfNeeded() {
213 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
214 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
215
216 $localConfigurationFileLocation = $configurationManager->getLocalConfigurationFileLocation();
217 $localConfigurationFileExists = is_file($localConfigurationFileLocation);
218 $localConfFileLocation = PATH_typo3conf . 'localconf.php';
219 $localConfFileExists = is_file($localConfFileLocation);
220
221 if (is_dir(PATH_typo3conf) && $localConfFileExists && !$localConfigurationFileExists) {
222 $localConfContent = file($localConfFileLocation);
223
224 // Line array for the three categories: localConfiguration, db settings, additionalConfiguration
225 $typo3ConfigurationVariables = array();
226 $typo3DatabaseVariables = array();
227 $additionalConfiguration = array();
228 foreach ($localConfContent as $line) {
229 $line = trim($line);
230 $matches = array();
231 // Convert extList to array
232 if (
233 preg_match('/^\\$TYPO3_CONF_VARS\\[\'EXT\'\\]\\[\'extList\'\\] *={1} *\'(.+)\';{1}/', $line, $matches) === 1
234 || preg_match('/^\\$GLOBALS\\[\'TYPO3_CONF_VARS\'\\]\\[\'EXT\'\\]\\[\'extList\'\\] *={1} *\'(.+)\';{1}/', $line, $matches) === 1
235 ) {
236 $extListAsArray = GeneralUtility::trimExplode(',', $matches[1], TRUE);
237 $typo3ConfigurationVariables[] = '$TYPO3_CONF_VARS[\'EXT\'][\'extListArray\'] = ' . var_export($extListAsArray, TRUE) . ';';
238 } elseif (
239 preg_match('/^\\$TYPO3_CONF_VARS.+;{1}/', $line, $matches) === 1
240 ) {
241 $typo3ConfigurationVariables[] = $matches[0];
242 } elseif (
243 preg_match('/^\\$GLOBALS\\[\'TYPO3_CONF_VARS\'\\].+;{1}/', $line, $matches) === 1
244 ) {
245 $lineWithoutGlobals = str_replace('$GLOBALS[\'TYPO3_CONF_VARS\']', '$TYPO3_CONF_VARS', $matches[0]);
246 $typo3ConfigurationVariables[] = $lineWithoutGlobals;
247 } elseif (
248 preg_match('/^\\$typo_db.+;{1}/', $line, $matches) === 1
249 ) {
250 eval($matches[0]);
251 if (isset($typo_db_host)) {
252 $typo3DatabaseVariables['host'] = $typo_db_host;
253 } elseif (isset($typo_db)) {
254 $typo3DatabaseVariables['database'] = $typo_db;
255 } elseif (isset($typo_db_username)) {
256 $typo3DatabaseVariables['username'] = $typo_db_username;
257 } elseif (isset($typo_db_password)) {
258 $typo3DatabaseVariables['password'] = $typo_db_password;
259 } elseif (isset($typo_db_extTableDef_script)) {
260 $typo3DatabaseVariables['extTablesDefinitionScript'] = $typo_db_extTableDef_script;
261 }
262 unset($typo_db_host, $typo_db, $typo_db_username, $typo_db_password, $typo_db_extTableDef_script);
263 } elseif (
264 strlen($line) > 0 && preg_match('/^\\/\\/.+|^#.+|^<\\?php$|^<\\?$|^\\?>$/', $line, $matches) === 0
265 ) {
266 $additionalConfiguration[] = $line;
267 }
268 }
269
270 // Build new TYPO3_CONF_VARS array
271 $TYPO3_CONF_VARS = NULL;
272 eval(implode(LF, $typo3ConfigurationVariables));
273
274 // Add db settings to array
275 $TYPO3_CONF_VARS['DB'] = $typo3DatabaseVariables;
276 $TYPO3_CONF_VARS = \TYPO3\CMS\Core\Utility\ArrayUtility::sortByKeyRecursive($TYPO3_CONF_VARS);
277
278 // Write out new LocalConfiguration file
279 $configurationManager->writeLocalConfiguration($TYPO3_CONF_VARS);
280
281 // Write out new AdditionalConfiguration file
282 if (sizeof($additionalConfiguration) > 0) {
283 $configurationManager->writeAdditionalConfiguration($additionalConfiguration);
284 } else {
285 @unlink($configurationManager->getAdditionalConfigurationFileLocation());
286 }
287
288 // Move localconf.php to localconf.obsolete.php
289 rename($localConfFileLocation, PATH_site . 'typo3conf/localconf.obsolete.php');
290
291 // Perform a reload to self, so bootstrap now uses new LocalConfiguration.php
292 $this->redirect();
293 }
294 }
295
296 /**
297 * Some settings in LocalConfiguration vanished in DefaultConfiguration
298 * and have no impact on the core anymore.
299 * To keep the configuration clean, those old settings are just silently
300 * removed from LocalConfiguration if set.
301 *
302 * @return void
303 */
304 protected function removeObsoleteLocalConfigurationSettings() {
305 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
306 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
307 $removed = $configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
308 // If something was changed: Trigger a reload to have new values in next request
309 if ($removed) {
310 $this->redirect();
311 }
312 }
313
314 /**
315 * The first install step has a special standing and needs separate handling:
316 * At this point no directory exists (no typo3conf, no typo3temp), so we can
317 * not start the session handling (that stores the install tool session within typo3temp).
318 * This also means, we can not start the token handling for CSRF protection. This
319 * is no real problem, since no local configuration or other security relevant
320 * information was created yet.
321 *
322 * So, if no typo3conf directory exists yet, the first step is just rendered, or
323 * executed if called so. After that, a redirect is initiated to proceed with
324 * other tasks.
325 *
326 * @return void
327 */
328 protected function executeOrOutputFirstInstallStepIfNeeded() {
329 $postValues = $this->getPostValues();
330
331 $wasExecuted= FALSE;
332 $errorMessagesFromExecute = array();
333 if (isset($postValues['action'])
334 && $postValues['action'] === 'environmentAndFolders'
335 ) {
336 /** @var \TYPO3\CMS\Install\Controller\Action\Step\StepInterface $action */
337 $action = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Step\\EnvironmentAndFolders');
338 $errorMessagesFromExecute = $action->execute();
339 $wasExecuted = TRUE;
340 }
341
342 /** @var \TYPO3\CMS\Install\Controller\Action\Step\StepInterface $action */
343 $action = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Step\\EnvironmentAndFolders');
344 $needsExecution = $action->needsExecution();
345
346 if (!is_dir(PATH_typo3conf)
347 || count($errorMessagesFromExecute) > 0
348 || $needsExecution
349 ) {
350 /** @var \TYPO3\CMS\Install\Controller\Action\Step\StepInterface $action */
351 $action = $this->objectManager->get('TYPO3\\CMS\\Install\\Controller\\Action\\Step\\EnvironmentAndFolders');
352 $action->setController('step');
353 $action->setAction('environmentAndFolders');
354 if (count($errorMessagesFromExecute) > 0) {
355 $action->setMessages($errorMessagesFromExecute);
356 }
357 $this->output($action->handle());
358 }
359
360 if ($wasExecuted) {
361 $this->redirect();
362 }
363 }
364
365 /**
366 * "Silent" upgrade: The encryption key is crucial for securing form tokens
367 * and the whole TYPO3 link rendering later on. A random key is set here in
368 * LocalConfiguration if it does not exist yet. This might possible happen
369 * during upgrading and will happen during first install.
370 *
371 * @return void
372 */
373 protected function generateEncryptionKeyIfNeeded() {
374 if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
375 $randomKey = GeneralUtility::getRandomHexString(96);
376 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
377 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
378 $configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
379 $this->redirect();
380 }
381 }
382 }
383 ?>