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