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