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