[!!!][TASK] Drop ContentAdapter
[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\Utility\ExtensionManagementUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Install\Controller\Exception\RedirectException;
20
21 /**
22 * Execute "silent" LocalConfiguration upgrades if needed.
23 *
24 * Some LocalConfiguration settings are obsolete or changed over time.
25 * This class handles upgrades of these settings. It is called by
26 * the step controller at an early point.
27 *
28 * Every change is encapsulated in one method an must throw a RedirectException
29 * if new data is written to LocalConfiguration. This is caught by above
30 * step controller to initiate a redirect and start again with adapted configuration.
31 */
32 class SilentConfigurationUpgradeService {
33
34 /**
35 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
36 * @inject
37 */
38 protected $objectManager = NULL;
39
40 /**
41 * @var \TYPO3\CMS\Core\Configuration\ConfigurationManager
42 * @inject
43 */
44 protected $configurationManager = NULL;
45
46 /**
47 * List of obsolete configuration options in LocalConfiguration to be removed
48 * Example:
49 * // #forge-ticket
50 * 'BE/somesetting',
51 *
52 * @var array
53 */
54 protected $obsoleteLocalConfigurationSettings = array(
55 // #62402
56 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\ExtensionManagerTables',
57 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FileIdentifierHashUpdate',
58 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FilemountUpdateWizard',
59 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FilePermissionUpdate',
60 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\FileTableSplittingUpdate',
61 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\InitUpdateWizard',
62 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\MediaFlexformUpdate',
63 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\ReferenceIntegrityUpdateWizard',
64 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\RteFileLinksUpdateWizard',
65 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\RteMagicImagesUpdateWizard',
66 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\TceformsUpdateWizard',
67 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\TtContentUploadsUpdateWizard',
68 'INSTALL/wizardDone/TYPO3\\CMS\\Install\\Updates\\TruncateSysFileProcessedFileTable',
69 // #63818
70 'BE/staticFileEditPath',
71 // #64226
72 'BE/accessListRenderMode',
73 // #24900
74 'SYS/compat_version',
75 // #64643
76 'GFX/enable_typo3temp_db_tracking',
77 // #48542
78 'GFX/TTFdpi',
79 // #64872
80 'SYS/useCachingFramework',
81 // #65912
82 'FE/allowedTempPaths',
83 // #66034
84 'FE/activateContentAdapter',
85 );
86
87 /**
88 * Executed configuration upgrades. Single upgrade methods must throw a
89 * RedirectException if something was written to LocalConfiguration.
90 *
91 * @return void
92 */
93 public function execute() {
94 $this->generateEncryptionKeyIfNeeded();
95 $this->configureBackendLoginSecurity();
96 $this->configureSaltedPasswords();
97 $this->setProxyAuthScheme();
98 $this->disableImageMagickAndGdlibIfImageProcessingIsDisabled();
99 $this->disableImageMagickDetailSettingsIfImageMagickIsDisabled();
100 $this->setImageMagickDetailSettings();
101 $this->removeObsoleteLocalConfigurationSettings();
102 }
103
104 /**
105 * Some settings in LocalConfiguration vanished in DefaultConfiguration
106 * and have no impact on the core anymore.
107 * To keep the configuration clean, those old settings are just silently
108 * removed from LocalConfiguration if set.
109 *
110 * @return void
111 */
112 protected function removeObsoleteLocalConfigurationSettings() {
113 $removed = $this->configurationManager->removeLocalConfigurationKeysByPath($this->obsoleteLocalConfigurationSettings);
114
115 // If something was changed: Trigger a reload to have new values in next request
116 if ($removed) {
117 $this->throwRedirectException();
118 }
119 }
120
121 /**
122 * Backend login security is set to rsa if rsaauth
123 * is installed (but not used) otherwise the default value "normal" has to be used.
124 * This forces either 'normal' or 'rsa' to be set in LocalConfiguration.
125 *
126 * @return void
127 */
128 protected function configureBackendLoginSecurity() {
129 try {
130 $currentLoginSecurityLevelValue = $this->configurationManager->getLocalConfigurationValueByPath('BE/loginSecurityLevel');
131 if (ExtensionManagementUtility::isLoaded('rsaauth')
132 && $currentLoginSecurityLevelValue !== 'rsa'
133 ) {
134 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
135 $this->throwRedirectException();
136 } elseif (!ExtensionManagementUtility::isLoaded('rsaauth')
137 && $currentLoginSecurityLevelValue !== 'normal'
138 ) {
139 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
140 $this->throwRedirectException();
141 }
142 } catch (\RuntimeException $e) {
143 // If an exception is thrown, the value is not set in LocalConfiguration
144 if (ExtensionManagementUtility::isLoaded('rsaauth')) {
145 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'rsa');
146 $this->throwRedirectException();
147 } elseif (!ExtensionManagementUtility::isLoaded('rsaauth')) {
148 $this->configurationManager->setLocalConfigurationValueByPath('BE/loginSecurityLevel', 'normal');
149 $this->throwRedirectException();
150 }
151 }
152 }
153
154 /**
155 * Check the settings for salted passwords extension to load it as a required extension.
156 * Unset obsolete configuration options if given.
157 *
158 * @return void
159 */
160 protected function configureSaltedPasswords() {
161 $defaultConfiguration = $this->configurationManager->getDefaultConfiguration();
162 $defaultExtensionConfiguration = unserialize($defaultConfiguration['EXT']['extConf']['saltedpasswords']);
163 try {
164 $extensionConfiguration = @unserialize($this->configurationManager->getLocalConfigurationValueByPath('EXT/extConf/saltedpasswords'));
165 } catch (\RuntimeException $e) {
166 $extensionConfiguration = array();
167 }
168 if (is_array($extensionConfiguration) && !empty($extensionConfiguration)) {
169 if (isset($extensionConfiguration['BE.']['enabled'])) {
170 if ($extensionConfiguration['BE.']['enabled']) {
171 unset($extensionConfiguration['BE.']['enabled']);
172 } else {
173 $extensionConfiguration['BE.'] = $defaultExtensionConfiguration['BE.'];
174 }
175 $this->configurationManager->setLocalConfigurationValueByPath(
176 'EXT/extConf/saltedpasswords',
177 serialize($extensionConfiguration)
178 );
179 $this->throwRedirectException();
180 }
181 } else {
182 $this->configurationManager->setLocalConfigurationValueByPath(
183 'EXT/extConf/saltedpasswords',
184 serialize($defaultExtensionConfiguration)
185 );
186 $this->throwRedirectException();
187 }
188 }
189
190 /**
191 * The encryption key is crucial for securing form tokens
192 * and the whole TYPO3 link rendering later on. A random key is set here in
193 * LocalConfiguration if it does not exist yet. This might possible happen
194 * during upgrading and will happen during first install.
195 *
196 * @return void
197 */
198 protected function generateEncryptionKeyIfNeeded() {
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::getRandomHexString(96);
208 $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
209 $this->throwRedirectException();
210 }
211 }
212
213 /**
214 * $GLOBALS['TYPO3_CONF_VARS']['HTTP']['proxy_auth_scheme'] must be either
215 * 'digest' or 'basic'. 'basic' is default in DefaultConfiguration, so the
216 * setting can be removed from LocalConfiguration if it is not set to 'digest'.
217 *
218 * @return void
219 */
220 protected function setProxyAuthScheme() {
221 // Get current value from LocalConfiguration
222 try {
223 $currentValueInLocalConfiguration = $this->configurationManager->getLocalConfigurationValueByPath('HTTP/proxy_auth_scheme');
224 } catch (\RuntimeException $e) {
225 // If an exception is thrown, the value is not set in LocalConfiguration, so we don't need to do anything
226 return;
227 }
228 if ($currentValueInLocalConfiguration !== 'digest') {
229 $this->configurationManager->removeLocalConfigurationKeysByPath(array('HTTP/proxy_auth_scheme'));
230 $this->throwRedirectException();
231 }
232 }
233
234 /**
235 * GFX/im and GFX/gdlib must be set to 0 if image_processing is disabled.
236 *
237 * "Configuration presets" in install tool is not type safe, so value
238 * comparisons here are not type safe too, to not trigger changes to
239 * LocalConfiguration again.
240 *
241 * @return void
242 */
243 protected function disableImageMagickAndGdlibIfImageProcessingIsDisabled() {
244 $changedValues = array();
245 try {
246 $currentImageProcessingValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/image_processing');
247 } catch (\RuntimeException $e) {
248 $currentImageProcessingValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/image_processing');
249 }
250 try {
251 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
252 } catch (\RuntimeException $e) {
253 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
254 }
255 try {
256 $currentGdlibValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/gdlib');
257 } catch (\RuntimeException $e) {
258 $currentGdlibValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/gdlib');
259 }
260 // If image processing is fully disabled, im and gdlib sub settings must be 0
261 if (!$currentImageProcessingValue) {
262 if ($currentImValue != 0) {
263 $changedValues['GFX/im'] = 0;
264 }
265 if ($currentGdlibValue != 0) {
266 $changedValues['GFX/gdlib'] = 0;
267 }
268 }
269 if (count($changedValues) > 0) {
270 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
271 $this->throwRedirectException();
272 }
273 }
274
275 /**
276 * Detail configuration of Image Magick settings must be cleared
277 * if Image Magick handling is disabled.
278 *
279 * "Configuration presets" in install tool is not type safe, so value
280 * comparisons here are not type safe too, to not trigger changes to
281 * LocalConfiguration again.
282 *
283 * @return void
284 */
285 protected function disableImageMagickDetailSettingsIfImageMagickIsDisabled() {
286 $changedValues = array();
287 try {
288 $currentImValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im');
289 }
290 catch (\RuntimeException $e) {
291 $currentImValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im');
292 }
293 try {
294 $currentImPathValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path');
295 }
296 catch (\RuntimeException $e) {
297 $currentImPathValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path');
298 }
299 try {
300 $currentImPathLzwValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_path_lzw');
301 }
302 catch (\RuntimeException $e) {
303 $currentImPathLzwValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_path_lzw');
304 }
305 try {
306 $currentImageFileExtValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/imagefile_ext');
307 }
308 catch (\RuntimeException $e) {
309 $currentImageFileExtValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/imagefile_ext');
310 }
311 try {
312 $currentThumbnailsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/thumbnails');
313 }
314 catch (\RuntimeException $e) {
315 $currentThumbnailsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/thumbnails');
316 }
317 if (!$currentImValue) {
318 if ($currentImPathValue != '') {
319 $changedValues['GFX/im_path'] = '';
320 }
321 if ($currentImPathLzwValue != '') {
322 $changedValues['GFX/im_path_lzw'] = '';
323 }
324 if ($currentImageFileExtValue !== 'gif,jpg,jpeg,png') {
325 $changedValues['GFX/imagefile_ext'] = 'gif,jpg,jpeg,png';
326 }
327 if ($currentThumbnailsValue != 0) {
328 $changedValues['GFX/thumbnails'] = 0;
329 }
330 }
331 if (count($changedValues) > 0) {
332 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
333 $this->throwRedirectException();
334 }
335 }
336
337 /**
338 * Detail configuration of Image Magick and Graphics Magick settings
339 * depending on main values.
340 *
341 * "Configuration presets" in install tool is not type safe, so value
342 * comparisons here are not type safe too, to not trigger changes to
343 * LocalConfiguration again.
344 *
345 * @return void
346 */
347 protected function setImageMagickDetailSettings() {
348 $changedValues = array();
349 try {
350 $currentIm5Value = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_version_5');
351 }
352 catch (\RuntimeException $e) {
353 $currentIm5Value = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_version_5');
354 }
355 try {
356 $currentImMaskValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
357 }
358 catch (\RuntimeException $e) {
359 $currentImMaskValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_mask_temp_ext_gif');
360 }
361 try {
362 $currentIm5EffectsValue = $this->configurationManager->getLocalConfigurationValueByPath('GFX/im_v5effects');
363 }
364 catch (\RuntimeException $e) {
365 $currentIm5EffectsValue = $this->configurationManager->getDefaultConfigurationValueByPath('GFX/im_v5effects');
366 }
367 if ((string)$currentIm5Value !== '') {
368 if ($currentImMaskValue != 1) {
369 $changedValues['GFX/im_mask_temp_ext_gif'] = 1;
370 }
371 if ($currentIm5Value === 'gm') {
372 if ($currentIm5EffectsValue != -1) {
373 $changedValues['GFX/im_v5effects'] = -1;
374 }
375 }
376 }
377 if (count($changedValues) > 0) {
378 $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($changedValues);
379 $this->throwRedirectException();
380 }
381 }
382
383 /**
384 * Throw exception after configuration change to trigger a redirect.
385 *
386 * @throws RedirectException
387 */
388 protected function throwRedirectException() {
389 throw new RedirectException(
390 'Configuration updated, reload needed',
391 1379024938
392 );
393 }
394
395 }