Passed
Branch master (6c65a4)
by Christian
27:15 queued 11:09
created

transferHttpSettings()   F

Complexity

Conditions 41
Paths 0

Size

Total Lines 183
Code Lines 123

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 41
eloc 123
nc 0
nop 0
dl 0
loc 183
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

825
            $newSettings['FE/cacheHash/cachedParametersWhiteList'] = GeneralUtility::trimExplode(',', /** @scrutinizer ignore-type */ $value, true);
Loading history...
826
        } catch (\RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
827
        }
828
829
        try {
830
            $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParameters');
831
            $removeSettings[] = 'FE/cHashExcludedParameters';
832
            $newSettings['FE/cacheHash/excludedParameters'] = GeneralUtility::trimExplode(',', $value, true);
833
        } catch (\RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
834
        }
835
836
        try {
837
            $value = $confManager->getLocalConfigurationValueByPath('FE/cHashRequiredParameters');
838
            $removeSettings[] = 'FE/cHashRequiredParameters';
839
            $newSettings['FE/cacheHash/requireCacheHashPresenceParameters'] = GeneralUtility::trimExplode(',', $value, true);
840
        } catch (\RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
841
        }
842
843
        try {
844
            $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParametersIfEmpty');
845
            $removeSettings[] = 'FE/cHashExcludedParametersIfEmpty';
846
            if (trim($value) === '*') {
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

846
            if (trim(/** @scrutinizer ignore-type */ $value) === '*') {
Loading history...
847
                $newSettings['FE/cacheHash/excludeAllEmptyParameters'] = true;
848
            } else {
849
                $newSettings['FE/cacheHash/excludedParametersIfEmpty'] = GeneralUtility::trimExplode(',', $value, true);
850
            }
851
        } catch (\RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
852
        }
853
854
        // Add new settings and remove old ones
855
        if (!empty($newSettings)) {
856
            $confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
857
        }
858
        if (!empty($removeSettings)) {
859
            $confManager->removeLocalConfigurationKeysByPath($removeSettings);
860
        }
861
862
        // Throw redirect if something was changed
863
        if (!empty($newSettings) || !empty($removeSettings)) {
864
            $this->throwConfigurationChangedException();
865
        }
866
    }
867
868
    /**
869
     * Migrate SYS/exceptionalErrors to not contain E_USER_DEPRECATED
870
     */
871
    protected function migrateExceptionErrors()
872
    {
873
        $confManager = $this->configurationManager;
874
        try {
875
            $currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/exceptionalErrors');
876
            // make sure E_USER_DEPRECATED is not part of the exceptionalErrors
877
            if ($currentOption & E_USER_DEPRECATED) {
878
                $confManager->setLocalConfigurationValueByPath('SYS/exceptionalErrors', $currentOption & ~E_USER_DEPRECATED);
879
            }
880
        } catch (\RuntimeException $e) {
881
            // no change inside the LocalConfiguration.php found, so nothing needs to be modified
882
        }
883
    }
884
}
885