InifileConfiguration.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\config\impl;
12 
22 
23 /**
24  * InifileConfiguration reads the application configuraiton from ini files.
25  * @note This class only supports ini files with sections.
26  *
27  * @author ingo herwig <ingo@wemove.com>
28  */
30 
31  private $_configArray = array(); // an assoziate array that holds sections with keys with values
32  private $_comments = array(); // an assoziate array that holds the comments/blank lines in the file
33  // (each comment is attached to the following section/key)
34  // the key ';' holds the comments at the end of the file
35  private $_lookupTable = array(); // an assoziate array that has lowercased section or section:key
36  // keys and array(section, key) values for fast lookup
37 
38  private $_isModified = false;
39  private $_addedFiles = array(); // files added to the configuration
40  private $_containedFiles = array(); // all included files (also by config include)
41  private $_useCache = true;
42 
43  private $_configPath = null;
44  private $_configExtension = 'ini';
45 
46  private $_fileUtil = null;
47 
48  private static $_logger = null;
49 
50  /**
51  * Constructor.
52  * @param $configPath The path, either absolute or relative to the executed script
53  */
54  public function __construct($configPath) {
55  $this->_configPath = $configPath;
56  $this->_fileUtil = new FileUtil();
57  if (self::$_logger == null) {
58  self::$_logger = LogManager::getLogger(__CLASS__);
59  }
60  }
61 
62  /**
63  * Get the filesystem path to the configuration files.
64  * @return The path, either absolute or relative to the executed script
65  */
66  public function getConfigPath() {
67  return $this->_configPath;
68  }
69 
70  /**
71  * Configuration interface
72  */
73 
74  /**
75  * @see Configuration::getConfigurations()
76  */
77  public function getConfigurations() {
78  return $this->_fileUtil->getFiles($this->_configPath, '/\.'.$this->_configExtension.'$/', true);
79  }
80 
81  /**
82  * @see Configuration::addConfiguration()
83  * Name is the ini file to be parsed (relative to configPath)
84  * @note ini files referenced in section 'config' key 'include' are parsed afterwards
85  */
86  public function addConfiguration($name, $processValues=true) {
87  if (self::$_logger->isDebugEnabled()) {
88  self::$_logger->debug("Add configuration: ".$name);
89  }
90  $filename = $this->_configPath.$name;
91 
92  // do nothing, if the requested file was the last parsed file
93  // we don't only check if it's parsed, because order matters
94  $numParsedFiles = sizeof($this->_addedFiles);
95  $lastFile = $numParsedFiles > 0 ? $this->_addedFiles[$numParsedFiles-1] : '';
96  if (self::$_logger->isDebugEnabled()) {
97  self::$_logger->debug("Parsed files: ".$numParsedFiles.", last file: ".$lastFile);
98  }
99  if ($numParsedFiles > 0 && $lastFile == $filename) {
100  if (self::$_logger->isDebugEnabled()) {
101  self::$_logger->debug("Skipping");
102  }
103  return;
104  }
105 
106  if (file_exists($filename)) {
107  if (self::$_logger->isDebugEnabled()) {
108  self::$_logger->debug("Adding...");
109  }
110  // try to unserialize an already parsed ini file sequence
111  $this->_addedFiles[] = $filename;
112  if (!$this->unserialize($this->_addedFiles)) {
113  if (self::$_logger->isDebugEnabled()) {
114  self::$_logger->debug("Parse first time");
115  }
116  $result = $this->processFile($filename, $this->_configArray, $this->_containedFiles);
117  $this->_configArray = $result['config'];
118  $this->_containedFiles = array_unique($result['files']);
119 
120  if ($processValues) {
121  $this->processValues();
122  }
123 
124  // re-build lookup table
125  $this->buildLookupTable();
126 
127  // serialize the parsed ini file sequence
128  $this->serialize();
129  }
130  else {
131  if (self::$_logger->isDebugEnabled()) {
132  self::$_logger->debug("Reuse from cache");
133  }
134  }
135  }
136  else {
137  throw new ConfigurationException('Configuration file '.$filename.' not found!');
138  }
139  }
140 
141  /**
142  * Process the given file recursivly
143  * @param $filename The filename
144  * @param $configArray Configuration array
145  * @param $parsedFiles Parsed files
146  * @return Associative array with keys 'config' (configuration array) and 'files'
147  * (array of parsed files)
148  */
149  protected function processFile($filename, $configArray=array(), $parsedFiles=array()) {
150  // avoid circular includes
151  if (!in_array($filename, $parsedFiles)) {
152  $parsedFiles[] = $filename;
153 
154  $content = $this->_parse_ini_file($filename);
155 
156  // process includes
157  $includes = $this->getConfigIncludes($content);
158  if ($includes) {
159  $this->processValue($includes);
160  foreach ($includes as $include) {
161  $result = $this->processFile($this->_configPath.$include, $configArray, $parsedFiles);
162  $configArray = $this->configMerge($configArray, $result['config'], true);
163  $parsedFiles = $result['files'];
164  }
165  }
166 
167  // process self
168  $configArray = $this->configMerge($configArray, $content, true);
169  }
170  return array('config' => $configArray, 'files' => $parsedFiles);
171  }
172 
173  /**
174  * @see Configuration::getSections()
175  */
176  public function getSections() {
177  return array_keys($this->_configArray);
178  }
179 
180  /**
181  * @see Configuration::hasSection()
182  */
183  public function hasSection($section) {
184  return ($this->lookup($section) != null);
185  }
186 
187  /**
188  * @see Configuration::getSection()
189  */
190  public function getSection($section) {
191  $lookupEntry = $this->lookup($section);
192  if ($lookupEntry == null) {
193  throw new ConfigurationException('Section \''.$section.'\' not found!');
194  }
195  else {
196  return $this->_configArray[$lookupEntry[0]];
197  }
198  }
199 
200  /**
201  * @see Configuration::hasValue()
202  */
203  public function hasValue($key, $section) {
204  return ($this->lookup($section, $key) != null);
205  }
206 
207  /**
208  * @see Configuration::getValue()
209  */
210  public function getValue($key, $section) {
211  $lookupEntry = $this->lookup($section, $key);
212  if ($lookupEntry == null || sizeof($lookupEntry) == 1) {
213  throw new ConfigurationException('Key \''.$key.'\' not found in section \''.$section.'\'!');
214  }
215  else {
216  return $this->_configArray[$lookupEntry[0]][$lookupEntry[1]];
217  }
218  }
219 
220  /**
221  * @see Configuration::getBooleanValue()
222  */
223  public function getBooleanValue($key, $section) {
224  $value = $this->getValue($key, $section);
225  return StringUtil::getBoolean($value);
226  }
227 
228  /**
229  * @see Configuration::getDirectoryValue()
230  */
231  public function getDirectoryValue($key, $section) {
232  $value = $this->getValue($key, $section);
233  $isArray = is_array($value);
234  $values = !$isArray ? array($value) : $value;
235 
236  $result = array();
237  foreach ($values as $path) {
238  $absPath = WCMF_BASE.$path;
239  $result[] = $this->_fileUtil->realpath($absPath).'/';
240  }
241 
242  return $isArray ? $result : (sizeof($result) > 0 ? $result[0] : null);
243  }
244 
245  /**
246  * @see Configuration::getFileValue()
247  */
248  public function getFileValue($key, $section) {
249  $value = $this->getValue($key, $section);
250  $isArray = is_array($value);
251  $values = !$isArray ? array($value) : $value;
252 
253  $result = array();
254  foreach ($values as $path) {
255  $absPath = WCMF_BASE.$path;
256  $result[] = $this->_fileUtil->realpath(dirname($absPath)).'/'.basename($absPath);
257  }
258 
259  return $isArray ? $result : (sizeof($result) > 0 ? $result[0] : null);
260  }
261 
262  /**
263  * @see Configuration::getKey()
264  */
265  public function getKey($value, $section) {
266  $map = array_flip($this->getSection($section));
267  if (!isset($map[$value])) {
268  throw new ConfigurationException('Value \''.$value.'\' not found in section \''.$section.'\'!');
269  }
270  return $map[$value];
271  }
272 
273  /**
274  * WritableConfiguration interface
275  */
276 
277  /**
278  * @see WritableConfiguration::isEditable()
279  */
280  public function isEditable($section) {
281  if ($this->hasValue('readonlySections', 'config')) {
282  $readonlySections = $this->getValue('readonlySections', 'config');
283  $sectionLower = strtolower($section);
284  if (is_array($readonlySections)) {
285  foreach($readonlySections as $readonlySection) {
286  if ($sectionLower == strtolower($readonlySection)) {
287  return false;
288  }
289  }
290  }
291  }
292  return true;
293  }
294 
295  /**
296  * @see WritableConfiguration::isModified()
297  */
298  public function isModified() {
299  return $this->_isModified;
300  }
301 
302  /**
303  * @see WritableConfiguration::createSection()
304  */
305  public function createSection($section) {
306  $section = trim($section);
307  if (strlen($section) == 0) {
308  throw new IllegalArgumentException('Empty section names are not allowed!');
309  }
310  if ($this->hasSection($section)) {
311  throw new IllegalArgumentException('Section \''.$section.'\' already exists!');
312  }
313  $this->_configArray[$section] = '';
314  $this->buildLookupTable();
315  $this->_isModified = true;
316  return true;
317  }
318 
319  /**
320  * @see WritableConfiguration::removeSection()
321  */
322  public function removeSection($section) {
323  if (!$this->isEditable($section)) {
324  throw new IllegalArgumentException('Section \''.$section.'\' is not editable!');
325  }
326  $lookupEntry = $this->lookup($section);
327  if ($lookupEntry != null) {
328  unset($this->_configArray[$lookupEntry[0]]);
329  $this->buildLookupTable();
330  $this->_isModified = true;
331  }
332  }
333 
334  /**
335  * @see WritableConfiguration::renameSection()
336  */
337  public function renameSection($oldname, $newname) {
338  $newname = trim($newname);
339  if (strlen($newname) == 0) {
340  throw new IllegalArgumentException('Empty section names are not allowed!');
341  }
342  $lookupEntryOld = $this->lookup($oldname);
343  if ($lookupEntryOld == null) {
344  throw new IllegalArgumentException('Section \''.$oldname.'\' does not exist!');
345  }
346  if (!$this->isEditable($oldname)) {
347  throw new IllegalArgumentException('Section \''.$oldname.'\' is not editable!');
348  }
349  $lookupEntryNew = $this->lookup($newname);
350  if ($lookupEntryNew != null) {
351  throw new IllegalArgumentException('Section \''.$newname.'\' already exists!');
352  }
353  // do rename
354  $value = $this->_configArray[$lookupEntryOld[0]];
355  $this->_configArray[$newname] = $value;
356  unset($this->_configArray[$lookupEntryOld[0]]);
357  $this->buildLookupTable();
358  $this->_isModified = true;
359  }
360 
361  /**
362  * @see WritableConfiguration::setValue()
363  */
364  public function setValue($key, $value, $section, $createSection=true) {
365  $key = trim($key);
366  if (strlen($key) == 0) {
367  throw new IllegalArgumentException('Empty key names are not allowed!');
368  }
369  $lookupEntrySection = $this->lookup($section);
370  if ($lookupEntrySection == null && !$createSection) {
371  throw new IllegalArgumentException('Section \''.$section.'\' does not exist!');
372  }
373  if ($lookupEntrySection != null && !$this->isEditable($section)) {
374  throw new IllegalArgumentException('Section \''.$section.'\' is not editable!');
375  }
376 
377  // create section if requested and determine section name
378  if ($lookupEntrySection == null && $createSection) {
379  $section = trim($section);
380  $this->_configArray[$section] = array();
381  $finalSectionName = $section;
382  }
383  else {
384  $finalSectionName = $lookupEntrySection[0];
385  }
386  // determine key name
387  if ($lookupEntrySection != null) {
388  $lookupEntryKey = $this->lookup($section, $key);
389  if ($lookupEntryKey == null) {
390  // key does not exist yet
391  $finalKeyName = $key;
392  }
393  else {
394  $finalKeyName = $lookupEntryKey[1];
395  }
396  }
397  else {
398  $finalKeyName = $key;
399  }
400  $this->_configArray[$finalSectionName][$finalKeyName] = $value;
401  $this->buildLookupTable();
402  $this->_isModified = true;
403  }
404 
405  /**
406  * @see WritableConfiguration::removeKey()
407  */
408  public function removeKey($key, $section) {
409  if (!$this->isEditable($section)) {
410  throw new IllegalArgumentException('Section \''.$section.'\' is not editable!');
411  }
412  $lookupEntry = $this->lookup($section, $key);
413  if ($lookupEntry != null) {
414  unset($this->_configArray[$lookupEntry[0]][$lookupEntry[1]]);
415  $this->buildLookupTable();
416  $this->_isModified = true;
417  }
418  }
419 
420  /**
421  * @see WritableConfiguration::renameKey()
422  */
423  public function renameKey($oldname, $newname, $section) {
424  $newname = trim($newname);
425  if (strlen($newname) == 0) {
426  throw new IllegalArgumentException('Empty key names are not allowed!');
427  }
428  if (!$this->hasSection($section)) {
429  throw new IllegalArgumentException('Section \''.$section.'\' does not exist!');
430  }
431  if (!$this->isEditable($section)) {
432  throw new IllegalArgumentException('Section \''.$section.'\' is not editable!');
433  }
434  $lookupEntryOld = $this->lookup($section, $oldname);
435  if ($lookupEntryOld == null) {
436  throw new IllegalArgumentException('Key \''.$oldname.'\' does not exist in section \''.$section.'\'!');
437  }
438  $lookupEntryNew = $this->lookup($section, $newname);
439  if ($lookupEntryNew != null) {
440  throw new IllegalArgumentException('Key \''.$newname.'\' already exists in section \''.$section.'\'!');
441  }
442  // do rename
443  $value = $this->_configArray[$lookupEntryOld[0]][$lookupEntryOld[1]];
444  $this->_configArray[$lookupEntryOld[0]][$newname] = $value;
445  unset($this->_configArray[$lookupEntryOld[0]][$lookupEntryOld[1]]);
446  $this->buildLookupTable();
447  $this->_isModified = true;
448  }
449 
450  /**
451  * @see WritableConfiguration::writeConfiguration()
452  */
453  public function writeConfiguration($name) {
454  $filename = $name;
455  $content = "";
456  foreach($this->_configArray as $section => $values) {
457  $sectionString = "[".$section."]";
458  $content .= $this->_comments[$sectionString];
459  $content .= $sectionString."\n";
460  if (is_array($values)) {
461  foreach($values as $key => $value) {
462  if (is_array($value)) {
463  $value = "{".join(", ", $value)."}";
464  }
465  // unescape double quotes
466  $value = str_replace("\\\"", "\"", $value);
467  $content .= $this->_comments[$section][$key];
468  $content .= $key." = ".$value."\n";
469  }
470  }
471  }
472  $content .= $this->_comments[';'];
473 
474  if (!$fh = fopen($filename, 'w')) {
475  throw new IOException('Can\'t open ini file \''.$filename.'\'!');
476  }
477 
478  if (!fwrite($fh, $content)) {
479  throw new IOException('Can\'t write ini file \''.$filename.'\'!');
480  }
481  fclose($fh);
482  // clear the application cache, because it may become invalid
483  $this->clearAllCache();
484  $this->_isModified = false;
485  }
486 
487  /**
488  * Private interface
489  */
490 
491  /**
492  * Load in the ini file specified in filename, and return
493  * the settings in a multidimensional array, with the section names and
494  * settings included. All section names and keys are lowercased.
495  * @param $filename The filename of the ini file to parse
496  * @return An associative array containing the data
497  *
498  * @author: Sebastien Cevey <seb@cine7.net>
499  * Original Code base: <info@megaman.nl>
500  * Added comment handling/Removed process sections flag: Ingo Herwig
501  */
502  protected function _parse_ini_file($filename) {
503  if (!file_exists($filename)) {
504  throw new ConfigurationException('The config file '.$filename.' does not exist.');
505  }
506  $configArray = array();
507  $sectionName = '';
508  $lines = file($filename);
509  $commentsPending = '';
510  foreach($lines as $line) {
511  $line = trim($line);
512  // comments/blank lines
513  if($line == '' || $line[0] == ';') {
514  $commentsPending .= $line."\n";
515  continue;
516  }
517 
518  if($line[0] == '[' && $line[strlen($line)-1] == ']') {
519  $sectionName = substr($line, 1, strlen($line)-2);
520  $configArray[$sectionName] = array();
521 
522  // store comments/blank lines for section
523  $this->_comments[$line] = $commentsPending;
524  $commentsPending = '';
525  }
526  else {
527  $parts = explode('=', $line, 2);
528  $key = trim($parts[0]);
529  $value = trim($parts[1]);
530  $configArray[$sectionName][$key] = $value;
531 
532  // store comments/blank lines for key
533  $this->_comments[$sectionName][$key] = $commentsPending;
534  $commentsPending = "";
535  }
536  }
537  // store comments/blank lines from the end of the file
538  $this->_comments[';'] = substr($commentsPending, 0, -1);
539 
540  return $configArray;
541  }
542 
543  /**
544  * Process the values in the ini array.
545  * This method turns string values that hold array definitions
546  * (comma separated values enclosed by curly brackets) into array values.
547  */
548  protected function processValues() {
549  array_walk_recursive($this->_configArray, array($this, 'processValue'));
550  }
551 
552  /**
553  * Process the values in the ini array.
554  * This method turns string values that hold array definitions
555  * (comma separated values enclosed by curly brackets) into array values.
556  * @param $value A reference to the value
557  */
558  protected function processValue(&$value) {
559  if (!is_array($value)) {
560  // decode encoded (%##) values
561  if (preg_match ("/%/", $value)) {
562  $value = urldecode($value);
563  }
564  // make arrays
565  if(preg_match("/^{.*}$/", $value)) {
566  $arrayValues = StringUtil::quotesplit(substr($value, 1, -1));
567  $value = array();
568  foreach ($arrayValues as $arrayValue) {
569  $value[] = trim($arrayValue);
570  }
571  }
572  }
573  }
574 
575  /**
576  * Merge two arrays, preserving entries in first one unless they are
577  * overridden by ones in the second.
578  * @param $array1 First array.
579  * @param $array2 Second array.
580  * @param $override Boolean whether values defined in array1 should be overriden by values defined in array2.
581  * @return The merged array.
582  */
583  protected function configMerge($array1, $array2, $override) {
584  $result = $array1;
585  foreach(array_keys($array2) as $key) {
586  if (!array_key_exists($key, $result)) {
587  $result[$key] = $array2[$key];
588  }
589  else {
590  foreach(array_keys($array2[$key]) as $subkey) {
591  if ((array_key_exists($subkey, $result[$key]) && $override) || !isset($result[$key][$subkey])) {
592  $result[$key][$subkey] = $array2[$key][$subkey];
593  }
594  }
595  }
596  }
597  return $result;
598  }
599 
600  /**
601  * Search the given value for a 'include' key in a section named 'config' (case-insensivite)
602  * @param $array The array to search in
603  * @return Mixed
604  */
605  protected function getConfigIncludes($array) {
606  $sectionMatches = null;
607  if (preg_match('/(?:^|,)(config)(?:,|$)/i', join(',', array_keys($array)), $sectionMatches)) {
608  $sectionKey = sizeof($sectionMatches) > 0 ? $sectionMatches[1] : null;
609  if ($sectionKey) {
610  $keyMatches = null;
611  if (preg_match('/(?:^|,)(include)(?:,|$)/i', join(',', array_keys($array[$sectionKey])), $keyMatches)) {
612  return sizeof($keyMatches) > 0 ? $array[$sectionKey][$keyMatches[1]] : null;
613  }
614  }
615  }
616  return null;
617  }
618 
619  /**
620  * Store the instance in the filesystem. If the instance is modified, this call is ignored.
621  */
622  protected function serialize() {
623  if ($this->_useCache && !$this->isModified()) {
624  $cacheFile = $this->getSerializeFilename($this->_addedFiles);
625  if (self::$_logger->isDebugEnabled()) {
626  self::$_logger->debug("Serialize configuration: ".join(',', $this->_addedFiles)." to file: ".$cacheFile);
627  }
628  if ($fh = @fopen($cacheFile, "w")) {
629  if (@fwrite($fh, serialize(get_object_vars($this)))) {
630  @fclose($fh);
631  }
632  // clear the application cache, because it may become invalid
633  $this->clearAllCache();
634  }
635  }
636  }
637 
638  /**
639  * Retrieve parsed ini data from the filesystem and update the current instance.
640  * If the current instance is modified or the last file given in parsedFiles
641  * is newer than the serialized data, this call is ignored.
642  * If InifileConfiguration class changed, the call will be ignored as well.
643  * @param $parsedFiles An array of ini filenames that must be contained in the data.
644  * @return Boolean whether the data could be retrieved or not
645  */
646  protected function unserialize($parsedFiles) {
647  if ($this->_useCache && !$this->isModified()) {
648  $cacheFile = $this->getSerializeFilename($parsedFiles);
649  if (file_exists($cacheFile)) {
650  $parsedFiles[] = __FILE__;
651  if (!$this->checkFileDate($parsedFiles, $cacheFile)) {
652  $vars = unserialize(file_get_contents($cacheFile));
653 
654  // check if included ini files were updated since last cache time
655  $includes = $vars['_containedFiles'];
656  if (is_array($includes)) {
657  if ($this->checkFileDate($includes, $cacheFile)) {
658  return false;
659  }
660  }
661 
662  // everything is up-to-date
663  foreach($vars as $key => $val) {
664  $this->$key = $val;
665  }
666  return true;
667  }
668  }
669  }
670  return false;
671  }
672 
673  /**
674  * Get the filename for the serialized data that correspond to the the given ini file sequence.
675  * @param $parsedFiles An array of parsed filenames
676  * @return Filename
677  */
678  protected function getSerializeFilename($parsedFiles) {
679  $path = session_save_path().DIRECTORY_SEPARATOR;
680  $filename = $path.'wcmf_config_'.md5(realpath($this->_configPath).'/'.join('_', $parsedFiles));
681  return $filename;
682  }
683 
684  /**
685  * Check if one file in fileList is newer than the referenceFile.
686  * @param $fileList An array of files
687  * @param $referenceFile The file to check against
688  * @return True, if one of the files is newer, false else
689  */
690  protected function checkFileDate($fileList, $referenceFile) {
691  foreach ($fileList as $file) {
692  if (filemtime($file) > filemtime($referenceFile)) {
693  return true;
694  }
695  }
696  return false;
697  }
698 
699  /**
700  * Clear application cache.
701  */
702  protected function clearAllCache() {
703  if (self::$_logger->isDebugEnabled()) {
704  self::$_logger->debug("Clear all caches");
705  }
706  try {
707  $cache = ObjectFactory::getInstance('cache');
708  $cache->clearAll();
709  }
710  catch (\Exception $e) {}
711  }
712 
713  /**
714  * Build the internal lookup table
715  */
716  protected function buildLookupTable() {
717  $this->_lookupTable = array();
718  foreach ($this->_configArray as $section => $entry) {
719  // create section entry
720  $lookupSectionKey = strtolower($section.':');
721  $this->_lookupTable[$lookupSectionKey] = array($section);
722  // create key entries
723  foreach ($entry as $key => $value) {
724  $lookupKey = strtolower($lookupSectionKey.$key);
725  $this->_lookupTable[$lookupKey] = array($section, $key);
726  }
727  }
728  }
729 
730  /**
731  * Lookup section and key.
732  * @param $section The section to lookup
733  * @param $key The key to lookup (optional)
734  * @return Array with section as first entry and key as second or null if not found
735  */
736  protected function lookup($section, $key=null) {
737  $lookupKey = strtolower($section).':'.strtolower($key);
738  if (isset($this->_lookupTable[$lookupKey])) {
739  return $this->_lookupTable[$lookupKey];
740  }
741  return null;
742  }
743 }
744 ?>
Implementations of WritableConfiguration allow to change the whole or parts of the configuration and ...
configMerge($array1, $array2, $override)
Merge two arrays, preserving entries in first one unless they are overridden by ones in the second...
processValue(&$value)
Process the values in the ini array.
processFile($filename, $configArray=array(), $parsedFiles=array())
Process the given file recursivly.
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:35
lookup($section, $key=null)
Lookup section and key.
getConfigPath()
Get the filesystem path to the configuration files.
getConfigIncludes($array)
Search the given value for a 'include' key in a section named 'config' (case-insensivite) ...
processValues()
Process the values in the ini array.
Implementations of Configuration give access to the application configuration.
_parse_ini_file($filename)
Private interface.
buildLookupTable()
Build the internal lookup table.
InifileConfiguration reads the application configuraiton from ini files.
FileUtil provides basic support for file functionality like HTTP file upload.
Definition: FileUtil.php:22
serialize()
Store the instance in the filesystem.
ConfigurationException signals an exception in the configuration.
unserialize($parsedFiles)
Retrieve parsed ini data from the filesystem and update the current instance.