769f9e5d7414627048d8b974a12ea3da440c8f5b
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Configuration / ConfigurationManager.php
1 <?php
2 namespace TYPO3\CMS\Core\Configuration;
3 use TYPO3\CMS\Core\Utility;
4
5 /***************************************************************
6 * Copyright notice
7 *
8 * (c) 2012-2013 Helge Funk <helge.funk@e-net.info>
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Handle loading and writing of global and local (instance specific)
29 * configuration.
30 *
31 * This class handles the access to the files
32 * - EXT:core/Configuration/DefaultConfiguration.php (default TYPO3_CONF_VARS)
33 * - typo3conf/LocalConfiguration.php (overrides of TYPO3_CONF_VARS)
34 * - typo3conf/AdditionalConfiguration.php (optional additional local code blocks)
35 * - typo3conf/localconf.php (legacy configuration file)
36 *
37 * @author Helge Funk <helge.funk@e-net.info>
38 */
39 class ConfigurationManager {
40
41 /**
42 * @var string Path to default TYPO3_CONF_VARS file, relative to PATH_site
43 */
44 protected $defaultConfigurationFile = 'typo3/sysext/core/Configuration/DefaultConfiguration.php';
45
46 /**
47 * @var string Path to local overload TYPO3_CONF_VARS file, relative to PATH_site
48 */
49 protected $localConfigurationFile = 'typo3conf/LocalConfiguration.php';
50
51 /**
52 * @var string Path to additional local file, relative to PATH_site
53 */
54 protected $additionalConfigurationFile = 'typo3conf/AdditionalConfiguration.php';
55
56 /**
57 * @var string Path to factory configuration file used during installation as LocalConfiguration boilerplate
58 */
59 protected $factoryConfigurationFile = 'typo3/sysext/core/Configuration/FactoryConfiguration.php';
60
61 /**
62 * @var string Path to possible additional factory configuration file delivered by packages
63 */
64 protected $additionalFactoryConfigurationFile = 'typo3conf/AdditionalFactoryConfiguration.php';
65
66 /**
67 * @var string Path to legacy localconf.php file, relative to PATH_site
68 */
69 protected $localconfFile = 'typo3conf/localconf.php';
70
71 /**
72 * @var string Absolute path to typo3conf directory
73 */
74 protected $pathTypo3Conf = PATH_typo3conf;
75
76 /**
77 * Writing to these configuration pathes is always allowed,
78 * even if the requested sub path does not exist yet.
79 *
80 * @var array
81 */
82 protected $whiteListedLocalConfigurationPaths = array(
83 'EXT/extConf',
84 'EXTCONF',
85 'INSTALL/wizardDone',
86 'DB'
87 );
88
89 /**
90 * Return default configuration array
91 *
92 * @return array
93 */
94 public function getDefaultConfiguration() {
95 return require $this->getDefaultConfigurationFileLocation();
96 }
97
98 /**
99 * Get the file location of the default configuration file,
100 * currently the path and filename.
101 *
102 * @return string
103 * @access private
104 */
105 public function getDefaultConfigurationFileLocation() {
106 return PATH_site . $this->defaultConfigurationFile;
107 }
108
109 /**
110 * Return local configuration array typo3conf/LocalConfiguration.php
111 *
112 * @return array Content array of local configuration file
113 */
114 public function getLocalConfiguration() {
115 return require $this->getLocalConfigurationFileLocation();
116 }
117
118 /**
119 * Get the file location of the local configuration file,
120 * currently the path and filename.
121 *
122 * @return string
123 * @access private
124 */
125 public function getLocalConfigurationFileLocation() {
126 return PATH_site . $this->localConfigurationFile;
127 }
128
129 /**
130 * Get the file location of the additional configuration file,
131 * currently the path and filename.
132 *
133 * @return string
134 * @access private
135 */
136 public function getAdditionalConfigurationFileLocation() {
137 return PATH_site . $this->additionalConfigurationFile;
138 }
139
140 /**
141 * Get absolute file location of factory configuration file
142 *
143 * @return string
144 */
145 protected function getFactoryConfigurationFileLocation() {
146 return PATH_site . $this->factoryConfigurationFile;
147 }
148
149 /**
150 * Get absolute file location of factory configuration file
151 *
152 * @return string
153 */
154 protected function getAdditionalFactoryConfigurationFileLocation() {
155 return PATH_site . $this->additionalFactoryConfigurationFile;
156 }
157
158 /**
159 * Get the file resource
160 *
161 * @return string
162 * @deprecated since 6.1, will be removed if the compatibily layer for localconf.php is dropped
163 */
164 public function getLocalconfFileLocation() {
165 return PATH_site . $this->localconfFile;
166 }
167
168 /**
169 * Override local configuration with new values.
170 *
171 * @param array $configurationToMerge Override configuration array
172 * @return void
173 */
174 public function updateLocalConfiguration(array $configurationToMerge) {
175 $newLocalConfiguration = Utility\GeneralUtility::array_merge_recursive_overrule(
176 $this->getLocalConfiguration(),
177 $configurationToMerge
178 );
179 $this->writeLocalConfiguration($newLocalConfiguration);
180 }
181
182 /**
183 * Get a value at given path from default configuration
184 *
185 * @param string $path Path to search for
186 * @return mixed Value at path
187 */
188 public function getDefaultConfigurationValueByPath($path) {
189 return Utility\ArrayUtility::getValueByPath($this->getDefaultConfiguration(), $path);
190 }
191
192 /**
193 * Get a value at given path from local configuration
194 *
195 * @param string $path Path to search for
196 * @return mixed Value at path
197 */
198 public function getLocalConfigurationValueByPath($path) {
199 return Utility\ArrayUtility::getValueByPath($this->getLocalConfiguration(), $path);
200 }
201
202 /**
203 * Get a value from configuration, this is default configuration
204 * merged with local configuration
205 *
206 * @param string $path Path to search for
207 * @return mixed
208 */
209 public function getConfigurationValueByPath($path) {
210 return Utility\ArrayUtility::getValueByPath(
211 Utility\GeneralUtility::array_merge_recursive_overrule(
212 $this->getDefaultConfiguration(), $this->getLocalConfiguration()
213 ),
214 $path
215 );
216 }
217
218 /**
219 * Update a given path in local configuration to a new value.
220 *
221 * @param string $path Path to update
222 * @param mixed $value Value to set
223 * @return boolean TRUE on success
224 */
225 public function setLocalConfigurationValueByPath($path, $value) {
226 $result = FALSE;
227 if ($this->isValidLocalConfigurationPath($path)) {
228 $localConfiguration = $this->getLocalConfiguration();
229 $localConfiguration = Utility\ArrayUtility::setValueByPath($localConfiguration, $path, $value);
230 $result = $this->writeLocalConfiguration($localConfiguration);
231 }
232 return $result;
233 }
234
235 /**
236 * Update / set a list of path and value pairs in local configuration file
237 *
238 * @param array $pairs Key is path, value is value to set
239 * @return boolean TRUE on success
240 */
241 public function setLocalConfigurationValuesByPathValuePairs(array $pairs) {
242 $localConfiguration = $this->getLocalConfiguration();
243 foreach ($pairs as $path => $value) {
244 if ($this->isValidLocalConfigurationPath($path)) {
245 $localConfiguration = Utility\ArrayUtility::setValueByPath($localConfiguration, $path, $value);
246 }
247 }
248 return $this->writeLocalConfiguration($localConfiguration);
249 }
250
251 /**
252 * Checks if the configuration can be written.
253 *
254 * @return boolean
255 * @access private
256 */
257 public function canWriteConfiguration() {
258 $result = TRUE;
259 if (!@is_writable($this->pathTypo3Conf)) {
260 $result = FALSE;
261 }
262 if (
263 file_exists($this->getLocalConfigurationFileLocation())
264 && !@is_writable($this->getLocalConfigurationFileLocation())
265 ) {
266 $result = FALSE;
267 }
268 if (
269 file_exists($this->getLocalconfFileLocation())
270 && !@is_writable($this->getLocalconfFileLocation())
271 ) {
272 $result = FALSE;
273 }
274 return $result;
275 }
276
277 /**
278 * Reads the configuration array and exports it to the global variable
279 *
280 * @access private
281 * @throws \RuntimeException
282 * @throws \UnexpectedValueException
283 * @return void
284 */
285 public function exportConfiguration() {
286 if (@is_file($this->getLocalConfigurationFileLocation())) {
287 $localConfiguration = $this->getLocalConfiguration();
288 if (is_array($localConfiguration)) {
289 $GLOBALS['TYPO3_CONF_VARS'] = Utility\GeneralUtility::array_merge_recursive_overrule($this->getDefaultConfiguration(), $localConfiguration);
290 } else {
291 throw new \UnexpectedValueException('LocalConfiguration invalid.', 1349272276);
292 }
293 if (@is_file($this->getAdditionalConfigurationFileLocation())) {
294 require $this->getAdditionalConfigurationFileLocation();
295 }
296 // @deprecated since 6.0: Simulate old 'extList' as comma separated list of 'extListArray'
297 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'] = implode(',', $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray']);
298 } elseif (@is_file($this->getLocalconfFileLocation())) {
299 $GLOBALS['TYPO3_CONF_VARS'] = $this->getDefaultConfiguration();
300 // Legacy localconf.php handling
301 // @deprecated: Can be removed if old localconf.php is not supported anymore
302 global $TYPO3_CONF_VARS, $typo_db, $typo_db_username, $typo_db_password, $typo_db_host, $typo_db_extTableDef_script;
303 require $this->getLocalconfFileLocation();
304 // If the localconf.php was not upgraded to LocalConfiguration.php, the default extListArray
305 // from EXT:core/Configuration/DefaultConfiguration.php is still set. In this case we just unset
306 // this key here, so \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getLoadedExtensionListArray() falls back to use extList string
307 // @deprecated: This case can be removed later if localconf.php is not supported anymore
308 unset($TYPO3_CONF_VARS['EXT']['extListArray']);
309 // Write the old globals into the new place in the configuration array
310 $GLOBALS['TYPO3_CONF_VARS']['DB'] = array();
311 $GLOBALS['TYPO3_CONF_VARS']['DB']['database'] = $typo_db;
312 $GLOBALS['TYPO3_CONF_VARS']['DB']['username'] = $typo_db_username;
313 $GLOBALS['TYPO3_CONF_VARS']['DB']['password'] = $typo_db_password;
314 $GLOBALS['TYPO3_CONF_VARS']['DB']['host'] = $typo_db_host;
315 $GLOBALS['TYPO3_CONF_VARS']['DB']['extTablesDefinitionScript'] = $typo_db_extTableDef_script;
316 unset($GLOBALS['typo_db']);
317 unset($GLOBALS['typo_db_username']);
318 unset($GLOBALS['typo_db_password']);
319 unset($GLOBALS['typo_db_host']);
320 unset($GLOBALS['typo_db_extTableDef_script']);
321 } else {
322 throw new \RuntimeException(
323 'Neither ' . $this->localConfigurationFile . ' (recommended) nor ' . $this->localconfFile . ' (obsolete) could be found!',
324 1349272337
325 );
326 }
327 }
328
329 /**
330 * Write local configuration array to typo3conf/LocalConfiguration.php
331 *
332 * @param array $configuration The local configuration to be written
333 * @throws \RuntimeException
334 * @return boolean TRUE on success
335 * @access private
336 */
337 public function writeLocalConfiguration(array $configuration) {
338 $localConfigurationFile = $this->getLocalConfigurationFileLocation();
339 if (!$this->canWriteConfiguration()) {
340 throw new \RuntimeException(
341 $localConfigurationFile . ' is not writable.', 1346323822
342 );
343 }
344 $configuration = Utility\ArrayUtility::sortByKeyRecursive($configuration);
345 $result = Utility\GeneralUtility::writeFile(
346 $localConfigurationFile,
347 '<?php' . LF .
348 'return ' .
349 Utility\ArrayUtility::arrayExport(
350 Utility\ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($configuration)
351 ) .
352 ';' . LF .
353 '?>',
354 TRUE
355 );
356 return $result === FALSE ? FALSE : TRUE;
357 }
358
359 /**
360 * Write additional configuration array to typo3conf/AdditionalConfiguration.php
361 *
362 * @param array $additionalConfigurationLines The configuration lines to be written
363 * @throws \RuntimeException
364 * @return boolean TRUE on success
365 * @access private
366 */
367 public function writeAdditionalConfiguration(array $additionalConfigurationLines) {
368 $result = Utility\GeneralUtility::writeFile(
369 PATH_site . $this->additionalConfigurationFile,
370 '<?php' . LF .
371 implode(LF, $additionalConfigurationLines) . LF .
372 '?>'
373 );
374 return $result === FALSE ? FALSE : TRUE;
375 }
376
377 /**
378 * Uses FactoryConfiguration file and a possible AdditionalFactoryConfiguration
379 * file in typo3conf to create a basic LocalConfiguration.php. This is used
380 * by the install tool in an early step.
381 *
382 * @return void
383 * @access private
384 */
385 public function createLocalConfigurationFromFactoryConfiguration() {
386 if (file_exists($this->getLocalConfigurationFileLocation())) {
387 throw new \RuntimeException(
388 'LocalConfiguration.php exists already', 1364836026
389 );
390 }
391 $localConfigurationArray = require $this->getFactoryConfigurationFileLocation();
392 $additionalFactoryConfigurationFileLocation = $this->getAdditionalFactoryConfigurationFileLocation();
393 if (file_exists($additionalFactoryConfigurationFileLocation)) {
394 $additionalFactoryConfigurationArray = require $additionalFactoryConfigurationFileLocation;
395 $localConfigurationArray = Utility\GeneralUtility::array_merge_recursive_overrule(
396 $localConfigurationArray,
397 $additionalFactoryConfigurationArray
398 );
399 }
400 $this->writeLocalConfiguration($localConfigurationArray);
401 }
402
403 /**
404 * Check if access / write to given path in local configuration is allowed.
405 *
406 * @param string $path Path to search for
407 * @return boolean TRUE if access is allowed
408 */
409 protected function isValidLocalConfigurationPath($path) {
410 // Early return for white listed paths
411 foreach ($this->whiteListedLocalConfigurationPaths as $whiteListedPath) {
412 if (Utility\GeneralUtility::isFirstPartOfStr($path, $whiteListedPath)) {
413 return TRUE;
414 }
415 }
416 return Utility\ArrayUtility::isValidPath($this->getDefaultConfiguration(), $path);
417 }
418
419 }
420
421
422 ?>