5ac4ac8a0d1d691ebb68d34839ca5bfb7f579549
[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\Controller\Exception\RedirectException;
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 RedirectException
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 ];
85
86 public function __construct(ConfigurationManager $configurationManager = null)
87 {
88 $this->configurationManager = $configurationManager ?: GeneralUtility::makeInstance(ConfigurationManager::class);
89 }
90
91 /**
92 * Executed configuration upgrades. Single upgrade methods must throw a
93 * RedirectException if something was written to LocalConfiguration.
94 *
95 * @return void
96 */
97 public function execute()
98 {
99 $this->generateEncryptionKeyIfNeeded();
100 $this->configureBackendLoginSecurity();
101 $this->configureSaltedPasswords();
102 $this->migrateImageProcessorSetting();
103 $this->transferHttpSettings();
104 $this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
105 $this->setImageMagickDetailSettings();
106 $this->removeObsoleteLocalConfigurationSettings();
107 $this->migrateThumbnailsPngSetting();
108 $this->migrateLockSslSetting();
109 $this->migrateDatabaseConnectionSettings();
110 }
111
112 /**
113 * Some settings in LocalConfiguration vanished in DefaultConfiguration
114 * and have no impact on the core anymore.
115 * To keep the configuration clean, those old settings are just silently
116 * removed from LocalConfiguration if set.
117 *
118 * @return void
119 */
120 protected function removeObsoleteLocalConfigurationSettings()
121 {
122 $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
123
124 // If something was changed: Trigger a reload to have new values in next request
125 if ($removed) {
126 $this->throwRedirectException();
127 }
128 }
129
130 /**
131 * Backend login security is set to rsa if rsaauth
132 * is installed (but not used) otherwise the default value "normal" has to be used.
133 * This forces either 'normal' or 'rsa' to be set in LocalConfiguration.
134 *
135 * @return void
136 */
137 protected function configureBackendLoginSecurity()
138 {
139 $rsaauthLoaded = ExtensionManagementUtility::isLoaded('rsaauth');
140 try {
141 $currentLoginSecurityLevelValue = $this->configurationManager->getLocalConfigurationValueByPath('BE/loginSecurityLevel');
142 if ($rsaauthLoaded && $currentLoginSecurityLevelValue !== 'rsa') {
143 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
144 $this->throwRedirectException();
145 } elseif (!$rsaauthLoaded && $currentLoginSecurityLevelValue !== 'normal') {
146 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
147 $this->throwRedirectException();
148 }
149 } catch (\RuntimeException $e) {
150 // If an exception is thrown, the value is not set in LocalConfiguration
151 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel',
152 $rsaauthLoaded ? 'rsa' : 'normal');
153 $this->throwRedirectException();
154 }
155 }
156
157 /**
158 * Check the settings for salted passwords extension to load it as a required extension.
159 * Unset obsolete configuration options if given.
160 *
161 * @return void
162 */
163 protected function configureSaltedPasswords()
164 {
165 $defaultConfiguration = $this->configurationManager->getDefaultConfiguration();
166 $defaultExtensionConfiguration = unserialize($defaultConfiguration['EXT']['extConf']['saltedpasswords']);
167 try {
168 $extensionConfiguration = @unserialize($this->configurationManager->getLocalConfigurationValueByPath('EXT/extConf/saltedpasswords'));
169 } catch (\RuntimeException $e) {
170 $extensionConfiguration = [];
171 }
172 if (is_array($extensionConfiguration) && !empty($extensionConfiguration)) {
173 if (isset($extensionConfiguration['BE.']['enabled'])) {
174 if ($extensionConfiguration['BE.']['enabled']) {
175 unset($extensionConfiguration['BE.']['enabled']);
176 } else {
177 $extensionConfiguration['BE.'] = $defaultExtensionConfiguration['BE.'];
178 }
179 $this->configurationManager->setLocalConfigurationValueByPath(
180 'EXT/extConf/saltedpasswords',
181 serialize($extensionConfiguration)
182 );
183 $this->throwRedirectException();
184 }
185 } else {
186 $this->configurationManager->setLocalConfigurationValueByPath(
187 'EXT/extConf/saltedpasswords',
188 serialize($defaultExtensionConfiguration)
189 );
190 $this->throwRedirectException();
191 }
192 }
193
194 /**
195 * The encryption key is crucial for securing form tokens
196 * and the whole TYPO3 link rendering later on. A random key is set here in
197 * LocalConfiguration if it does not exist yet. This might possible happen
198 * during upgrading and will happen during first install.
199 *
200 * @return void
201 */
202 protected function generateEncryptionKeyIfNeeded()
203 {
204 try {
205 $currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
206 } catch (\RuntimeException $e) {
207 // If an exception is thrown, the value is not set in LocalConfiguration
208 $currentValue = '';
209 }
210
211 if (empty($currentValue)) {
212 $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96);
213 $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
214 $this->throwRedirectException();
215 }
216 }
217
218 /**
219 * Parse old curl and HTTP options and set new HTTP options, related to Guzzle
220 *
221 * @return void
222 */
223 protected function transferHttpSettings()
224 {
225 $changed = false;
226 $newParameters = [];
227 $obsoleteParameters = [];
228
229 // Remove / migrate options to new options
230 try {
231 // Check if the adapter option is set, if so, set it to the parameters that are obsolete
232 $this->configurationManager->getLocalConfigurationValueByPath('HTTP/adapter');
233 $obsoleteParameters[] = 'HTTP/adapter';
234 } catch (\RuntimeException $e) {
235 }
236 try {
237 $newParameters['HTTP/version'] = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/protocol_version');
238 $obsoleteParameters[] = 'HTTP/protocol_version';
239 } catch (\RuntimeException $e) {
240 }
241 try {
242 $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_host');
243 $obsoleteParameters[] = 'HTTP/ssl_verify_host';
244 } catch (\RuntimeException $e) {
245 }
246 try {
247 $legacyUserAgent = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/userAgent');
248 $newParameters['HTTP/headers/User-Agent'] = $legacyUserAgent;
249 $obsoleteParameters[] = 'HTTP/userAgent';
250 } catch (\RuntimeException $e) {
251 }
252
253 // Redirects
254 try {
255 $legacyFollowRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/follow_redirects');
256 $obsoleteParameters[] = 'HTTP/follow_redirects';
257 } catch (\RuntimeException $e) {
258 $legacyFollowRedirects = '';
259 }
260 try {
261 $legacyMaximumRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/max_redirects');
262 $obsoleteParameters[] = 'HTTP/max_redirects';
263 } catch (\RuntimeException $e) {
264 $legacyMaximumRedirects = '';
265 }
266 try {
267 $legacyStrictRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/strict_redirects');
268 $obsoleteParameters[] = 'HTTP/strict_redirects';
269 } catch (\RuntimeException $e) {
270 $legacyStrictRedirects = '';
271 }
272
273 // Check if redirects have been disabled
274 if ($legacyFollowRedirects !== '' && (bool)$legacyFollowRedirects === false) {
275 $newParameters['HTTP/allow_redirects'] = false;
276 } elseif ($legacyMaximumRedirects !== '' || $legacyStrictRedirects !== '') {
277 $newParameters['HTTP/allow_redirects'] = [];
278 if ($legacyMaximumRedirects !== '' && (int)$legacyMaximumRedirects !== 5) {
279 $newParameters['HTTP/allow_redirects']['max'] = (int)$legacyMaximumRedirects;
280 }
281 if ($legacyStrictRedirects !== '' && (bool)$legacyStrictRedirects === true) {
282 $newParameters['HTTP/allow_redirects']['strict'] = true;
283 }
284 // defaults are used, no need to set the option in LocalConfiguration.php
285 if (empty($newParameters['HTTP/allow_redirects'])) {
286 unset($newParameters['HTTP/allow_redirects']);
287 }
288 }
289
290 // Migrate Proxy settings
291 try {
292 // Currently without protocol or port
293 $legacyProxyHost = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_host');
294 $obsoleteParameters[] = 'HTTP/proxy_host';
295 } catch (\RuntimeException $e) {
296 $legacyProxyHost = '';
297 }
298 try {
299 $legacyProxyPort = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_port');
300 $obsoleteParameters[] = 'HTTP/proxy_port';
301 } catch (\RuntimeException $e) {
302 $legacyProxyPort = '';
303 }
304 try {
305 $legacyProxyUser = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_user');
306 $obsoleteParameters[] = 'HTTP/proxy_user';
307 } catch (\RuntimeException $e) {
308 $legacyProxyUser = '';
309 }
310 try {
311 $legacyProxyPassword = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_password');
312 $obsoleteParameters[] = 'HTTP/proxy_password';
313 } catch (\RuntimeException $e) {
314 $legacyProxyPassword = '';
315 }
316 // Auth Scheme: Basic, digest etc.
317 try {
318 $legacyProxyAuthScheme = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
319 $obsoleteParameters[] = 'HTTP/proxy_auth_scheme';
320 } catch (\RuntimeException $e) {
321 $legacyProxyAuthScheme = '';
322 }
323
324 if ($legacyProxyHost !== '') {
325 $proxy = 'http://';
326 if ($legacyProxyAuthScheme !== '' && $legacyProxyUser !== '' && $legacyProxyPassword !== '') {
327 $proxy .= $legacyProxyUser . ':' . $legacyProxyPassword . '@';
328 }
329 $proxy .= $legacyProxyHost;
330 if ($legacyProxyPort !== '') {
331 $proxy .= ':' . $legacyProxyPort;
332 }
333 $newParameters['HTTP/proxy'] = $proxy;
334 }
335
336 // Verify peers
337 // see http://docs.guzzlephp.org/en/latest/request-options.html#verify
338 try {
339 $legacySslVerifyPeer = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_peer');
340 $obsoleteParameters[] = 'HTTP/ssl_verify_peer';
341 } catch (\RuntimeException $e) {
342 $legacySslVerifyPeer = '';
343 }
344
345 // Directory holding multiple Certificate Authority files
346 try {
347 $legacySslCaPath = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_capath');
348 $obsoleteParameters[] = 'HTTP/ssl_capath';
349 } catch (\RuntimeException $e) {
350 $legacySslCaPath = '';
351 }
352 // Certificate Authority file to verify the peer with (use when ssl_verify_peer is TRUE)
353 try {
354 $legacySslCaFile = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_cafile');
355 $obsoleteParameters[] = 'HTTP/ssl_cafile';
356 } catch (\RuntimeException $e) {
357 $legacySslCaFile = '';
358 }
359 if ($legacySslVerifyPeer !== '') {
360 if ($legacySslCaFile !== '' && $legacySslCaPath !== '') {
361 $newParameters['HTTP/verify'] = $legacySslCaPath . $legacySslCaFile;
362 } elseif ((bool)$legacySslVerifyPeer === false) {
363 $newParameters['HTTP/verify'] = false;
364 }
365 }
366
367 // SSL Key + Passphrase
368 // Name of a file containing local certificate
369 try {
370 $legacySslLocalCert = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_local_cert');
371 $obsoleteParameters[] = 'HTTP/ssl_local_cert';
372 } catch (\RuntimeException $e) {
373 $legacySslLocalCert = '';
374 }
375
376 // Passphrase with which local certificate was encoded
377 try {
378 $legacySslPassphrase = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_passphrase');
379 $obsoleteParameters[] = 'HTTP/ssl_passphrase';
380 } catch (\RuntimeException $e) {
381 $legacySslPassphrase = '';
382 }
383
384 if ($legacySslLocalCert !== '') {
385 if ($legacySslPassphrase !== '') {
386 $newParameters['HTTP/ssl_key'] = [
387 $legacySslLocalCert,
388 $legacySslPassphrase
389 ];
390 } else {
391 $newParameters['HTTP/ssl_key'] = $legacySslLocalCert;
392 }
393 }
394
395 // Update the LocalConfiguration file if obsolete parameters or new parameters are set
396 if (!empty($obsoleteParameters)) {
397 $this->configurationManager->removeLocalConfigurationKeysByPath($obsoleteParameters);
398 $changed = true;
399 }
400 if (!empty($newParameters)) {
401 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($newParameters);
402 $changed = true;
403 }
404 if ($changed) {
405 $this->throwRedirectException();
406 }
407 }
408
409 /**
410 * Detail configuration of Image Magick settings must be cleared
411 * if Image Magick handling is disabled.
412 *
413 * "Configuration presets" in install tool is not type safe, so value
414 * comparisons here are not type safe too, to not trigger changes to
415 * LocalConfiguration again.
416 *
417 * @return void
418 */
419 protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled()
420 {
421 $changedValues = [];
422 try {
423 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_enabled');
424 } catch (\RuntimeException $e) {
425 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_enabled');
426 }
427
428 try {
429 $currentImPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path');
430 } catch (\RuntimeException $e) {
431 $currentImPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path');
432 }
433
434 try {
435 $currentImPathLzwValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path_lzw');
436 } catch (\RuntimeException $e) {
437 $currentImPathLzwValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path_lzw');
438 }
439
440 try {
441 $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
442 } catch (\RuntimeException $e) {
443 $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
444 }
445
446 try {
447 $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
448 } catch (\RuntimeException $e) {
449 $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
450 }
451
452 if (!$currentImValue) {
453 if ($currentImPathValue != '') {
454 $changedValues['GFX/processor_path'] = '';
455 }
456 if ($currentImPathLzwValue != '') {
457 $changedValues['GFX/processor_path_lzw'] = '';
458 }
459 if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
460 $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
461 }
462 if ($currentThumbnailsValue != 0) {
463 $changedValues['GFX/thumbnails'] = 0;
464 }
465 }
466 if (!empty($changedValues)) {
467 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
468 $this->throwRedirectException();
469 }
470 }
471
472 /**
473 * Detail configuration of Image Magick and Graphics Magick settings
474 * depending on main values.
475 *
476 * "Configuration presets" in install tool is not type safe, so value
477 * comparisons here are not type safe too, to not trigger changes to
478 * LocalConfiguration again.
479 *
480 * @return void
481 */
482 protected function setImageMagickDetailSettings()
483 {
484 $changedValues = [];
485 try {
486 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor');
487 } catch (\RuntimeException $e) {
488 $currentProcessorValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor');
489 }
490
491 try {
492 $currentProcessorMaskValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_allowTemporaryMasksAsPng');
493 } catch (\RuntimeException $e) {
494 $currentProcessorMaskValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_allowTemporaryMasksAsPng');
495 }
496
497 try {
498 $currentProcessorEffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_effects');
499 } catch (\RuntimeException $e) {
500 $currentProcessorEffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_effects');
501 }
502
503 if ((string)$currentProcessorValue !== '') {
504 if ($currentProcessorMaskValue != 0) {
505 $changedValues['GFX/processor_allowTemporaryMasksAsPng'] = 0;
506 }
507 if ($currentProcessorValue === 'GraphicsMagick') {
508 if ($currentProcessorEffectsValue != -1) {
509 $changedValues['GFX/processor_effects'] = -1;
510 }
511 }
512 }
513 if (!empty($changedValues)) {
514 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
515 $this->throwRedirectException();
516 }
517 }
518
519 /**
520 * Migrate the definition of the image processor from the configuration value
521 * im_version_5 to the setting processor.
522 *
523 * @return void
524 */
525 protected function migrateImageProcessorSetting()
526 {
527 $changedSettings = [];
528 $settingsToRename = [
529 'GFX/im' => 'GFX/processor_enabled',
530 'GFX/im_version_5' => 'GFX/processor',
531 'GFX/im_v5effects' => 'GFX/processor_effects',
532 'GFX/im_path' => 'GFX/processor_path',
533 'GFX/im_path_lzw' => 'GFX/processor_path_lzw',
534 'GFX/im_mask_temp_ext_gif' => 'GFX/processor_allowTemporaryMasksAsPng',
535 'GFX/im_noScaleUp' => 'GFX/processor_allowUpscaling',
536 'GFX/im_noFramePrepended' => 'GFX/processor_allowFrameSelection',
537 'GFX/im_stripProfileCommand' => 'GFX/processor_stripColorProfileCommand',
538 'GFX/im_useStripProfileByDefault' => 'GFX/processor_stripColorProfileByDefault',
539 'GFX/colorspace' => 'GFX/processor_colorspace',
540 ];
541
542 foreach ($settingsToRename as $oldPath => $newPath) {
543 try {
544 $value = $this->configurationManager->getLocalConfigurationValueByPath($oldPath);
545 $this->configurationManager->setLocalConfigurationValueByPath($newPath, $value);
546 $changedSettings[$oldPath] = true;
547 } catch (\RuntimeException $e) {
548 // If an exception is thrown, the value is not set in LocalConfiguration
549 $changedSettings[$oldPath] = false;
550 }
551 }
552
553 if (!empty($changedSettings['GFX/im_version_5'])) {
554 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
555 $newProcessorValue = $currentProcessorValue === 'gm' ? 'GraphicsMagick' : 'ImageMagick';
556 $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor', $newProcessorValue);
557 }
558
559 if (!empty($changedSettings['GFX/im_noScaleUp'])) {
560 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noScaleUp');
561 $newProcessorValue = !$currentProcessorValue;
562 $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor_allowUpscaling',
563 $newProcessorValue);
564 }
565
566 if (!empty($changedSettings['GFX/im_noFramePrepended'])) {
567 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noFramePrepended');
568 $newProcessorValue = !$currentProcessorValue;
569 $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor_allowFrameSelection',
570 $newProcessorValue);
571 }
572
573 if (!empty($changedSettings['GFX/im_mask_temp_ext_gif'])) {
574 $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
575 $newProcessorValue = !$currentProcessorValue;
576 $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor_allowTemporaryMasksAsPng',
577 $newProcessorValue);
578 }
579
580 if (!empty(array_filter($changedSettings))) {
581 $this->configurationManager->removeLocalConfigurationKeysByPath(array_keys($changedSettings));
582 $this->throwRedirectException();
583 }
584 }
585
586 /**
587 * Throw exception after configuration change to trigger a redirect.
588 *
589 * @throws RedirectException
590 */
591 protected function throwRedirectException()
592 {
593 throw new RedirectException(
594 'Configuration updated, reload needed',
595 1379024938
596 );
597 }
598
599 /**
600 * Migrate the configuration value thumbnails_png to a boolean value.
601 *
602 * @return void
603 */
604 protected function migrateThumbnailsPngSetting()
605 {
606 $changedValues = [];
607 try {
608 $currentThumbnailsPngValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails_png');
609 } catch (\RuntimeException $e) {
610 $currentThumbnailsPngValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails_png');
611 }
612
613 if (is_int($currentThumbnailsPngValue) && $currentThumbnailsPngValue > 0) {
614 $changedValues['GFX/thumbnails_png'] = true;
615 }
616 if (!empty($changedValues)) {
617 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
618 $this->throwRedirectException();
619 }
620 }
621
622 /**
623 * Migrate the configuration setting BE/lockSSL to boolean if set in the LocalConfiguration.php file
624 *
625 * @return void
626 */
627 protected function migrateLockSslSetting()
628 {
629 try {
630 $currentOption = $this->configurationManager->getLocalConfigurationValueByPath('BE/lockSSL');
631 // check if the current option is an integer/string and if it is active
632 if (!is_bool($currentOption) && (int)$currentOption > 0) {
633 $this->configurationManager->setLocalConfigurationValueByPath('BE/lockSSL', true);
634 $this->throwRedirectException();
635 }
636 } catch (\RuntimeException $e) {
637 // no change inside the LocalConfiguration.php found, so nothing needs to be modified
638 }
639 }
640
641 /**
642 * Move the database connection settings to a "Default" connection
643 *
644 * @return void
645 */
646 protected function migrateDatabaseConnectionSettings()
647 {
648 $changedSettings = [];
649 $settingsToRename = [
650 'DB/username' => 'DB/Connections/Default/user',
651 'DB/password' => 'DB/Connections/Default/password',
652 'DB/host' => 'DB/Connections/Default/host',
653 'DB/port' => 'DB/Connections/Default/port',
654 'DB/socket' => 'DB/Connections/Default/unix_socket',
655 'DB/database' => 'DB/Connections/Default/dbname',
656 'SYS/setDBinit' => 'DB/Connections/Default/initCommands',
657 'SYS/no_pconnect' => 'DB/Connections/Default/persistentConnection',
658 'SYS/dbClientCompress' => 'DB/Connections/Default/driverOptions',
659
660 ];
661
662 $confManager = $this->configurationManager;
663
664 foreach ($settingsToRename as $oldPath => $newPath) {
665 try {
666 $value = $confManager->getLocalConfigurationValueByPath($oldPath);
667 $confManager->setLocalConfigurationValueByPath($newPath, $value);
668 $changedSettings[$oldPath] = true;
669 } catch (\RuntimeException $e) {
670 // If an exception is thrown, the value is not set in LocalConfiguration
671 $changedSettings[$oldPath] = false;
672 }
673 }
674
675 // Remove empty socket connects
676 if (!empty($changedSettings['DB/Connections/Default/unix_socket'])) {
677 $value = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/unix_socket');
678 if (empty($value)) {
679 $confManager->removeLocalConfigurationKeysByPath(array_keys('DB/Connections/Default/unix_socket'));
680 }
681 }
682
683 // Convert the dbClientCompress flag to a mysqli driver option
684 if (!empty($changedSettings['DB/Connections/Default/driverOptions'])) {
685 $value = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driverOptions');
686 $confManager->setLocalConfigurationValueByPath(
687 'DB/Connections/Default/driverOptions',
688 (bool)$value ? MYSQLI_CLIENT_COMPRESS : 0
689 );
690 }
691
692 // Swap value as the semantics have changed
693 if (!empty($changedSettings['DB/Connections/Default/persistentConnection'])) {
694 $value = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/persistentConnection');
695 $confManager->setLocalConfigurationValueByPath(
696 'DB/Connections/Default/persistentConnection',
697 !$value
698 );
699 }
700
701 // Set the utf-8 connection charset by default
702 $confManager->setLocalConfigurationValueByPath('DB/Connections/Default/charset', 'utf-8');
703
704 // Use the mysqli driver by default
705 $confManager->setLocalConfigurationValueByPath('DB/Connections/Default/driver', 'mysqli');
706
707 if (!empty(array_filter($changedSettings))) {
708 $confManager->removeLocalConfigurationKeysByPath(array_keys($changedSettings));
709 $this->throwRedirectException();
710 }
711 }
712 }