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