[TASK] Only set FE user cookie if session data or user logged in
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Service / SilentConfigurationUpgradeService.php
1 <?php
2 namespace TYPO3\CMS\Install\Service;
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\ExtensionManagementUtility;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * Execute "silent" LocalConfiguration upgrades if needed.
32 *
33 * Some LocalConfiguration settings are obsolete or changed over time.
34 * This class handles upgrades of these settings. It is called by
35 * the step controller at an early point.
36 *
37 * Every change is encapsulated in one method an must throw a RedirectException
38 * if new data is written to LocalConfiguration. This is caught by above
39 * step controller to initiate a redirect and start again with adapted configuration.
40 */
41 class SilentConfigurationUpgradeService {
42
43 /**
44 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
45 * @inject
46 */
47 protected $objectManager = NULL;
48
49 /**
50 * @var \TYPO3\CMS\Core\Configuration\ConfigurationManager
51 * @inject
52 */
53 protected $configurationManager = NULL;
54
55 /**
56 * @var array List of obsolete configuration options in LocalConfiguration to be removed
57 */
58 protected $obsoleteLocalConfigurationSettings = array(
59 // #34092
60 'BE/forceCharset',
61 // #26519
62 'BE/loginLabels',
63 // #44506
64 'BE/loginNews',
65 // #52013
66 'BE/TSconfigConditions',
67 // #30613
68 'BE/useOnContextMenuHandler',
69 // #48179
70 'EXT/em_mirrorListURL',
71 'EXT/em_wsdlURL',
72 // #43094
73 'EXT/extList',
74 // #47018
75 'EXT/extListArray',
76 // #35877
77 'EXT/extList_FE',
78 // #41813
79 'EXT/noEdit',
80 // #47018
81 'EXT/requiredExt',
82 // #26090
83 'FE/defaultTypoScript_editorcfg',
84 'FE/defaultTypoScript_editorcfg.',
85 // #25099
86 'FE/simulateStaticDocuments',
87 // #52786
88 'FE/logfile_dir',
89 // #55549
90 'FE/dontSetCookie',
91 // #52011
92 'GFX/im_combine_filename',
93 // #52088
94 'GFX/im_imvMaskState',
95 // #22687
96 'GFX/gdlib_2',
97 // #52012
98 'GFX/im_mask_temp_ext_noloss',
99 // #52088
100 'GFX/im_negate_mask',
101 // #52010
102 'GFX/im_no_effects',
103 // #18431
104 'GFX/noIconProc',
105 // #17606
106 'GFX/TTFLocaleConv',
107 // #39164
108 'SYS/additionalAllowedClassPrefixes',
109 // #27689
110 'SYS/caching/cacheBackends',
111 'SYS/caching/cacheFrontends',
112 // #38414
113 'SYS/extCache',
114 // #35923
115 'SYS/multiplyDBfieldSize',
116 // #46993
117 'SYS/T3instID',
118 // #52857
119 'SYS/forceReturnPath',
120 );
121
122 /**
123 * Executed configuration upgrades. Single upgrade methods must throw a
124 * RedirectException if something was written to LocalConfiguration.
125 *
126 * @return void
127 */
128 public function execute() {
129 $this->generateEncryptionKeyIfNeeded();
130 $this->configureBackendLoginSecurity();
131 $this->configureSaltedPasswords();
132 $this->migrateOldInstallWizardDoneSettingsToNewClassNames();
133 $this->setProxyAuthScheme();
134 $this->disableImageMagickAndGdlibIfImageProcessingIsDisabled();
135 $this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
136 $this->setImageMagickDetailSettings();
137 $this->addFileTableToDefaultCategorizedTablesIfAlreadyCustomized();
138 $this->removeObsoleteLocalConfigurationSettings();
139 }
140
141 /**
142 * Some settings in LocalConfiguration vanished in DefaultConfiguration
143 * and have no impact on the core anymore.
144 * To keep the configuration clean, those old settings are just silently
145 * removed from LocalConfiguration if set.
146 *
147 * @return void
148 */
149 protected function removeObsoleteLocalConfigurationSettings() {
150 $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
151
152 // The old default value is not needed anymore. So if the user
153 // did not set a different value we can remove it.
154 $currentSetDbInitValue = $this->configurationManager->getConfigurationValueByPath('SYS/setDBinit');
155 if (preg_match('/^\s*SET\s+NAMES\s+[\'"]?utf8[\'"]?\s*[;]?\s*$/i', $currentSetDbInitValue) === 1) {
156 $removed = $removed || $this->configurationManager->removeLocalConfigurationKeysByPath(array('SYS/setDBinit'));
157 }
158
159 // If something was changed: Trigger a reload to have new values in next request
160 if ($removed) {
161 $this->throwRedirectException();
162 }
163 }
164
165 /**
166 * Backend login security is set to rsa if rsaauth
167 * is installed (but not used) otherwise the default value "normal" has to be used.
168 * This forces either 'normal' or 'rsa' to be set in LocalConfiguration.
169 *
170 * @return void
171 */
172 protected function configureBackendLoginSecurity() {
173 try {
174 $currentLoginSecurityLevelValue = $this->configurationManager->getLocalConfigurationValueByPath('BE/loginSecurityLevel');
175 if (ExtensionManagementUtility::isLoaded('rsaauth')
176 && $currentLoginSecurityLevelValue !== 'rsa'
177 ) {
178 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
179 $this->throwRedirectException();
180 } elseif (!ExtensionManagementUtility::isLoaded('rsaauth')
181 && $currentLoginSecurityLevelValue !== 'normal'
182 ) {
183 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
184 $this->throwRedirectException();
185 }
186 } catch (\RuntimeException $e) {
187 // If an exception is thrown, the value is not set in LocalConfiguration
188 if (ExtensionManagementUtility::isLoaded('rsaauth')) {
189 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
190 $this->throwRedirectException();
191 } elseif (!ExtensionManagementUtility::isLoaded('rsaauth')) {
192 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
193 $this->throwRedirectException();
194 }
195 }
196 }
197
198 /**
199 * Check the settings for salted passwords extension to load it as a required extension.
200 * Unset obsolete configuration options if given.
201 *
202 * @return void
203 */
204 protected function configureSaltedPasswords() {
205 $defaultConfiguration = $this->configurationManager->getDefaultConfiguration();
206 $defaultExtensionConfiguration = unserialize($defaultConfiguration['EXT']['extConf']['saltedpasswords']);
207 try {
208 $extensionConfiguration = @unserialize($this->configurationManager->getLocalConfigurationValueByPath('EXT/extConf/saltedpasswords'));
209 } catch (\RuntimeException $e) {
210 $extensionConfiguration = array();
211 }
212 if (is_array($extensionConfiguration) && !empty($extensionConfiguration)) {
213 if (isset($extensionConfiguration['BE.']['enabled'])) {
214 if ($extensionConfiguration['BE.']['enabled']) {
215 unset($extensionConfiguration['BE.']['enabled']);
216 } else {
217 $extensionConfiguration['BE.'] = $defaultExtensionConfiguration['BE.'];
218 }
219 $this->configurationManager->setLocalConfigurationValueByPath(
220 'EXT/extConf/saltedpasswords',
221 serialize($extensionConfiguration)
222 );
223 $this->throwRedirectException();
224 }
225 } else {
226 $this->configurationManager->setLocalConfigurationValueByPath(
227 'EXT/extConf/saltedpasswords',
228 serialize($defaultExtensionConfiguration)
229 );
230 $this->throwRedirectException();
231 }
232 }
233
234 /**
235 * The encryption key is crucial for securing form tokens
236 * and the whole TYPO3 link rendering later on. A random key is set here in
237 * LocalConfiguration if it does not exist yet. This might possible happen
238 * during upgrading and will happen during first install.
239 *
240 * @return void
241 */
242 protected function generateEncryptionKeyIfNeeded() {
243 try{
244 $currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
245 } catch (\RuntimeException $e) {
246 // If an exception is thrown, the value is not set in LocalConfiguration
247 $currentValue = '';
248 }
249
250 if (empty($currentValue)) {
251 $randomKey = GeneralUtility::getRandomHexString(96);
252 $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
253 $this->throwRedirectException();
254 }
255 }
256
257 /**
258 * $GLOBALS['TYPO3_CONF_VARS']['HTTP']['proxy_auth_scheme'] must be either
259 * 'digest' or 'basic'. 'basic' is default in DefaultConfiguration, so the
260 * setting can be removed from LocalConfiguration if it is not set to 'digest'.
261 *
262 * @return void
263 */
264 protected function setProxyAuthScheme() {
265 // Get current value from LocalConfiguration
266 try {
267 $currentValueInLocalConfiguration = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
268 } catch (\RuntimeException $e) {
269 // If an exception is thrown, the value is not set in LocalConfiguration, so we don't need to do anything
270 return;
271 }
272 if ($currentValueInLocalConfiguration !== 'digest') {
273 $this->configurationManager->removeLocalConfigurationKeysByPath(array('HTTP/proxy_auth_scheme'));
274 $this->throwRedirectException();
275 }
276 }
277
278 /**
279 * GFX/im and GFX/gdlib must be set to 0 if image_processing is disabled.
280 *
281 * "Configuration presets" in install tool is not type safe, so value
282 * comparisons here are not type safe too, to not trigger changes to
283 * LocalConfiguration again.
284 *
285 * @return void
286 */
287 protected function disableImageMagickAndGdlibIfImageProcessingIsDisabled() {
288 $changedValues = array();
289 try {
290 $currentImageProcessingValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/image_processing');
291 } catch (\RuntimeException $e) {
292 $currentImageProcessingValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/image_processing');
293 }
294 try {
295 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
296 } catch (\RuntimeException $e) {
297 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
298 }
299 try {
300 $currentGdlibValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/gdlib');
301 } catch (\RuntimeException $e) {
302 $currentGdlibValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/gdlib');
303 }
304 // If image processing is fully disabled, im and gdlib sub settings must be 0
305 if (!$currentImageProcessingValue) {
306 if ($currentImValue != 0) {
307 $changedValues['GFX/im'] = 0;
308 }
309 if ($currentGdlibValue != 0) {
310 $changedValues['GFX/gdlib'] = 0;
311 }
312 }
313 if (count($changedValues) > 0) {
314 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
315 $this->throwRedirectException();
316 }
317 }
318
319 /**
320 * Detail configuration of Image Magick settings must be cleared
321 * if Image Magick handling is disabled.
322 *
323 * "Configuration presets" in install tool is not type safe, so value
324 * comparisons here are not type safe too, to not trigger changes to
325 * LocalConfiguration again.
326 *
327 * @return void
328 */
329 protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled() {
330 $changedValues = array();
331 try {
332 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
333 }
334 catch (\RuntimeException $e) {
335 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
336 }
337 try {
338 $currentImPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path');
339 }
340 catch (\RuntimeException $e) {
341 $currentImPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path');
342 }
343 try {
344 $currentImPathLzwValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path_lzw');
345 }
346 catch (\RuntimeException $e) {
347 $currentImPathLzwValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path_lzw');
348 }
349 try {
350 $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
351 }
352 catch (\RuntimeException $e) {
353 $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
354 }
355 try {
356 $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
357 }
358 catch (\RuntimeException $e) {
359 $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
360 }
361 if (!$currentImValue) {
362 if ($currentImPathValue != '') {
363 $changedValues['GFX/im_path'] = '';
364 }
365 if ($currentImPathLzwValue != '') {
366 $changedValues['GFX/im_path_lzw'] = '';
367 }
368 if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
369 $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
370 }
371 if ($currentThumbnailsValue != 0) {
372 $changedValues['GFX/thumbnails'] = 0;
373 }
374 }
375 if (count($changedValues) > 0) {
376 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
377 $this->throwRedirectException();
378 }
379 }
380
381 /**
382 * Detail configuration of Image Magick and Graphics Magick settings
383 * depending on main values.
384 *
385 * "Configuration presets" in install tool is not type safe, so value
386 * comparisons here are not type safe too, to not trigger changes to
387 * LocalConfiguration again.
388 *
389 * @return void
390 */
391 protected function setImageMagickDetailSettings() {
392 $changedValues = array();
393 try {
394 $currentIm5Value = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
395 }
396 catch (\RuntimeException $e) {
397 $currentIm5Value = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_version_5');
398 }
399 try {
400 $currentImMaskValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
401 }
402 catch (\RuntimeException $e) {
403 $currentImMaskValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
404 }
405 try {
406 $currentIm5EffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_v5effects');
407 }
408 catch (\RuntimeException $e) {
409 $currentIm5EffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_v5effects');
410 }
411 if (strlen($currentIm5Value) > 0) {
412 if ($currentImMaskValue != 1) {
413 $changedValues['GFX/im_mask_temp_ext_gif'] = 1;
414 }
415 if ($currentIm5Value === 'gm') {
416 if ($currentIm5EffectsValue != -1) {
417 $changedValues['GFX/im_v5effects'] = -1;
418 }
419 }
420 }
421 if (count($changedValues) > 0) {
422 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
423 $this->throwRedirectException();
424 }
425 }
426
427 /**
428 * Make sure file table is categorized as of TYPO3 6.2. To enable DAM Migration
429 * sys_file_metadata table is included in DefaultConfiguration.
430 * If the setting already has been modified but does not contain sys_file_metadata: add it
431 *
432 * @return void
433 */
434 protected function addFileTableToDefaultCategorizedTablesIfAlreadyCustomized() {
435 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
436 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
437
438 $default = $configurationManager->getDefaultConfigurationValueByPath('SYS/defaultCategorizedTables');
439 try {
440 $actual = $configurationManager->getLocalConfigurationValueByPath('SYS/defaultCategorizedTables');
441 } catch(\RuntimeException $e) {
442 $actual = '';
443 }
444
445 $tables = GeneralUtility::trimExplode(',', $actual);
446 if ($actual !== '' && $actual !== $default && !in_array('sys_file_metadata', $tables)) {
447 $tables[] = 'sys_file_metadata';
448 $configurationManager->setLocalConfigurationValueByPath('SYS/defaultCategorizedTables', implode(',', $tables));
449 $this->throwRedirectException();
450 }
451 }
452
453 /**
454 * Migrate old Install Tool Wizard "done"-settings to new class names
455 * this happens usually when an existing 6.0/6.1 has called the TceformsUpdateWizard wizard
456 * and has written Tx_Install_Updates_File_TceformsUpdateWizard in TYPO3's LocalConfiguration.php
457 *
458 * @return void
459 */
460 protected function migrateOldInstallWizardDoneSettingsToNewClassNames() {
461 $classNamesToConvert = array();
462 $localConfiguration = $this->configurationManager->getLocalConfiguration();
463 // check for wizards that have been run already and don't start with TYPO3...
464 if (isset($localConfiguration['INSTALL']['wizardDone']) && is_array($localConfiguration['INSTALL']['wizardDone'])) {
465 $classNames = array_keys($localConfiguration['INSTALL']['wizardDone']);
466 foreach ($classNames as $className) {
467 if (!GeneralUtility::isFirstPartOfStr($className, 'TYPO3')) {
468 $classNamesToConvert[] = $className;
469 }
470 }
471 }
472 if (!count($classNamesToConvert)) {
473 return;
474 }
475
476 $migratedClassesMapping = array(
477 'Tx_Install_Updates_File_TceformsUpdateWizard' => 'TYPO3\\CMS\\Install\\Updates\\TceformsUpdateWizard'
478 );
479
480 $migratedSettings = array();
481 $settingsToRemove = array();
482 foreach ($classNamesToConvert as $oldClassName) {
483 if (isset($migratedClassesMapping[$oldClassName])) {
484 $newClassName = $migratedClassesMapping[$oldClassName];
485 } else {
486 continue;
487 }
488 $oldValue = NULL;
489 $newValue = NULL;
490 try {
491 $oldValue = $this->configurationManager->getLocalConfigurationValueByPath('INSTALL/wizardDone/' . $oldClassName);
492 } catch (\RuntimeException $e) {
493 // The old configuration does not exist
494 continue;
495 }
496 try {
497 $newValue = $this->configurationManager->getLocalConfigurationValueByPath('INSTALL/wizardDone/' . $newClassName);
498 } catch (\RuntimeException $e) {
499 // The new configuration does not exist yet
500 }
501 if ($newValue === NULL) {
502 // Migrate the old configuration to the new one
503 $migratedSettings['INSTALL/wizardDone/' . $newClassName] = $oldValue;
504 }
505 $settingsToRemove[] = 'INSTALL/wizardDone/' . $oldClassName;
506
507 }
508
509 if (count($migratedSettings)) {
510 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($migratedSettings);
511 }
512 $this->configurationManager->removeLocalConfigurationKeysByPath($settingsToRemove);
513 if (count($migratedSettings) || count($settingsToRemove)) {
514 $this->throwRedirectException();
515 }
516 }
517
518 /**
519 * Throw exception after configuration change to trigger a redirect.
520 *
521 * @throws \TYPO3\CMS\Install\Controller\Exception\RedirectException
522 */
523 protected function throwRedirectException() {
524 throw new \TYPO3\CMS\Install\Controller\Exception\RedirectException(
525 'Configuration updated, reload needed',
526 1379024938
527 );
528 }
529 }