[TASK] Drop XCLASS registration from DefaultConfiguration
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Service / SilentConfigurationUpgradeService.php
1 <?php
2 namespace TYPO3\CMS\Install\Service;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Install\Controller\Exception\RedirectException;
20
21 /**
22 * Execute "silent" LocalConfiguration upgrades if needed.
23 *
24 * Some LocalConfiguration settings are obsolete or changed over time.
25 * This class handles upgrades of these settings. It is called by
26 * the step controller at an early point.
27 *
28 * Every change is encapsulated in one method an must throw a RedirectException
29 * if new data is written to LocalConfiguration. This is caught by above
30 * step controller to initiate a redirect and start again with adapted configuration.
31 */
32 class SilentConfigurationUpgradeService
33 {
34 /**
35 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
36 */
37 protected $objectManager = null;
38
39 /**
40 * @var \TYPO3\CMS\Core\Configuration\ConfigurationManager
41 */
42 protected $configurationManager = null;
43
44 /**
45 * List of obsolete configuration options in LocalConfiguration to be removed
46 * Example:
47 * // #forge-ticket
48 * 'BE/somesetting',
49 *
50 * @var array
51 */
52 protected $obsoleteLocalConfigurationSettings = array(
53 // #72367
54 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\AccessRightParametersUpdate',
55 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\BackendUserStartModuleUpdate',
56 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\Compatibility6ExtractionUpdate',
57 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\ContentTypesToTextMediaUpdate',
58 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FileListIsStartModuleUpdate',
59 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FilesReplacePermissionUpdate',
60 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\LanguageIsoCodeUpdate',
61 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\MediaceExtractionUpdate',
62 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\MigrateMediaToAssetsForTextMediaCe',
63 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\MigrateShortcutUrlsAgainUpdate',
64 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\OpenidExtractionUpdate',
65 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\PageShortcutParentUpdate',
66 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\ProcessedFileChecksumUpdate',
67 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\TableFlexFormToTtContentFieldsUpdate',
68 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\WorkspacesNotificationSettingsUpdate',
69 'INSTALL/wizardDone/TYPO3\\CMS\\Rtehtmlarea\\Hook\\Install\\DeprecatedRteProperties',
70 'INSTALL/wizardDone/TYPO3\\CMS\\Rtehtmlarea\\Hook\\Install\\RteAcronymButtonRenamedToAbbreviation',
71 // #72400
72 'BE/spriteIconGenerator_handler',
73 // #72417
74 'SYS/lockingMode',
75 // #72473
76 'FE/secureFormmail',
77 'FE/strictFormmail',
78 'FE/formmailMaxAttachmentSize',
79 // #72337
80 'SYS/t3lib_cs_utils',
81 'SYS/t3lib_cs_convMethod',
82 // #72604
83 'SYS/maxFileNameLength',
84 // #72602
85 'BE/unzip_path',
86 // #72615
87 'BE/notificationPrefix',
88 // #72616
89 'BE/XCLASS',
90 'FE/XCLASS',
91 );
92
93 /**
94 * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
95 */
96 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager)
97 {
98 $this->objectManager = $objectManager;
99 }
100
101 /**
102 * @param \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager
103 */
104 public function injectConfigurationManager(\TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager)
105 {
106 $this->configurationManager = $configurationManager;
107 }
108
109 /**
110 * Executed configuration upgrades. Single upgrade methods must throw a
111 * RedirectException if something was written to LocalConfiguration.
112 *
113 * @return void
114 */
115 public function execute()
116 {
117 $this->generateEncryptionKeyIfNeeded();
118 $this->configureBackendLoginSecurity();
119 $this->configureSaltedPasswords();
120 $this->setProxyAuthScheme();
121 $this->transferDeprecatedCurlSettings();
122 $this->disableImageMagickAndGdlibIfImageProcessingIsDisabled();
123 $this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
124 $this->setImageMagickDetailSettings();
125 $this->removeObsoleteLocalConfigurationSettings();
126 }
127
128 /**
129 * Some settings in LocalConfiguration vanished in DefaultConfiguration
130 * and have no impact on the core anymore.
131 * To keep the configuration clean, those old settings are just silently
132 * removed from LocalConfiguration if set.
133 *
134 * @return void
135 */
136 protected function removeObsoleteLocalConfigurationSettings()
137 {
138 $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
139
140 // If something was changed: Trigger a reload to have new values in next request
141 if ($removed) {
142 $this->throwRedirectException();
143 }
144 }
145
146 /**
147 * Backend login security is set to rsa if rsaauth
148 * is installed (but not used) otherwise the default value "normal" has to be used.
149 * This forces either 'normal' or 'rsa' to be set in LocalConfiguration.
150 *
151 * @return void
152 */
153 protected function configureBackendLoginSecurity()
154 {
155 $rsaauthLoaded = ExtensionManagementUtility::isLoaded('rsaauth');
156 try {
157 $currentLoginSecurityLevelValue = $this->configurationManager->getLocalConfigurationValueByPath('BE/loginSecurityLevel');
158 if ($rsaauthLoaded && $currentLoginSecurityLevelValue !== 'rsa') {
159 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
160 $this->throwRedirectException();
161 } elseif (!$rsaauthLoaded && $currentLoginSecurityLevelValue !== 'normal') {
162 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
163 $this->throwRedirectException();
164 }
165 } catch (\RuntimeException $e) {
166 // If an exception is thrown, the value is not set in LocalConfiguration
167 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', $rsaauthLoaded ? 'rsa' : 'normal');
168 $this->throwRedirectException();
169 }
170 }
171
172 /**
173 * Check the settings for salted passwords extension to load it as a required extension.
174 * Unset obsolete configuration options if given.
175 *
176 * @return void
177 */
178 protected function configureSaltedPasswords()
179 {
180 $defaultConfiguration = $this->configurationManager->getDefaultConfiguration();
181 $defaultExtensionConfiguration = unserialize($defaultConfiguration['EXT']['extConf']['saltedpasswords']);
182 try {
183 $extensionConfiguration = @unserialize($this->configurationManager->getLocalConfigurationValueByPath('EXT/extConf/saltedpasswords'));
184 } catch (\RuntimeException $e) {
185 $extensionConfiguration = array();
186 }
187 if (is_array($extensionConfiguration) && !empty($extensionConfiguration)) {
188 if (isset($extensionConfiguration['BE.']['enabled'])) {
189 if ($extensionConfiguration['BE.']['enabled']) {
190 unset($extensionConfiguration['BE.']['enabled']);
191 } else {
192 $extensionConfiguration['BE.'] = $defaultExtensionConfiguration['BE.'];
193 }
194 $this->configurationManager->setLocalConfigurationValueByPath(
195 'EXT/extConf/saltedpasswords',
196 serialize($extensionConfiguration)
197 );
198 $this->throwRedirectException();
199 }
200 } else {
201 $this->configurationManager->setLocalConfigurationValueByPath(
202 'EXT/extConf/saltedpasswords',
203 serialize($defaultExtensionConfiguration)
204 );
205 $this->throwRedirectException();
206 }
207 }
208
209 /**
210 * The encryption key is crucial for securing form tokens
211 * and the whole TYPO3 link rendering later on. A random key is set here in
212 * LocalConfiguration if it does not exist yet. This might possible happen
213 * during upgrading and will happen during first install.
214 *
215 * @return void
216 */
217 protected function generateEncryptionKeyIfNeeded()
218 {
219 try {
220 $currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
221 } catch (\RuntimeException $e) {
222 // If an exception is thrown, the value is not set in LocalConfiguration
223 $currentValue = '';
224 }
225
226 if (empty($currentValue)) {
227 $randomKey = GeneralUtility::getRandomHexString(96);
228 $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
229 $this->throwRedirectException();
230 }
231 }
232
233 /**
234 * $GLOBALS['TYPO3_CONF_VARS']['HTTP']['proxy_auth_scheme'] must be either
235 * 'digest' or 'basic'. 'basic' is default in DefaultConfiguration, so the
236 * setting can be removed from LocalConfiguration if it is not set to 'digest'.
237 *
238 * @return void
239 */
240 protected function setProxyAuthScheme()
241 {
242 // Get current value from LocalConfiguration
243 try {
244 $currentValueInLocalConfiguration = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
245 } catch (\RuntimeException $e) {
246 // If an exception is thrown, the value is not set in LocalConfiguration, so we don't need to do anything
247 return;
248 }
249 if ($currentValueInLocalConfiguration !== 'digest') {
250 $this->configurationManager->removeLocalConfigurationKeysByPath(array('HTTP/proxy_auth_scheme'));
251 $this->throwRedirectException();
252 }
253 }
254
255 /**
256 * Parse old curl options and set new http ones instead
257 *
258 * @return void
259 */
260 protected function transferDeprecatedCurlSettings()
261 {
262 $changed = false;
263 try {
264 $curlProxyServer = $this->configurationManager->getLocalConfigurationValueByPath('SYS/curlProxyServer');
265 } catch (\RuntimeException $e) {
266 $curlProxyServer = '';
267 }
268 try {
269 $proxyHost = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_host');
270 } catch (\RuntimeException $e) {
271 $proxyHost = '';
272 }
273 if (!empty($curlProxyServer) && empty($proxyHost)) {
274 $curlProxy = rtrim(preg_replace('#^https?://#', '', $curlProxyServer), '/');
275 $proxyParts = GeneralUtility::revExplode(':', $curlProxy, 2);
276 $this->configurationManager->setLocalConfigurationValueByPath('HTTP/proxy_host', $proxyParts[0]);
277 $this->configurationManager->setLocalConfigurationValueByPath('HTTP/proxy_port', $proxyParts[1]);
278 $changed = true;
279 }
280
281 try {
282 $curlProxyUserPass = $this->configurationManager->getLocalConfigurationValueByPath('SYS/curlProxyUserPass');
283 } catch (\RuntimeException $e) {
284 $curlProxyUserPass = '';
285 }
286 try {
287 $proxyUser = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_user');
288 } catch (\RuntimeException $e) {
289 $proxyUser = '';
290 }
291 if (!empty($curlProxyUserPass) && empty($proxyUser)) {
292 $userPassParts = explode(':', $curlProxyUserPass, 2);
293 $this->configurationManager->setLocalConfigurationValueByPath('HTTP/proxy_user', $userPassParts[0]);
294 $this->configurationManager->setLocalConfigurationValueByPath('HTTP/proxy_password', $userPassParts[1]);
295 $changed = true;
296 }
297
298 try {
299 $curlUse = $this->configurationManager->getLocalConfigurationValueByPath('SYS/curlUse');
300 } catch (\RuntimeException $e) {
301 $curlUse = '';
302 }
303 try {
304 $adapter = $this->configurationManager->getConfigurationValueByPath('HTTP/adapter');
305 } catch (\RuntimeException $e) {
306 $adapter = '';
307 }
308 if (!empty($curlUse) && $adapter !== 'curl') {
309 $GLOBALS['TYPO3_CONF_VARS']['HTTP']['adapter'] = 'curl';
310 $this->configurationManager->setLocalConfigurationValueByPath('HTTP/adapter', 'curl');
311 $changed = true;
312 }
313 if ($changed) {
314 $this->throwRedirectException();
315 }
316 }
317
318 /**
319 * GFX/im and GFX/gdlib must be set to 0 if image_processing is disabled.
320 *
321 * "Configuration presets" in install tool is not type safe, so value
322 * comparisons here are not type safe too, to not trigger changes to
323 * LocalConfiguration again.
324 *
325 * @return void
326 */
327 protected function disableImageMagickAndGdlibIfImageProcessingIsDisabled()
328 {
329 $changedValues = array();
330 try {
331 $currentImageProcessingValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/image_processing');
332 } catch (\RuntimeException $e) {
333 $currentImageProcessingValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/image_processing');
334 }
335 try {
336 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
337 } catch (\RuntimeException $e) {
338 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
339 }
340 try {
341 $currentGdlibValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/gdlib');
342 } catch (\RuntimeException $e) {
343 $currentGdlibValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/gdlib');
344 }
345 // If image processing is fully disabled, im and gdlib sub settings must be 0
346 if (!$currentImageProcessingValue) {
347 if ($currentImValue != 0) {
348 $changedValues['GFX/im'] = 0;
349 }
350 if ($currentGdlibValue != 0) {
351 $changedValues['GFX/gdlib'] = 0;
352 }
353 }
354 if (!empty($changedValues)) {
355 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
356 $this->throwRedirectException();
357 }
358 }
359
360 /**
361 * Detail configuration of Image Magick settings must be cleared
362 * if Image Magick handling is disabled.
363 *
364 * "Configuration presets" in install tool is not type safe, so value
365 * comparisons here are not type safe too, to not trigger changes to
366 * LocalConfiguration again.
367 *
368 * @return void
369 */
370 protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled()
371 {
372 $changedValues = array();
373 try {
374 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
375 } catch (\RuntimeException $e) {
376 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
377 }
378 try {
379 $currentImPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path');
380 } catch (\RuntimeException $e) {
381 $currentImPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path');
382 }
383 try {
384 $currentImPathLzwValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path_lzw');
385 } catch (\RuntimeException $e) {
386 $currentImPathLzwValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path_lzw');
387 }
388 try {
389 $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
390 } catch (\RuntimeException $e) {
391 $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
392 }
393 try {
394 $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
395 } catch (\RuntimeException $e) {
396 $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
397 }
398 if (!$currentImValue) {
399 if ($currentImPathValue != '') {
400 $changedValues['GFX/im_path'] = '';
401 }
402 if ($currentImPathLzwValue != '') {
403 $changedValues['GFX/im_path_lzw'] = '';
404 }
405 if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
406 $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
407 }
408 if ($currentThumbnailsValue != 0) {
409 $changedValues['GFX/thumbnails'] = 0;
410 }
411 }
412 if (!empty($changedValues)) {
413 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
414 $this->throwRedirectException();
415 }
416 }
417
418 /**
419 * Detail configuration of Image Magick and Graphics Magick settings
420 * depending on main values.
421 *
422 * "Configuration presets" in install tool is not type safe, so value
423 * comparisons here are not type safe too, to not trigger changes to
424 * LocalConfiguration again.
425 *
426 * @return void
427 */
428 protected function setImageMagickDetailSettings()
429 {
430 $changedValues = array();
431 try {
432 $currentIm5Value = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
433 } catch (\RuntimeException $e) {
434 $currentIm5Value = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_version_5');
435 }
436 try {
437 $currentImMaskValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
438 } catch (\RuntimeException $e) {
439 $currentImMaskValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
440 }
441 try {
442 $currentIm5EffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_v5effects');
443 } catch (\RuntimeException $e) {
444 $currentIm5EffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_v5effects');
445 }
446 if ((string)$currentIm5Value !== '') {
447 if ($currentImMaskValue != 1) {
448 $changedValues['GFX/im_mask_temp_ext_gif'] = 1;
449 }
450 if ($currentIm5Value === 'gm') {
451 if ($currentIm5EffectsValue != -1) {
452 $changedValues['GFX/im_v5effects'] = -1;
453 }
454 }
455 }
456 if (!empty($changedValues)) {
457 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
458 $this->throwRedirectException();
459 }
460 }
461
462 /**
463 * Throw exception after configuration change to trigger a redirect.
464 *
465 * @throws RedirectException
466 */
467 protected function throwRedirectException()
468 {
469 throw new RedirectException(
470 'Configuration updated, reload needed',
471 1379024938
472 );
473 }
474 }