‪TYPO3CMS  ‪main
SilentConfigurationUpgradeService.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
30 
45 {
53  // #72400
54  'BE/spriteIconGenerator_handler',
55  // #72417
56  'SYS/lockingMode',
57  // #72473
58  'FE/secureFormmail',
59  'FE/strictFormmail',
60  'FE/formmailMaxAttachmentSize',
61  // #72337
62  'SYS/t3lib_cs_utils',
63  'SYS/t3lib_cs_convMethod',
64  // #72604
65  'SYS/maxFileNameLength',
66  // #72602
67  'BE/unzip_path',
68  // #72615
69  'BE/notificationPrefix',
70  // #72616
71  'BE/XCLASS',
72  'FE/XCLASS',
73  // #43085
74  'GFX/image_processing',
75  // #70056
76  'SYS/curlUse',
77  'SYS/curlProxyNTLM',
78  'SYS/curlProxyServer',
79  'SYS/curlProxyTunnel',
80  'SYS/curlProxyUserPass',
81  'SYS/curlTimeout',
82  // #75355
83  'BE/niceFlexFormXMLtags',
84  'BE/compactFlexFormXML',
85  // #75625
86  'SYS/clearCacheSystem',
87  // #77411
88  'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_tablecolumns',
89  // #77460
90  'SYS/caching/cacheConfigurations/extbase_typo3dbbackend_queries',
91  // #79513
92  'FE/lockHashKeyWords',
93  'BE/lockHashKeyWords',
94  // #78835
95  'SYS/cookieHttpOnly',
96  // #71095
97  'BE/lang',
98  // #80050
99  'FE/cHashIncludePageId',
100  // #80711
101  'FE/noPHPscriptInclude',
102  'FE/maxSessionDataSize',
103  // #82162
104  'SYS/enable_errorDLOG',
105  'SYS/enable_exceptionDLOG',
106  // #82377
107  'EXT/allowSystemInstall',
108  // #82421
109  'SYS/sqlDebug',
110  'SYS/no_pconnect',
111  'SYS/setDBinit',
112  'SYS/dbClientCompress',
113  // #82430
114  'SYS/syslogErrorReporting',
115  // #82639
116  'SYS/enable_DLOG',
117  'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLog',
118  'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogBE',
119  'SC_OPTIONS/t3lib/class.t3lib_userauth.php/writeDevLogFE',
120  // #82438
121  'SYS/enableDeprecationLog',
122  // #82680
123  'GFX/png_truecolor',
124  // #82803
125  'FE/content_doktypes',
126  // #83081
127  'BE/fileExtensions',
128  // #83768
129  'SYS/doNotCheckReferer',
130  // #83878
131  'SYS/isInitialInstallationInProgress',
132  'SYS/isInitialDatabaseImportDone',
133  // #84810
134  'BE/explicitConfirmationOfTranslation',
135  // #87482
136  'EXT/extConf',
137  // #87767
138  'SYS/recursiveDomainSearch',
139  // #88376
140  'FE/pageNotFound_handling',
141  'FE/pageNotFound_handling_statheader',
142  'FE/pageNotFound_handling_accessdeniedheader',
143  'FE/pageUnavailable_handling',
144  'FE/pageUnavailable_handling_statheader',
145  // #88458
146  'FE/get_url_id_token',
147  // #88500
148  'BE/RTE_imageStorageDir',
149  // #89645
150  'SYS/systemLog',
151  'SYS/systemLogLevel',
152  // #91974
153  'FE/IPmaskMountGroups',
154  // #87301
155  'SYS/cookieSecure',
156  // #92940
157  'BE/lockBeUserToDBmounts',
158  // #92941
159  'BE/enabledBeUserIPLock',
160  // #94312
161  'BE/loginSecurityLevel',
162  'FE/loginSecurityLevel',
163  // #94871
164  'SYS/features/form.legacyUploadMimeTypes',
165  // #96550
166  'SYS/USdateFormat',
167  // #96982
168  'EXT/allowGlobalInstall',
169  // #96988
170  'EXT/allowLocalInstall',
171  // #97265
172  'BE/explicitADmode',
173  // #98179
174  'BE/interfaces',
175  // Please note that further migrations in this file are kept in order to remove the setting at the very end
176  // #97797
177  'GFX/processor_path_lzw',
178  // #98503
179  'SYS/caching/cacheConfigurations/pagesection',
180  // #99075
181  'FE/defaultUserTSconfig',
182  // #101037
183  'BE/languageDebug',
184  'BE/lang/debug',
185  // #101793
186  'BE/checkStoredRecords',
187  'BE/checkStoredRecordsLoose',
188  // #101941
189  'GFX/thumbnails_png',
190  'GFX/gif_compress',
191  // #101950
192  'GFX/processor_allowTemporaryMasksAsPng',
193  // #102020
194  'GFX/gdlib_png',
195  // #102023
196  'SYS/features/security.usePasswordPolicyForFrontendUsers',
197  // #102113
198  'GFX/gdlib',
199  // #102146
200  'BE/flexformForceCDATA',
201  ];
202 
203  public function ‪__construct(private readonly ConfigurationManager $configurationManager) {}
204 
212  public function ‪execute(): void
213  {
216  $this->‪transferHttpSettings();
220  $this->‪migrateLockSslSetting();
225  $this->‪migrateExceptionErrors();
232 
233  // Should run at the end to prevent obsolete settings are removed before migration
235  }
236 
242  protected function ‪throwConfigurationChangedException(): void
243  {
245  'Configuration updated, reload needed',
246  1379024938
247  );
248  }
249 
259  {
260  $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
261 
262  // If something was changed: Trigger reload to have new values in next request
263  if ($removed) {
265  }
266  }
267 
276  protected function ‪generateEncryptionKeyIfNeeded(): void
277  {
278  try {
279  $currentValue = $this->configurationManager->getLocalConfigurationValueByPath('SYS/encryptionKey');
280  } catch (‪MissingArrayPathException) {
281  // If an exception is thrown, the value is not set in LocalConfiguration
282  $currentValue = '';
283  }
284 
285  if (empty($currentValue)) {
286  $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96);
287  $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
289  }
290  }
291 
297  protected function ‪transferHttpSettings(): void
298  {
299  $changed = false;
300  $newParameters = [];
301  $obsoleteParameters = [];
302 
303  // Remove / migrate options to new options
304  try {
305  // Check if the adapter option is set, if so, set it to the parameters that are obsolete
306  $this->configurationManager->getLocalConfigurationValueByPath('HTTP/adapter');
307  $obsoleteParameters[] = 'HTTP/adapter';
308  } catch (‪MissingArrayPathException) {
309  // Migration done already
310  }
311  try {
312  $newParameters['HTTP/version'] = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/protocol_version');
313  $obsoleteParameters[] = 'HTTP/protocol_version';
314  } catch (‪MissingArrayPathException) {
315  // Migration done already
316  }
317  try {
318  $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_host');
319  $obsoleteParameters[] = 'HTTP/ssl_verify_host';
320  } catch (‪MissingArrayPathException) {
321  // Migration done already
322  }
323  try {
324  $legacyUserAgent = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/userAgent');
325  $newParameters['HTTP/headers/User-Agent'] = $legacyUserAgent;
326  $obsoleteParameters[] = 'HTTP/userAgent';
327  } catch (‪MissingArrayPathException) {
328  // Migration done already
329  }
330 
331  // Redirects
332  try {
333  $legacyFollowRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/follow_redirects');
334  $obsoleteParameters[] = 'HTTP/follow_redirects';
335  } catch (‪MissingArrayPathException) {
336  $legacyFollowRedirects = '';
337  }
338  try {
339  $legacyMaximumRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/max_redirects');
340  $obsoleteParameters[] = 'HTTP/max_redirects';
341  } catch (‪MissingArrayPathException) {
342  $legacyMaximumRedirects = '';
343  }
344  try {
345  $legacyStrictRedirects = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/strict_redirects');
346  $obsoleteParameters[] = 'HTTP/strict_redirects';
347  } catch (‪MissingArrayPathException) {
348  $legacyStrictRedirects = '';
349  }
350 
351  // Check if redirects have been disabled
352  if ($legacyFollowRedirects !== '' && (bool)$legacyFollowRedirects === false) {
353  $newParameters['HTTP/allow_redirects'] = false;
354  } elseif ($legacyMaximumRedirects !== '' || $legacyStrictRedirects !== '') {
355  $newParameters['HTTP/allow_redirects'] = [];
356  if ($legacyMaximumRedirects !== '' && (int)$legacyMaximumRedirects !== 5) {
357  $newParameters['HTTP/allow_redirects']['max'] = (int)$legacyMaximumRedirects;
358  }
359  if ($legacyStrictRedirects !== '' && (bool)$legacyStrictRedirects === true) {
360  $newParameters['HTTP/allow_redirects']['strict'] = true;
361  }
362  // defaults are used, no need to set the option in system/settings.php
363  if (empty($newParameters['HTTP/allow_redirects'])) {
364  unset($newParameters['HTTP/allow_redirects']);
365  }
366  }
367 
368  // Migrate Proxy settings
369  try {
370  // Currently without protocol or port
371  $legacyProxyHost = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_host');
372  $obsoleteParameters[] = 'HTTP/proxy_host';
373  } catch (‪MissingArrayPathException) {
374  $legacyProxyHost = '';
375  }
376  try {
377  $legacyProxyPort = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_port');
378  $obsoleteParameters[] = 'HTTP/proxy_port';
379  } catch (‪MissingArrayPathException) {
380  $legacyProxyPort = '';
381  }
382  try {
383  $legacyProxyUser = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_user');
384  $obsoleteParameters[] = 'HTTP/proxy_user';
385  } catch (‪MissingArrayPathException) {
386  $legacyProxyUser = '';
387  }
388  try {
389  $legacyProxyPassword = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_password');
390  $obsoleteParameters[] = 'HTTP/proxy_password';
391  } catch (‪MissingArrayPathException) {
392  $legacyProxyPassword = '';
393  }
394  // Auth Scheme: Basic, digest etc.
395  try {
396  $legacyProxyAuthScheme = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
397  $obsoleteParameters[] = 'HTTP/proxy_auth_scheme';
398  } catch (‪MissingArrayPathException) {
399  $legacyProxyAuthScheme = '';
400  }
401 
402  if ($legacyProxyHost !== '') {
403  $proxy = 'http://';
404  if ($legacyProxyAuthScheme !== '' && $legacyProxyUser !== '' && $legacyProxyPassword !== '') {
405  $proxy .= $legacyProxyUser . ':' . $legacyProxyPassword . '@';
406  }
407  $proxy .= $legacyProxyHost;
408  if ($legacyProxyPort !== '') {
409  $proxy .= ':' . $legacyProxyPort;
410  }
411  $newParameters['HTTP/proxy'] = $proxy;
412  }
413 
414  // Verify peers
415  // see http://docs.guzzlephp.org/en/latest/request-options.html#verify
416  try {
417  $legacySslVerifyPeer = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_verify_peer');
418  $obsoleteParameters[] = 'HTTP/ssl_verify_peer';
419  } catch (‪MissingArrayPathException) {
420  $legacySslVerifyPeer = '';
421  }
422 
423  // Directory holding multiple Certificate Authority files
424  try {
425  $legacySslCaPath = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_capath');
426  $obsoleteParameters[] = 'HTTP/ssl_capath';
427  } catch (‪MissingArrayPathException) {
428  $legacySslCaPath = '';
429  }
430  // Certificate Authority file to verify the peer with (use when ssl_verify_peer is TRUE)
431  try {
432  $legacySslCaFile = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_cafile');
433  $obsoleteParameters[] = 'HTTP/ssl_cafile';
434  } catch (‪MissingArrayPathException) {
435  $legacySslCaFile = '';
436  }
437  if ($legacySslVerifyPeer !== '') {
438  if ($legacySslCaFile !== '' && $legacySslCaPath !== '') {
439  $newParameters['HTTP/verify'] = $legacySslCaPath . $legacySslCaFile;
440  } elseif ((bool)$legacySslVerifyPeer === false) {
441  $newParameters['HTTP/verify'] = false;
442  }
443  }
444 
445  // SSL Key + Passphrase
446  // Name of a file containing local certificate
447  try {
448  $legacySslLocalCert = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_local_cert');
449  $obsoleteParameters[] = 'HTTP/ssl_local_cert';
450  } catch (‪MissingArrayPathException) {
451  $legacySslLocalCert = '';
452  }
453 
454  // Passphrase with which local certificate was encoded
455  try {
456  $legacySslPassphrase = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/ssl_passphrase');
457  $obsoleteParameters[] = 'HTTP/ssl_passphrase';
458  } catch (‪MissingArrayPathException) {
459  $legacySslPassphrase = '';
460  }
461 
462  if ($legacySslLocalCert !== '') {
463  if ($legacySslPassphrase !== '') {
464  $newParameters['HTTP/ssl_key'] = [
465  $legacySslLocalCert,
466  $legacySslPassphrase,
467  ];
468  } else {
469  $newParameters['HTTP/ssl_key'] = $legacySslLocalCert;
470  }
471  }
472 
473  // Update the LocalConfiguration file if obsolete parameters or new parameters are set
474  if (!empty($obsoleteParameters)) {
475  $this->configurationManager->removeLocalConfigurationKeysByPath($obsoleteParameters);
476  $changed = true;
477  }
478  if (!empty($newParameters)) {
479  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($newParameters);
480  $changed = true;
481  }
482  if ($changed) {
484  }
485  }
486 
498  {
499  $changedValues = [];
500  try {
501  $currentEnabledValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_enabled');
502  } catch (‪MissingArrayPathException) {
503  $currentEnabledValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_enabled');
504  }
505 
506  try {
507  $currentPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_path');
508  } catch (‪MissingArrayPathException) {
509  $currentPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_path');
510  }
511 
512  try {
513  $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
514  } catch (‪MissingArrayPathException) {
515  $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
516  }
517 
518  try {
519  $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
520  } catch (‪MissingArrayPathException) {
521  $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
522  }
523 
524  if (!$currentEnabledValue) {
525  if ($currentPathValue != '') {
526  $changedValues['GFX/processor_path'] = '';
527  }
528  if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
529  $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
530  }
531  if ($currentThumbnailsValue != 0) {
532  $changedValues['GFX/thumbnails'] = 0;
533  }
534  }
535  if (!empty($changedValues)) {
536  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
538  }
539  }
540 
551  protected function ‪setImageMagickDetailSettings(): void
552  {
553  $changedValues = [];
554  try {
555  $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor');
556  } catch (‪MissingArrayPathException) {
557  $currentProcessorValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor');
558  }
559 
560  try {
561  $currentProcessorEffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/processor_effects');
562  } catch (‪MissingArrayPathException) {
563  $currentProcessorEffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/processor_effects');
564  }
565 
566  if ((string)$currentProcessorValue !== '') {
567  if (!is_bool($currentProcessorEffectsValue)) {
568  $changedValues['GFX/processor_effects'] = (int)$currentProcessorEffectsValue > 0;
569  }
570  }
571  if (!empty($changedValues)) {
572  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
574  }
575  }
576 
583  protected function ‪migrateImageProcessorSetting(): void
584  {
585  $changedSettings = [];
586  $settingsToRename = [
587  'GFX/im' => 'GFX/processor_enabled',
588  'GFX/im_version_5' => 'GFX/processor',
589  'GFX/im_v5effects' => 'GFX/processor_effects',
590  'GFX/im_path' => 'GFX/processor_path',
591  'GFX/im_path_lzw' => 'GFX/processor_path_lzw',
592  'GFX/im_mask_temp_ext_gif' => 'GFX/processor_allowTemporaryMasksAsPng',
593  'GFX/im_noScaleUp' => 'GFX/processor_allowUpscaling',
594  'GFX/im_noFramePrepended' => 'GFX/processor_allowFrameSelection',
595  'GFX/im_stripProfileCommand' => 'GFX/processor_stripColorProfileCommand',
596  'GFX/im_useStripProfileByDefault' => 'GFX/processor_stripColorProfileByDefault',
597  'GFX/colorspace' => 'GFX/processor_colorspace',
598  ];
599 
600  foreach ($settingsToRename as $oldPath => $newPath) {
601  try {
602  $value = $this->configurationManager->getLocalConfigurationValueByPath($oldPath);
603  $this->configurationManager->setLocalConfigurationValueByPath($newPath, $value);
604  $changedSettings[$oldPath] = true;
605  } catch (‪MissingArrayPathException) {
606  // If an exception is thrown, the value is not set in LocalConfiguration
607  $changedSettings[$oldPath] = false;
608  }
609  }
610 
611  if (!empty($changedSettings['GFX/im_version_5'])) {
612  $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
613  $newProcessorValue = $currentProcessorValue === 'gm' ? 'GraphicsMagick' : 'ImageMagick';
614  $this->configurationManager->setLocalConfigurationValueByPath('GFX/processor', $newProcessorValue);
615  }
616 
617  if (!empty($changedSettings['GFX/im_noScaleUp'])) {
618  $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noScaleUp');
619  $newProcessorValue = !$currentProcessorValue;
620  $this->configurationManager->setLocalConfigurationValueByPath(
621  'GFX/processor_allowUpscaling',
622  $newProcessorValue
623  );
624  }
625 
626  if (!empty($changedSettings['GFX/im_noFramePrepended'])) {
627  $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_noFramePrepended');
628  $newProcessorValue = !$currentProcessorValue;
629  $this->configurationManager->setLocalConfigurationValueByPath(
630  'GFX/processor_allowFrameSelection',
631  $newProcessorValue
632  );
633  }
634 
635  if (!empty($changedSettings['GFX/im_mask_temp_ext_gif'])) {
636  $currentProcessorValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
637  $newProcessorValue = !$currentProcessorValue;
638  $this->configurationManager->setLocalConfigurationValueByPath(
639  'GFX/processor_allowTemporaryMasksAsPng',
640  $newProcessorValue
641  );
642  }
643 
644  if (!empty(array_filter($changedSettings))) {
645  $this->configurationManager->removeLocalConfigurationKeysByPath(array_keys($changedSettings));
647  }
648  }
649 
655  protected function ‪migrateLockSslSetting(): void
656  {
657  try {
658  $currentOption = $this->configurationManager->getLocalConfigurationValueByPath('BE/lockSSL');
659  // check if the current option is an integer/string and if it is active
660  if (!is_bool($currentOption) && (int)$currentOption > 0) {
661  $this->configurationManager->setLocalConfigurationValueByPath('BE/lockSSL', true);
663  }
664  } catch (‪MissingArrayPathException) {
665  // no change inside the system/settings.php found, so nothing needs to be modified
666  }
667  }
668 
674  protected function ‪migrateDatabaseConnectionSettings(): void
675  {
676  $confManager = $this->configurationManager;
677 
678  $newSettings = [];
679  $removeSettings = [];
680 
681  try {
682  $value = $confManager->getLocalConfigurationValueByPath('DB/username');
683  $removeSettings[] = 'DB/username';
684  $newSettings['DB/Connections/Default/user'] = $value;
685  } catch (‪MissingArrayPathException) {
686  // Old setting does not exist, do nothing
687  }
688 
689  try {
690  $value = $confManager->getLocalConfigurationValueByPath('DB/password');
691  $removeSettings[] = 'DB/password';
692  $newSettings['DB/Connections/Default/password'] = $value;
693  } catch (‪MissingArrayPathException) {
694  // Old setting does not exist, do nothing
695  }
696 
697  try {
698  $value = $confManager->getLocalConfigurationValueByPath('DB/host');
699  $removeSettings[] = 'DB/host';
700  $newSettings['DB/Connections/Default/host'] = $value;
701  } catch (‪MissingArrayPathException) {
702  // Old setting does not exist, do nothing
703  }
704 
705  try {
706  $value = $confManager->getLocalConfigurationValueByPath('DB/port');
707  $removeSettings[] = 'DB/port';
708  $newSettings['DB/Connections/Default/port'] = $value;
709  } catch (‪MissingArrayPathException) {
710  // Old setting does not exist, do nothing
711  }
712 
713  try {
714  $value = $confManager->getLocalConfigurationValueByPath('DB/socket');
715  $removeSettings[] = 'DB/socket';
716  // Remove empty socket connects
717  if (!empty($value)) {
718  $newSettings['DB/Connections/Default/unix_socket'] = $value;
719  }
720  } catch (‪MissingArrayPathException) {
721  // Old setting does not exist, do nothing
722  }
723 
724  try {
725  $value = $confManager->getLocalConfigurationValueByPath('DB/database');
726  $removeSettings[] = 'DB/database';
727  $newSettings['DB/Connections/Default/dbname'] = $value;
728  } catch (‪MissingArrayPathException) {
729  // Old setting does not exist, do nothing
730  }
731 
732  try {
733  $value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/dbClientCompress');
734  $removeSettings[] = 'SYS/dbClientCompress';
735  if ($value) {
736  $newSettings['DB/Connections/Default/driverOptions'] = [
737  'flags' => MYSQLI_CLIENT_COMPRESS,
738  ];
739  }
740  } catch (‪MissingArrayPathException) {
741  // Old setting does not exist, do nothing
742  }
743 
744  try {
745  $value = (bool)$confManager->getLocalConfigurationValueByPath('SYS/no_pconnect');
746  $removeSettings[] = 'SYS/no_pconnect';
747  if (!$value) {
748  $newSettings['DB/Connections/Default/persistentConnection'] = true;
749  }
750  } catch (‪MissingArrayPathException) {
751  // Old setting does not exist, do nothing
752  }
753 
754  try {
755  $value = $confManager->getLocalConfigurationValueByPath('SYS/setDBinit');
756  $removeSettings[] = 'SYS/setDBinit';
757  $newSettings['DB/Connections/Default/initCommands'] = $value;
758  } catch (‪MissingArrayPathException) {
759  // Old setting does not exist, do nothing
760  }
761 
762  try {
763  $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
764  } catch (‪MissingArrayPathException) {
765  // If there is no charset option yet, add it.
766  $newSettings['DB/Connections/Default/charset'] = 'utf8';
767  }
768 
769  try {
770  $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
771  } catch (‪MissingArrayPathException) {
772  // Use the mysqli driver by default if no value has been provided yet
773  $newSettings['DB/Connections/Default/driver'] = 'mysqli';
774  }
775 
776  // Add new settings and remove old ones
777  if (!empty($newSettings)) {
778  $confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
779  }
780  if (!empty($removeSettings)) {
781  $confManager->removeLocalConfigurationKeysByPath($removeSettings);
782  }
783 
784  // Throw redirect if something was changed
785  if (!empty($newSettings) || !empty($removeSettings)) {
787  }
788  }
789 
796  protected function ‪migrateDatabaseConnectionCharset(): void
797  {
798  $confManager = $this->configurationManager;
799  try {
800  $driver = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driver');
801  $charset = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/charset');
802  if (in_array($driver, ['mysqli', 'pdo_mysql', 'drizzle_pdo_mysql'], true) && $charset === 'utf-8') {
803  $confManager->setLocalConfigurationValueByPath('DB/Connections/Default/charset', 'utf8');
805  }
806  } catch (‪MissingArrayPathException) {
807  // no incompatible charset configuration found, so nothing needs to be modified
808  }
809  }
810 
816  protected function ‪migrateDatabaseDriverOptions(): void
817  {
818  $confManager = $this->configurationManager;
819  try {
820  $options = $confManager->getLocalConfigurationValueByPath('DB/Connections/Default/driverOptions');
821  if (!is_array($options)) {
822  $confManager->setLocalConfigurationValueByPath(
823  'DB/Connections/Default/driverOptions',
824  ['flags' => (int)$options]
825  );
827  }
828  } catch (‪MissingArrayPathException) {
829  // no driver options found, nothing needs to be modified
830  }
831  }
832 
838  protected function ‪migrateCacheHashOptions(): void
839  {
840  $confManager = $this->configurationManager;
841  $removeSettings = [];
842  $newSettings = [];
843 
844  try {
845  $value = $confManager->getLocalConfigurationValueByPath('FE/cHashOnlyForParameters');
846  $removeSettings[] = 'FE/cHashOnlyForParameters';
847  $newSettings['FE/cacheHash/cachedParametersWhiteList'] = ‪GeneralUtility::trimExplode(',', $value, true);
848  } catch (‪MissingArrayPathException) {
849  // Migration done already
850  }
851 
852  try {
853  $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParameters');
854  $removeSettings[] = 'FE/cHashExcludedParameters';
855  $newSettings['FE/cacheHash/excludedParameters'] = ‪GeneralUtility::trimExplode(',', $value, true);
856  } catch (‪MissingArrayPathException) {
857  // Migration done already
858  }
859 
860  try {
861  $value = $confManager->getLocalConfigurationValueByPath('FE/cHashRequiredParameters');
862  $removeSettings[] = 'FE/cHashRequiredParameters';
863  $newSettings['FE/cacheHash/requireCacheHashPresenceParameters'] = ‪GeneralUtility::trimExplode(',', $value, true);
864  } catch (‪MissingArrayPathException) {
865  // Migration done already
866  }
867 
868  try {
869  $value = $confManager->getLocalConfigurationValueByPath('FE/cHashExcludedParametersIfEmpty');
870  $removeSettings[] = 'FE/cHashExcludedParametersIfEmpty';
871  if (trim($value) === '*') {
872  $newSettings['FE/cacheHash/excludeAllEmptyParameters'] = true;
873  } else {
874  $newSettings['FE/cacheHash/excludedParametersIfEmpty'] = ‪GeneralUtility::trimExplode(',', $value, true);
875  }
876  } catch (‪MissingArrayPathException) {
877  // Migration done already
878  }
879 
880  // Add new settings and remove old ones
881  if (!empty($newSettings)) {
882  $confManager->setLocalConfigurationValuesByPathValuePairs($newSettings);
883  }
884  if (!empty($removeSettings)) {
885  $confManager->removeLocalConfigurationKeysByPath($removeSettings);
886  }
887 
888  // Throw redirect if something was changed
889  if (!empty($newSettings) || !empty($removeSettings)) {
891  }
892  }
893 
899  protected function ‪migrateExceptionErrors(): void
900  {
901  $confManager = $this->configurationManager;
902  try {
903  $currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/exceptionalErrors');
904  // make sure E_USER_DEPRECATED is not part of the exceptionalErrors
905  if ($currentOption & E_USER_DEPRECATED) {
906  $confManager->setLocalConfigurationValueByPath('SYS/exceptionalErrors', $currentOption & ~E_USER_DEPRECATED);
908  }
909  } catch (‪MissingArrayPathException) {
910  // no change inside the system/settings.php found, so nothing needs to be modified
911  }
912  }
913 
919  protected function ‪migrateDisplayErrorsSetting(): void
920  {
921  $confManager = $this->configurationManager;
922  try {
923  $currentOption = (int)$confManager->getLocalConfigurationValueByPath('SYS/displayErrors');
924  // make sure displayErrors is set to 2
925  if ($currentOption === 2) {
926  $confManager->setLocalConfigurationValueByPath('SYS/displayErrors', -1);
928  }
929  } catch (‪MissingArrayPathException) {
930  // no change inside the system/settings.php found, so nothing needs to be modified
931  }
932  }
933 
939  protected function ‪migrateSaltedPasswordsSettings(): void
940  {
941  $confManager = $this->configurationManager;
942  $configsToRemove = [];
943  try {
944  $extensionConfiguration = (array)$confManager->getLocalConfigurationValueByPath('EXTENSIONS/saltedpasswords');
945  $configsToRemove[] = 'EXTENSIONS/saltedpasswords';
946  } catch (‪MissingArrayPathException) {
947  $extensionConfiguration = [];
948  }
949  // Migration already done
950  if (empty($extensionConfiguration)) {
951  return;
952  }
953  // Upgrade to the best available hash method. This is only done once since that code will no longer be reached
954  // after first migration because extConf and EXTENSIONS array entries are gone then. Thus, a manual selection
955  // to some different hash mechanism will not be touched again after first upgrade.
956  // Phpass is always available, so we have some last fallback if the others don't kick in
957  $okHashMethods = [
958  Argon2iPasswordHash::class,
959  Argon2idPasswordHash::class,
960  BcryptPasswordHash::class,
961  Pbkdf2PasswordHash::class,
962  PhpassPasswordHash::class,
963  ];
964  $newMethods = [];
965  foreach (['BE', 'FE'] as $mode) {
966  foreach ($okHashMethods as $className) {
968  $instance = GeneralUtility::makeInstance($className);
969  if ($instance->isAvailable()) {
970  $newMethods[$mode] = $className;
971  break;
972  }
973  }
974  }
975  // We only need to write to LocalConfiguration if method is different from Argon2i in DefaultConfiguration
976  $newConfig = [];
977  if ($newMethods['BE'] !== Argon2iPasswordHash::class) {
978  $newConfig['BE/passwordHashing/className'] = $newMethods['BE'];
979  }
980  if ($newMethods['FE'] !== Argon2iPasswordHash::class) {
981  $newConfig['FE/passwordHashing/className'] = $newMethods['FE'];
982  }
983  if (!empty($newConfig)) {
984  $confManager->setLocalConfigurationValuesByPathValuePairs($newConfig);
985  }
986  $confManager->removeLocalConfigurationKeysByPath($configsToRemove);
988  }
989 
996  protected function ‪migrateCachingFrameworkCaches(): void
997  {
998  $confManager = $this->configurationManager;
999  try {
1000  $cacheConfigurations = (array)$confManager->getLocalConfigurationValueByPath('SYS/caching/cacheConfigurations');
1001  $newConfig = [];
1002  $hasBeenModified = false;
1003  foreach ($cacheConfigurations as ‪$identifier => $cacheConfiguration) {
1004  if (str_starts_with(‪$identifier, 'cache_')) {
1005  ‪$identifier = substr(‪$identifier, 6);
1006  $hasBeenModified = true;
1007  }
1008  $newConfig[‪$identifier] = $cacheConfiguration;
1009  }
1010 
1011  if ($hasBeenModified) {
1012  $confManager->setLocalConfigurationValueByPath('SYS/caching/cacheConfigurations', $newConfig);
1014  }
1015  } catch (‪MissingArrayPathException) {
1016  // no change inside the system/settings.php found, so nothing needs to be modified
1017  }
1018  }
1019 
1027  protected function ‪migrateMailSettingsToSendmail(): void
1028  {
1029  $confManager = $this->configurationManager;
1030  try {
1031  $transport = $confManager->getLocalConfigurationValueByPath('MAIL/transport');
1032  if ($transport === 'mail') {
1033  $confManager->setLocalConfigurationValueByPath('MAIL/transport', 'sendmail');
1034  $confManager->setLocalConfigurationValueByPath('MAIL/transport_sendmail_command', (string)@ini_get('sendmail_path'));
1036  }
1037  } catch (‪MissingArrayPathException) {
1038  // no change inside the system/settings.php found, so nothing needs to be modified
1039  }
1040  }
1041 
1048  protected function ‪migrateMailSmtpEncryptSetting(): void
1049  {
1050  $confManager = $this->configurationManager;
1051  try {
1052  $transport = $confManager->getLocalConfigurationValueByPath('MAIL/transport');
1053  if ($transport === 'smtp') {
1054  $encrypt = $confManager->getLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt');
1055  if (is_string($encrypt)) {
1056  // SwiftMailer used 'tls' as identifier to connect with STARTTLS via SMTP (as usually used with port 587).
1057  // See https://github.com/swiftmailer/swiftmailer/blob/v5.4.10/lib/classes/Swift/Transport/EsmtpTransport.php#L144
1058  if ($encrypt === 'tls') {
1059  // With TYPO3 v10 the MAIL/transport_smtp_encrypt option is passed as constructor parameter $tls to
1060  // Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport
1061  // $tls = true instructs to start a SMTPS connection – that means SSL/TLS via SMTPS, not STARTTLS via SMTP.
1062  // That means symfony/mailer will use STARTTLS when $tls = false or ($tls = null with port != 465) is passed.
1063  // Actually symfony/mailer will use STARTTLS by default now.
1064  // Due to the misleading name (transport_smtp_encrypt) we avoid to set the option to false, but rather remove it.
1065  // Note: symfony/mailer provides no way to enforce STARTTLS usage, see https://github.com/symfony/symfony/commit/5b8c4676d059
1066  $confManager->removeLocalConfigurationKeysByPath(['MAIL/transport_smtp_encrypt']);
1067  } elseif ($encrypt === '') {
1068  $confManager->setLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt', false);
1069  } else {
1070  $confManager->setLocalConfigurationValueByPath('MAIL/transport_smtp_encrypt', true);
1071  }
1073  }
1074  }
1075  } catch (‪MissingArrayPathException) {
1076  // no change inside the system/settings.php found, so nothing needs to be modified
1077  }
1078  }
1079 
1085  protected function ‪migrateVersionNumberInFileNameSetting(): void
1086  {
1087  try {
1088  $confManager = $this->configurationManager;
1089  $currentOption = $confManager->getLocalConfigurationValueByPath('FE/versionNumberInFilename');
1090  if ($currentOption === true) {
1091  return;
1092  }
1093  if ($currentOption === 'embed') {
1094  $confManager->setLocalConfigurationValueByPath('FE/versionNumberInFilename', true);
1095  } else {
1096  $confManager->removeLocalConfigurationKeysByPath(['FE/versionNumberInFilename']);
1097  }
1099  } catch (‪MissingArrayPathException) {
1100  // no flag set, so nothing to be configured
1101  }
1102  }
1103 
1109  protected function ‪removeDefaultColorspaceSettings(): void
1110  {
1111  try {
1112  $confManager = $this->configurationManager;
1113  $currentProcessor = $confManager->getLocalConfigurationValueByPath('GFX/processor');
1114  $currentColorspace = $confManager->getLocalConfigurationValueByPath('GFX/processor_colorspace');
1115 
1116  if ($currentProcessor === 'ImageMagick' && $currentColorspace === 'sRGB' ||
1117  $currentProcessor === 'GraphicsMagick' && $currentColorspace === 'RGB') {
1118  $confManager->removeLocalConfigurationKeysByPath(['GFX/processor_colorspace']);
1120  }
1121  } catch (‪MissingArrayPathException) {
1122  // no change inside the system/settings.php found, so nothing needs to be modified
1123  }
1124  }
1125 }
‪TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash
Definition: BcryptPasswordHash.php:32
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateLockSslSetting
‪migrateLockSslSetting()
Definition: SilentConfigurationUpgradeService.php:655
‪TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException
Definition: ConfigurationChangedException.php:25
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService
Definition: SilentConfigurationUpgradeService.php:45
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateMailSettingsToSendmail
‪migrateMailSettingsToSendmail()
Definition: SilentConfigurationUpgradeService.php:1027
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Core\Configuration\Exception\SettingsWriteException
Definition: SettingsWriteException.php:25
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\disableImageMagickDetailSettingsIfImageMagickIsDisabled
‪disableImageMagickDetailSettingsIfImageMagickIsDisabled()
Definition: SilentConfigurationUpgradeService.php:497
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateExceptionErrors
‪migrateExceptionErrors()
Definition: SilentConfigurationUpgradeService.php:899
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\generateEncryptionKeyIfNeeded
‪generateEncryptionKeyIfNeeded()
Definition: SilentConfigurationUpgradeService.php:276
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\throwConfigurationChangedException
‪throwConfigurationChangedException()
Definition: SilentConfigurationUpgradeService.php:242
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateDatabaseConnectionCharset
‪migrateDatabaseConnectionCharset()
Definition: SilentConfigurationUpgradeService.php:796
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\$obsoleteLocalConfigurationSettings
‪array $obsoleteLocalConfigurationSettings
Definition: SilentConfigurationUpgradeService.php:52
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateImageProcessorSetting
‪migrateImageProcessorSetting()
Definition: SilentConfigurationUpgradeService.php:583
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\execute
‪execute()
Definition: SilentConfigurationUpgradeService.php:212
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateDatabaseConnectionSettings
‪migrateDatabaseConnectionSettings()
Definition: SilentConfigurationUpgradeService.php:674
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateCacheHashOptions
‪migrateCacheHashOptions()
Definition: SilentConfigurationUpgradeService.php:838
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Pbkdf2PasswordHash
Definition: Pbkdf2PasswordHash.php:28
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateSaltedPasswordsSettings
‪migrateSaltedPasswordsSettings()
Definition: SilentConfigurationUpgradeService.php:939
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\transferHttpSettings
‪transferHttpSettings()
Definition: SilentConfigurationUpgradeService.php:297
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateCachingFrameworkCaches
‪migrateCachingFrameworkCaches()
Definition: SilentConfigurationUpgradeService.php:996
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash
Definition: PhpassPasswordHash.php:35
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\setImageMagickDetailSettings
‪setImageMagickDetailSettings()
Definition: SilentConfigurationUpgradeService.php:551
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\__construct
‪__construct(private readonly ConfigurationManager $configurationManager)
Definition: SilentConfigurationUpgradeService.php:203
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateVersionNumberInFileNameSetting
‪migrateVersionNumberInFileNameSetting()
Definition: SilentConfigurationUpgradeService.php:1085
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateDatabaseDriverOptions
‪migrateDatabaseDriverOptions()
Definition: SilentConfigurationUpgradeService.php:816
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\removeDefaultColorspaceSettings
‪removeDefaultColorspaceSettings()
Definition: SilentConfigurationUpgradeService.php:1109
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:27
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateDisplayErrorsSetting
‪migrateDisplayErrorsSetting()
Definition: SilentConfigurationUpgradeService.php:919
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\removeObsoleteLocalConfigurationSettings
‪removeObsoleteLocalConfigurationSettings()
Definition: SilentConfigurationUpgradeService.php:258
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface
Definition: PasswordHashInterface.php:25
‪TYPO3\CMS\Install\Service
Definition: ClearCacheService.php:16
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash
Definition: Argon2idPasswordHash.php:31
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash
Definition: Argon2iPasswordHash.php:31
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService\migrateMailSmtpEncryptSetting
‪migrateMailSmtpEncryptSetting()
Definition: SilentConfigurationUpgradeService.php:1048
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37