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