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