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