9d9e4ca406023da72c7b51ca904f087701d0926d
[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\Configuration\ConfigurationManager;
18 use TYPO3\CMS\Core\Crypto\Random;
19 use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
20 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException;
23
24 /**
25 * Execute "silent" LocalConfiguration upgrades if needed.
26 *
27 * Some LocalConfiguration settings are obsolete or changed over time.
28 * This class handles upgrades of these settings. It is called by
29 * the step controller at an early point.
30 *
31 * Every change is encapsulated in one method an must throw a ConfigurationChangedException
32 * if new data is written to LocalConfiguration. This is caught by above
33 * step controller to initiate a redirect and start again with adapted configuration.
34 */
35 class SilentConfigurationUpgradeService
36 {
37 /**
38 * @var \TYPO3\CMS\Core\Configuration\ConfigurationManager
39 */
40 protected $configurationManager;
41
42 /**
43 * List of obsolete configuration options in LocalConfiguration to be removed
44 * Example:
45 * // #forge-ticket
46 * 'BE/somesetting',
47 *
48 * @var array
49 */
50 protected $obsoleteLocalConfigurationSettings = [
51 // #72400
52 'BE/spriteIconGenerator_handler',
53 // #72417
54 'SYS/lockingMode',
55 // #72473
56 'FE/secureFormmail',
57 'FE/strictFormmail',
58 'FE/formmailMaxAttachmentSize',
59 // #72337
60 'SYS/t3lib_cs_utils',
61 'SYS/t3lib_cs_convMethod',
62 // #72604
63 'SYS/maxFileNameLength',
64 // #72602
65 'BE/unzip_path',
66 // #72615
67 'BE/notificationPrefix',
68 // #72616
69 'BE/XCLASS',
70 'FE/XCLASS',
71 // #43085
72 'GFX/image_processing',
73 // #70056
74 'SYS/curlUse',
75 'SYS/curlProxyNTLM',
76 'SYS/curlProxyServer',
77 'SYS/curlProxyTunnel',
78 'SYS/curlProxyUserPass',
79 'SYS/curlTimeout',
80 // #75355
81 'BE/niceFlexFormXMLtags',
82 'BE/compactFlexFormXML',
83 // #75625
84 'SYS/clearCacheSystem',
85 // #77411
86 'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_tablecolumns',
87 // #77460
88 'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_queries',
89 // #79513
90 'FE/lockHashKeyWords',
91 'BE/lockHashKeyWords',
92 // #78835
93 'SYS/cookieHttpOnly',
94 // #71095
95 'BE/lang',
96 // #80050
97 'FE/cHashIncludePageId',
98 // #80711
99 'FE/noPHPscriptInclude',
100 'FE/maxSessionDataSize',
101 // #82162
102 'SYS/enable_errorDLOG',
103 'SYS/enable_exceptionDLOG',
104 // #82377
105 'EXT/allowSystemInstall',
106 // #82421
107 'SYS/sqlDebug',
108 'SYS/no_pconnect',
109 'SYS/setDBinit',
110 'SYS/dbClientCompress',
111 // #82430
112 'SYS/syslogErrorReporting',
113 // #82639
114 'SYS/enable_DLOG',
115 'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLog',
116 'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogBE',
117 'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogFE',
118 // #82438
119 'SYS/enableDeprecationLog',
120 // #82680
121 'GFX/png_truecolor',
122 // #82803
123 'FE/content_doktypes',
124 // #83081
125 'BE/fileExtensions',
126 // #83768
127 'SYS/doNotCheckReferer',
128 ];
129
130 public function __construct(ConfigurationManager $configurationManager = null)
131 {
132 $this->configurationManager = $configurationManager ?: GeneralUtility::makeInstance(ConfigurationManager::class);
133 }
134
135 /**
136 * Executed configuration upgrades. Single upgrade methods must throw a
137 * ConfigurationChangedException if something was written to LocalConfiguration.
138 */
139 public function execute()
140 {
141 $this->generateEncryptionKeyIfNeeded();
142 $this->configureBackendLoginSecurity();
143 $this->migrateImageProcessorSetting();
144 $this->transferHttpSettings();
145 $this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
146 $this->setImageMagickDetailSettings();
147 $this->migrateThumbnailsPngSetting();
148 $this->migrateLockSslSetting();
149 $this->migrateDatabaseConnectionSettings();
150 $this->migrateDatabaseConnectionCharset();
151 $this->migrateDatabaseDriverOptions();
152 $this->migrateLangDebug();
153 $this->migrateCacheHashOptions();
154 $this->migrateExceptionErrors();
155 $this->migrateDisplayErrorsSetting();
156
157 // Should run at the end to prevent that obsolete settings are removed before migration
158 $this->removeObsoleteLocalConfigurationSettings();
159 }
160
161 /**
162 * Some settings in LocalConfiguration vanished in DefaultConfiguration
163 * and have no impact on the core anymore.
164 * To keep the configuration clean, those old settings are just silently
165 * removed from LocalConfiguration if set.
166 */
167 protected function removeObsoleteLocalConfigurationSettings()
168 {
169 $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
170
171 // If something was changed: Trigger a reload to have new values in next request
172 if ($removed) {
173 $this->throwConfigurationChangedException();
174 }
175 }
176
177 /**
178 * Backend login security is set to rsa if rsaauth
179 * is installed (but not used) otherwise the default value "normal" has to be used.
180 * This forces either 'normal' or 'rsa' to be set in LocalConfiguration.
181 */
182 protected function configureBackendLoginSecurity()
183 {
184 $rsaauthLoaded = ExtensionManagementUtility::isLoaded('rsaauth');
185 try {
186 $currentLoginSecurityLevelValue = $this->configurationManager->getLocalConfigurationValueByPath('BE/loginSecurityLevel');
187 if ($rsaauthLoaded && $currentLoginSecurityLevelValue !== 'rsa') {
188 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
189 $this->throwConfigurationChangedException();
190 } elseif (!$rsaauthLoaded && $currentLoginSecurityLevelValue !== 'normal') {
191 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
192 $this->throwConfigurationChangedException();
193 }
194 } catch (MissingArrayPathException $e) {
195 // If an exception is thrown, the value is not set in LocalConfiguration
196 $this->configurationManager->setLocalConfigurationValueByPath(
197 'BE/loginSecurityLevel',
198 $rsaauthLoaded ? 'rsa' : 'normal'
199 );
200 $this->throwConfigurationChangedException();
201 }
202 }
203
204 /**
205 * The encryption key is crucial for securing form tokens
206 * and the whole TYPO3 link rendering later on. A random key is set here in
207 * LocalConfiguration if it does not exist yet. This might possible happen
208 * during upgrading and will happen during first install.
209 */
210 protected function generateEncryptionKeyIfNeeded()
211 {
212 try {
213 $currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
214 } catch (MissingArrayPathException $e) {
215 // If an exception is thrown, the value is not set in LocalConfiguration
216 $currentValue = '';
217 }
218
219 if (empty($currentValue)) {
220 $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96);
221 $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
222 $this->throwConfigurationChangedException();
223 }
224 }
225
226 /**
227 * Parse old curl and HTTP options and set new HTTP options, related to Guzzle
228 */
229 protected function transferHttpSettings()
230 {
231 $changed = false;
232 $newParameters = [];
233 $obsoleteParameters = [];
234
235 // Remove / migrate options to new options
236 try {
237 // Check if the adapter option is set, if so, set it to the parameters that are obsolete
238 $this->configurationManager->getLocalConfigurationValueByPath('HTTP/adapter');
239 $obsoleteParameters[] = 'HTTP/adapter';
240 } catch (MissingArrayPathException $e) {
241 // Migration done already
242 }
243 try {
244 $newParameters['HTTP/version'] = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/protocol_version');
245 $obsoleteParameters[] = 'HTTP/protocol_version';
246 } catch (MissingArrayPathException $e) {
247 // Migration done already
248 }
249 try {
250 $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_host');
251 $obsoleteParameters[] = 'HTTP/ssl_verify_host';
252 } catch (MissingArrayPathException $e) {
253 // Migration done already
254 }
255 try {
256 $legacyUserAgent = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/userAgent');
257 $newParameters['HTTP/headers/User-Agent'] = $legacyUserAgent;
258 $obsoleteParameters[] = 'HTTP/userAgent';
259 } catch (MissingArrayPathException $e) {
260 // Migration done already
261 }
262
263 // Redirects
264 try {
265 $legacyFollowRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/follow_redirects');
266 $obsoleteParameters[] = 'HTTP/follow_redirects';
267 } catch (MissingArrayPathException $e) {
268 $legacyFollowRedirects = '';
269 }
270 try {
271 $legacyMaximumRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/max_redirects');
272 $obsoleteParameters[] = 'HTTP/max_redirects';
273 } catch (MissingArrayPathException $e) {
274 $legacyMaximumRedirects = '';
275 }
276 try {
277 $legacyStrictRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/strict_redirects');
278 $obsoleteParameters[] = 'HTTP/strict_redirects';
279 } catch (MissingArrayPathException $e) {
280 $legacyStrictRedirects = '';
281 }
282
283 // Check if redirects have been disabled
284 if ($legacyFollowRedirects !== '' && (bool)$legacyFollowRedirects === false) {
285 $newParameters['HTTP/allow_redirects'] = false;
286 } elseif ($legacyMaximumRedirects !== '' || $legacyStrictRedirects !== '') {
287 $newParameters['HTTP/allow_redirects'] = [];
288 if ($legacyMaximumRedirects !== '' && (int)$legacyMaximumRedirects !== 5) {
289 $newParameters['HTTP/allow_redirects']['max'] = (int)$legacyMaximumRedirects;
290 }
291 if ($legacyStrictRedirects !== '' && (bool)$legacyStrictRedirects === true) {
292 $newParameters['HTTP/allow_redirects']['strict'] = true;
293 }
294 // defaults are used, no need to set the option in LocalConfiguration.php
295 if (empty($newParameters['HTTP/allow_redirects'])) {
296 unset($newParameters['HTTP/allow_redirects']);
297 }
298 }
299
300 // Migrate Proxy settings
301 try {
302 // Currently without protocol or port
303 $legacyProxyHost = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_host');
304 $obsoleteParameters[] = 'HTTP/proxy_host';
305 } catch (MissingArrayPathException $e) {
306 $legacyProxyHost = '';
307 }
308 try {
309 $legacyProxyPort = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_port');
310 $obsoleteParameters[] = 'HTTP/proxy_port';
311 } catch (MissingArrayPathException $e) {
312 $legacyProxyPort = '';
313 }
314 try {
315 $legacyProxyUser = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_user');
316 $obsoleteParameters[] = 'HTTP/proxy_user';
317 } catch (MissingArrayPathException $e) {
318 $legacyProxyUser = '';
319 }
320 try {
321 $legacyProxyPassword = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_password');
322 $obsoleteParameters[] = 'HTTP/proxy_password';
323 } catch (MissingArrayPathException $e) {
324 $legacyProxyPassword = '';
325 }
326 // Auth Scheme: Basic, digest etc.
327 try {
328 $legacyProxyAuthScheme = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
329 $obsoleteParameters[] = 'HTTP/proxy_auth_scheme';
330 } catch (MissingArrayPathException $e) {
331 $legacyProxyAuthScheme = '';
332 }
333
334 if ($legacyProxyHost !== '') {
335 $proxy = 'http://';
336 if ($legacyProxyAuthScheme !== '' && $legacyProxyUser !== '' && $legacyProxyPassword !== '') {
337 $proxy .= $legacyProxyUser . ':' . $legacyProxyPassword . '@';
338 }
339 $proxy .= $legacyProxyHost;
340 if ($legacyProxyPort !== '') {
341 $proxy .= ':' . $legacyProxyPort;
342 }
343 $newParameters['HTTP/proxy'] = $proxy;
344 }
345
346 // Verify peers
347 // see http://docs.guzzlephp.org/en/latest/request-options.html#verify
348 try {
349 $legacySslVerifyPeer = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_peer');
350 $obsoleteParameters[] = 'HTTP/ssl_verify_peer';
351 } catch (MissingArrayPathException $e) {
352 $legacySslVerifyPeer = '';
353 }
354
355 // Directory holding multiple Certificate Authority files
356 try {
357 $legacySslCaPath = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_capath');
358 $obsoleteParameters[] = 'HTTP/ssl_capath';
359 } catch (MissingArrayPathException $e) {
360 $legacySslCaPath = '';
361 }
362 // Certificate Authority file to verify the peer with (use when ssl_verify_peer is TRUE)
363 try {
364 $legacySslCaFile = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_cafile');
365 $obsoleteParameters[] = 'HTTP/ssl_cafile';
366 } catch (MissingArrayPathException $e) {
367 $legacySslCaFile = '';
368 }
369 if ($legacySslVerifyPeer !== '') {
370 if ($legacySslCaFile !== '' && $legacySslCaPath !== '') {
371 $newParameters['HTTP/verify'] = $legacySslCaPath . $legacySslCaFile;
372 } elseif ((bool)$legacySslVerifyPeer === false) {
373 $newParameters['HTTP/verify'] = false;
374 }
375 }
376
377 // SSL Key + Passphrase
378 // Name of a file containing local certificate
379 try {
380 $legacySslLocalCert = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_local_cert');
381 $obsoleteParameters[] = 'HTTP/ssl_local_cert';
382 } catch (MissingArrayPathException $e) {
383 $legacySslLocalCert = '';
384 }
385
386 // Passphrase with which local certificate was encoded
387 try {
388 $legacySslPassphrase = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_passphrase');
389 $obsoleteParameters[] = 'HTTP/ssl_passphrase';
390 } catch (MissingArrayPathException $e) {
391 $legacySslPassphrase = '';
392 }
393
394 if ($legacySslLocalCert !== '') {
395 if ($legacySslPassphrase !== '') {
396 $newParameters['HTTP/ssl_key'] = [
397 $legacySslLocalCert,
398 $legacySslPassphrase
399 ];
400 } else {
401 $newParameters['HTTP/ssl_key'] = $legacySslLocalCert;
402 }
403 }
404
405 // Update the LocalConfiguration file if obsolete parameters or new parameters are set
406 if (!empty($obsoleteParameters)) {
407 $this->configurationManager->removeLocalConfigurationKeysByPath($obsoleteParameters);
408 $changed = true;
409 }
410 if (!empty($newParameters)) {
411 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($newParameters);
412 $changed = true;
413 }
414 if ($changed) {
415 $this->throwConfigurationChangedException();
416 }
417 }
418
419 /**
420 * Detail configuration of Image Magick settings must be cleared
421 * if Image Magick handling is disabled.
422 *
423 * "Configuration presets" in install tool is not type safe, so value
424 * comparisons here are not type safe too, to not trigger changes to
425 * LocalConfiguration again.
426 */
427 protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled()
428 {
429 $changedValues = [];
430 try {
431 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_enabled');
432 } catch (MissingArrayPathException $e) {
433 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_enabled');
434 }
435
436 try {
437 $currentImPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path');
438 } catch (MissingArrayPathException $e) {
439 $currentImPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path');
440 }
441
442 try {
443 $currentImPathLzwValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path_lzw');
444 } catch (MissingArrayPathException $e) {
445 $currentImPathLzwValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path_lzw');
446 }
447
448 try {
449 $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
450 } catch (MissingArrayPathException $e) {
451 $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
452 }
453
454 try {
455 $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
456 } catch (MissingArrayPathException $e) {
457 $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
458 }
459
460 if (!$currentImValue) {
461 if ($currentImPathValue != '') {
462 $changedValues['GFX/processor_path'] = '';
463 }
464 if ($currentImPathLzwValue != '') {
465 $changedValues['GFX/processor_path_lzw'] = '';
466 }
467 if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
468 $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
469 }
470 if ($currentThumbnailsValue != 0) {
471 $changedValues['GFX/thumbnails'] = 0;
472 }
473 }
474 if (!empty($changedValues)) {
475 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
476 $this->throwConfigurationChangedException();
477 }
478 }
479
480 /**
481 * Detail configuration of Image Magick and Graphics Magick settings
482 * depending on main values.
483 *
484 * "Configuration presets" in install tool is not type safe, so value
485 * comparisons here are not type safe too, to not trigger changes to
486 * LocalConfiguration again.
487 */
488 protected function setImageMagickDetailSettings()
489 {
490 $changedValues = [];
491 try {
492 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor');
493 } catch (MissingArrayPathException $e) {
494 $currentProcessorValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor');
495 }
496
497 try {
498 $currentProcessorMaskValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_allowTemporaryMasksAsPng');
499 } catch (MissingArrayPathException $e) {
500 $currentProcessorMaskValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_allowTemporaryMasksAsPng');
501 }
502
503 try {
504 $currentProcessorEffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_effects');
505 } catch (MissingArrayPathException $e) {
506 $currentProcessorEffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_effects');
507 }
508
509 if ((string)$currentProcessorValue !== '') {
510 if ($currentProcessorMaskValue != 0) {
511 $changedValues['GFX/processor_allowTemporaryMasksAsPng'] = 0;
512 }
513 if ($currentProcessorValue === 'GraphicsMagick') {
514 if ($currentProcessorEffectsValue != -1) {
515 $changedValues['GFX/processor_effects'] = -1;
516 }
517 }
518 }
519 if (!empty($changedValues)) {
520 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
521 $this->throwConfigurationChangedException();
522 }
523 }
524
525 /**
526 * Migrate the definition of the image processor from the configuration value
527 * im_version_5 to the setting processor.
528 */
529 protected function migrateImageProcessorSetting()
530 {
531 $changedSettings = [];
532 $settingsToRename = [
533 'GFX/im' => 'GFX/processor_enabled',
534 'GFX/im_version_5' => 'GFX/processor',
535 'GFX/im_v5effects' => 'GFX/processor_effects',
536 'GFX/im_path' => 'GFX/processor_path',
537 'GFX/im_path_lzw' => 'GFX/processor_path_lzw',
538 'GFX/im_mask_temp_ext_gif' => 'GFX/processor_allowTemporaryMasksAsPng',
539 'GFX/im_noScaleUp' => 'GFX/processor_allowUpscaling',
540 'GFX/im_noFramePrepended' => 'GFX/processor_allowFrameSelection',
541 'GFX/im_stripProfileCommand' => 'GFX/processor_stripColorProfileCommand',
542 'GFX/im_useStripProfileByDefault' => 'GFX/processor_stripColorProfileByDefault',
543 'GFX/colorspace' => 'GFX/processor_colorspace',
544 ];
545
546 foreach ($settingsToRename as $oldPath => $newPath) {
547 try {
548 $value = $this->configurationManager->getLocalConfigurationValueByPath($oldPath);
549 $this->configurationManager->setLocalConfigurationValueByPath($newPath, $value);
550 $changedSettings[$oldPath] = true;
551 } catch (MissingArrayPathException $e) {
552 // If an exception is thrown, the value is not set in LocalConfiguration
553 $changedSettings[$oldPath] = false;
554 }
555 }
556
557 if (!empty($changedSettings['GFX/im_version_5'])) {
558 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
559 $newProcessorValue = $currentProcessorValue === 'gm' ? 'GraphicsMagick' : 'ImageMagick';
560 $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor', $newProcessorValue);
561 }
562
563 if (!empty($changedSettings['GFX/im_noScaleUp'])) {
564 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noScaleUp');
565 $newProcessorValue = !$currentProcessorValue;
566 $this->configurationManager->setLocalConfigurationValueByPath(
567 'GFX/processor_allowUpscaling',
568 $newProcessorValue
569 );
570 }
571
572 if (!empty($changedSettings['GFX/im_noFramePrepended'])) {
573 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noFramePrepended');
574 $newProcessorValue = !$currentProcessorValue;
575 $this->configurationManager->setLocalConfigurationValueByPath(
576 'GFX/processor_allowFrameSelection',
577 $newProcessorValue
578 );
579 }
580
581 if (!empty($changedSettings['GFX/im_mask_temp_ext_gif'])) {
582 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
583 $newProcessorValue = !$currentProcessorValue;
584 $this->configurationManager->setLocalConfigurationValueByPath(
585 'GFX/processor_allowTemporaryMasksAsPng',
586 $newProcessorValue
587 );
588 }
589
590 if (!empty(array_filter($changedSettings))) {
591 $this->configurationManager->removeLocalConfigurationKeysByPath(array_keys($changedSettings));
592 $this->throwConfigurationChangedException();
593 }
594 }
595
596 /**
597 * Throw exception after configuration change to trigger a redirect.
598 *
599 * @throws ConfigurationChangedException
600 */
601 protected function throwConfigurationChangedException()
602 {
603 throw new ConfigurationChangedException(
604 'Configuration updated, reload needed',
605 1379024938
606 );
607 }
608
609 /**
610 * Migrate the configuration value thumbnails_png to a boolean value.
611 */
612 protected function migrateThumbnailsPngSetting()
613 {
614 $changedValues = [];
615 try {
616 $currentThumbnailsPngValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails_png');
617 } catch (MissingArrayPathException $e) {
618 $currentThumbnailsPngValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails_png');
619 }
620
621 if (is_int($currentThumbnailsPngValue) && $currentThumbnailsPngValue > 0) {
622 $changedValues['GFX/thumbnails_png'] = true;
623 }
624 if (!empty($changedValues)) {
625 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
626 $this->throwConfigurationChangedException();
627 }
628 }
629
630 /**
631 * Migrate the configuration setting BE/lockSSL to boolean if set in the LocalConfiguration.php file
632 */
633 protected function migrateLockSslSetting()
634 {
635 try {
636 $currentOption = $this->configurationManager->getLocalConfigurationValueByPath('BE/lockSSL');
637 // check if the current option is an integer/string and if it is active
638 if (!is_bool($currentOption) && (int)$currentOption > 0) {
639 $this->configurationManager->setLocalConfigurationValueByPath('BE/lockSSL', true);
640 $this->throwConfigurationChangedException();
641 }
642 } catch (MissingArrayPathException $e) {
643 // no change inside the LocalConfiguration.php found, so nothing needs to be modified
644 }
645 }
646
647 /**
648 * Move the database connection settings to a "Default" connection
649 */
650 protected function migrateDatabaseConnectionSettings()
651 {
652 $confManager = $this->configurationManager;
653
654 $newSettings = [];
655 $removeSettings = [];
656
657 try {
658 $value = $confManager->getLocalConfigurationValueByPath('DB/username');
659 $removeSettings[] = 'DB/username';
660 $newSettings['DB/Connections/Default/user'] = $value;
661 } catch (MissingArrayPathException $e) {
662 // Old setting does not exist, do nothing
663 }
664
665 try {
666 $value = $confManager->getLocalConfigurationValueByPath('DB/password');
667 $removeSettings[] = 'DB/password';
668 $newSettings['DB/Connections/Default/password'] = $value;
669 } catch (MissingArrayPathException $e) {
670 // Old setting does not exist, do nothing
671 }
672
673 try {
674 $value = $confManager->getLocalConfigurationValueByPath('DB/host');
675 $removeSettings[] = 'DB/host';
676 $newSettings['DB/Connections/Default/host'] = $value;
677 } catch (MissingArrayPathException $e) {
678 // Old setting does not exist, do nothing
679 }
680
681 try {
682 $value = $confManager->getLocalConfigurationValueByPath('DB/port');
683 $removeSettings[] = 'DB/port';
684 $newSettings['DB/Connections/Default/port'] = $value;
685 } catch (MissingArrayPathException $e) {
686 // Old setting does not exist, do nothing
687 }
688
689 try {
690 $value = $confManager->getLocalConfigurationValueByPath('DB/socket');
691 $removeSettings[] = 'DB/socket';
692 // Remove empty socket connects
693 if (!empty($value)) {
694 $newSettings['DB/Connections/Default/unix_socket'] = $value;
695 }
696 } catch (MissingArrayPathException $e) {
697 // Old setting does not exist, do nothing
698 }
699
700 try {
701 $value = $confManager->getLocalConfigurationValueByPath('DB/database');
702 $removeSettings[] = 'DB/database';
703 $newSettings['DB/Connections/Default/dbname'] = $value;
704 } catch (MissingArrayPathException $e) {
705 // Old setting does not exist, do nothing
706 }
707
708 try {
709 $value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/dbClientCompress');
710 $removeSettings[] = 'SYS/dbClientCompress';
711 if ($value) {
712 $newSettings['DB/Connections/Default/driverOptions'] = [
713 'flags' => MYSQLI_CLIENT_COMPRESS,
714 ];
715 }
716 } catch (MissingArrayPathException $e) {
717 // Old setting does not exist, do nothing
718 }
719
720 try {
721 $value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/no_pconnect');
722 $removeSettings[] = 'SYS/no_pconnect';
723 if (!$value) {
724 $newSettings['DB/Connections/Default/persistentConnection'] = true;
725 }
726 } catch (MissingArrayPathException $e) {
727 // Old setting does not exist, do nothing
728 }
729
730 try {
731 $value = $confManager->getLocalConfigurationValueByPath('SYS/setDBinit');
732 $removeSettings[] = 'SYS/setDBinit';
733 $newSettings['DB/Connections/Default/initCommands'] = $value;
734 } catch (MissingArrayPathException $e) {
735 // Old setting does not exist, do nothing
736 }
737
738 try {
739 $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
740 } catch (MissingArrayPathException $e) {
741 // If there is no charset option yet, add it.
742 $newSettings['DB/Connections/Default/charset'] = 'utf8';
743 }
744
745 try {
746 $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
747 } catch (MissingArrayPathException $e) {
748 // Use the mysqli driver by default if no value has been provided yet
749 $newSettings['DB/Connections/Default/driver'] = 'mysqli';
750 }
751
752 // Add new settings and remove old ones
753 if (!empty($newSettings)) {
754 $confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
755 }
756 if (!empty($removeSettings)) {
757 $confManager->removeLocalConfigurationKeysByPath($removeSettings);
758 }
759
760 // Throw redirect if something was changed
761 if (!empty($newSettings) || !empty($removeSettings)) {
762 $this->throwConfigurationChangedException();
763 }
764 }
765
766 /**
767 * Migrate the configuration setting DB/Connections/Default/charset to 'utf8' as
768 * 'utf-8' is not supported by all MySQL versions.
769 */
770 protected function migrateDatabaseConnectionCharset()
771 {
772 $confManager = $this->configurationManager;
773 try {
774 $driver = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
775 $charset = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
776 if (in_array($driver, ['mysqli', 'pdo_mysql', 'drizzle_pdo_mysql'], true) && $charset === 'utf-8') {
777 $confManager->setLocalConfigurationValueByPath('DB/Connections/Default/charset', 'utf8');
778 $this->throwConfigurationChangedException();
779 }
780 } catch (MissingArrayPathException $e) {
781 // no incompatible charset configuration found, so nothing needs to be modified
782 }
783 }
784
785 /**
786 * Migrate the configuration setting DB/Connections/Default/driverOptions to array type.
787 */
788 protected function migrateDatabaseDriverOptions()
789 {
790 $confManager = $this->configurationManager;
791 try {
792 $options = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driverOptions');
793 if (!is_array($options)) {
794 $confManager->setLocalConfigurationValueByPath(
795 'DB/Connections/Default/driverOptions',
796 ['flags' => (int)$options]
797 );
798 }
799 } catch (MissingArrayPathException $e) {
800 // no driver options found, nothing needs to be modified
801 }
802 }
803
804 /**
805 * Migrate the configuration setting BE/lang/debug if set in the LocalConfiguration.php file
806 */
807 protected function migrateLangDebug()
808 {
809 $confManager = $this->configurationManager;
810 try {
811 $currentOption = $confManager->getLocalConfigurationValueByPath('BE/lang/debug');
812 // check if the current option is set and boolean
813 if (isset($currentOption) && is_bool($currentOption)) {
814 $confManager->setLocalConfigurationValueByPath('BE/languageDebug', $currentOption);
815 }
816 } catch (MissingArrayPathException $e) {
817 // no change inside the LocalConfiguration.php found, so nothing needs to be modified
818 }
819 }
820
821 /**
822 * Migrate single cache hash related options under "FE" into "FE/cacheHash"
823 */
824 protected function migrateCacheHashOptions()
825 {
826 $confManager = $this->configurationManager;
827 $removeSettings = [];
828 $newSettings = [];
829
830 try {
831 $value = $confManager->getLocalConfigurationValueByPath('FE/cHashOnlyForParameters');
832 $removeSettings[] = 'FE/cHashOnlyForParameters';
833 $newSettings['FE/cacheHash/cachedParametersWhiteList'] = GeneralUtility::trimExplode(',', $value, true);
834 } catch (MissingArrayPathException $e) {
835 // Migration done already
836 }
837
838 try {
839 $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParameters');
840 $removeSettings[] = 'FE/cHashExcludedParameters';
841 $newSettings['FE/cacheHash/excludedParameters'] = GeneralUtility::trimExplode(',', $value, true);
842 } catch (MissingArrayPathException $e) {
843 // Migration done already
844 }
845
846 try {
847 $value = $confManager->getLocalConfigurationValueByPath('FE/cHashRequiredParameters');
848 $removeSettings[] = 'FE/cHashRequiredParameters';
849 $newSettings['FE/cacheHash/requireCacheHashPresenceParameters'] = GeneralUtility::trimExplode(',', $value, true);
850 } catch (MissingArrayPathException $e) {
851 // Migration done already
852 }
853
854 try {
855 $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParametersIfEmpty');
856 $removeSettings[] = 'FE/cHashExcludedParametersIfEmpty';
857 if (trim($value) === '*') {
858 $newSettings['FE/cacheHash/excludeAllEmptyParameters'] = true;
859 } else {
860 $newSettings['FE/cacheHash/excludedParametersIfEmpty'] = GeneralUtility::trimExplode(',', $value, true);
861 }
862 } catch (MissingArrayPathException $e) {
863 // Migration done already
864 }
865
866 // Add new settings and remove old ones
867 if (!empty($newSettings)) {
868 $confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
869 }
870 if (!empty($removeSettings)) {
871 $confManager->removeLocalConfigurationKeysByPath($removeSettings);
872 }
873
874 // Throw redirect if something was changed
875 if (!empty($newSettings) || !empty($removeSettings)) {
876 $this->throwConfigurationChangedException();
877 }
878 }
879
880 /**
881 * Migrate SYS/exceptionalErrors to not contain E_USER_DEPRECATED
882 */
883 protected function migrateExceptionErrors()
884 {
885 $confManager = $this->configurationManager;
886 try {
887 $currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/exceptionalErrors');
888 // make sure E_USER_DEPRECATED is not part of the exceptionalErrors
889 if ($currentOption & E_USER_DEPRECATED) {
890 $confManager->setLocalConfigurationValueByPath('SYS/exceptionalErrors', $currentOption & ~E_USER_DEPRECATED);
891 }
892 } catch (MissingArrayPathException $e) {
893 // no change inside the LocalConfiguration.php found, so nothing needs to be modified
894 }
895 }
896
897 /**
898 * Migrate SYS/displayErrors to not contain 2
899 */
900 protected function migrateDisplayErrorsSetting()
901 {
902 $confManager = $this->configurationManager;
903 try {
904 $currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/displayErrors');
905 // make sure displayErrors is set to 2
906 if ($currentOption === 2) {
907 $confManager->setLocalConfigurationValueByPath('SYS/displayErrors', -1);
908 }
909 } catch (MissingArrayPathException $e) {
910 // no change inside the LocalConfiguration.php found, so nothing needs to be modified
911 }
912 }
913 }