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