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