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