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