/classes/config/ConfigParser.inc.php

https://github.com/ojsde/pkp-lib · PHP · 217 lines · 119 code · 40 blank · 58 comment · 64 complexity · 266080a99f5eb673409f45bf3125f6a0 MD5 · raw file

  1. <?php
  2. /**
  3. * @file classes/config/ConfigParser.inc.php
  4. *
  5. * Copyright (c) 2000-2012 John Willinsky
  6. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  7. *
  8. * @class ConfigParser
  9. * @ingroup config
  10. *
  11. * @brief Class for parsing and modifying php.ini style configuration files.
  12. */
  13. class ConfigParser {
  14. /** Contents of the config file currently being parsed */
  15. var $content;
  16. /**
  17. * Constructor.
  18. */
  19. function ConfigParser() {
  20. }
  21. /**
  22. * Read a configuration file into a multidimensional array.
  23. * This is a replacement for the PHP parse_ini_file function, which does not type setting values.
  24. * @param $file string full path to the config file
  25. * @return array the configuration data (same format as http://php.net/parse_ini_file)
  26. */
  27. static function &readConfig($file) {
  28. $configData = array();
  29. $currentSection = false;
  30. $falseValue = false;
  31. if (!file_exists($file) || !is_readable($file)) {
  32. return $falseValue;
  33. }
  34. $fp = fopen($file, 'rb');
  35. if (!$fp) {
  36. return $falseValue;
  37. }
  38. while (!feof($fp)) {
  39. $line = fgets($fp, 1024);
  40. $line = trim($line);
  41. if ($line === '' || strpos($line, ';') === 0) {
  42. // Skip empty or commented line
  43. continue;
  44. }
  45. if (preg_match('/^\[(.+)\]/', $line, $matches)) {
  46. // Found a section
  47. $currentSection = $matches[1];
  48. if (!isset($configData[$currentSection])) {
  49. $configData[$currentSection] = array();
  50. }
  51. } else if (strpos($line, '=') !== false) {
  52. // Found a setting
  53. list($key, $value) = explode('=', $line, 2);
  54. $key = trim($key);
  55. $value = trim($value);
  56. // FIXME This may produce incorrect results if the line contains a comment
  57. if (preg_match('/^[\"\'](.*)[\"\']$/', $value, $matches)) {
  58. // Treat value as a string
  59. $value = stripslashes($matches[1]);
  60. } else {
  61. preg_match('/^([\S]*)/', $value, $matches);
  62. $value = $matches[1];
  63. // Try to determine the type of the value
  64. if ($value === '') {
  65. $value = null;
  66. } else if (is_numeric($value)) {
  67. if (strstr($value, '.')) {
  68. // floating-point
  69. $value = (float) $value;
  70. } else if (substr($value, 0, 2) == '0x') {
  71. // hex
  72. $value = intval($value, 16);
  73. } else if (substr($value, 0, 1) == '0') {
  74. // octal
  75. $value = intval($value, 8);
  76. } else {
  77. // integer
  78. $value = (int) $value;
  79. }
  80. } else if (strtolower($value) == 'true' || strtolower($value) == 'on') {
  81. $value = true;
  82. } else if (strtolower($value) == 'false' || strtolower($value) == 'off') {
  83. $value = false;
  84. } else if (defined($value)) {
  85. // The value matches a named constant
  86. $value = constant($value);
  87. }
  88. }
  89. if ($currentSection === false) {
  90. $configData[$key] = $value;
  91. } else if (is_array($configData[$currentSection])) {
  92. $configData[$currentSection][$key] = $value;
  93. }
  94. }
  95. }
  96. fclose($fp);
  97. return $configData;
  98. }
  99. /**
  100. * Read a configuration file and update variables.
  101. * This method stores the updated configuration but does not write it out.
  102. * Use writeConfig() or getFileContents() afterwards to do something with the new config.
  103. * @param $file string full path to the config file
  104. * @param $params array an associative array of configuration parameters to update. If the value is an associative array (of variable name/value pairs) instead of a scalar, the key is treated as a section instead of a variable. Parameters not in $params remain unchanged
  105. * @return boolean true if file could be read, false otherwise
  106. */
  107. function updateConfig($file, $params) {
  108. if (!file_exists($file) || !is_readable($file)) {
  109. return false;
  110. }
  111. $this->content = '';
  112. $lines = file($file);
  113. // Parse each line of the configuration file
  114. for ($i=0, $count=count($lines); $i < $count; $i++) {
  115. $line = $lines[$i];
  116. if (preg_match('/^;/', $line) || preg_match('/^\s*$/', $line)) {
  117. // Comment or empty line
  118. $this->content .= $line;
  119. } else if (preg_match('/^\s*\[(\w+)\]/', $line, $matches)) {
  120. // Start of new section
  121. $currentSection = $matches[1];
  122. $this->content .= $line;
  123. } else if (preg_match('/^\s*(\w+)\s*=/', $line, $matches)) {
  124. // Variable definition
  125. $key = $matches[1];
  126. if (!isset($currentSection) && array_key_exists($key, $params) && !is_array($params[$key])) {
  127. // Variable not in a section
  128. $value = $params[$key];
  129. } else if (isset($params[$currentSection]) && is_array($params[$currentSection]) && array_key_exists($key, $params[$currentSection])) {
  130. // Variable in a section
  131. $value = $params[$currentSection][$key];
  132. } else {
  133. // Variable not to be changed, do not modify line
  134. $this->content .= $line;
  135. continue;
  136. }
  137. if (preg_match('/[^\w\-\/]/', $value)) {
  138. // Escape strings containing non-alphanumeric characters
  139. $valueString = '"' . $value . '"';
  140. } else {
  141. $valueString = $value;
  142. }
  143. $this->content .= "$key = $valueString\n";
  144. } else {
  145. $this->content .= $line;
  146. }
  147. }
  148. return true;
  149. }
  150. /**
  151. * Write contents of current config file
  152. * @param $file string full path to output file
  153. * @return boolean file write is successful
  154. */
  155. function writeConfig($file) {
  156. if (!(file_exists($file) && is_writable($file))
  157. && !(!file_exists($file) && is_dir(dirname($file)) && is_writable(dirname($file)))) {
  158. // File location cannot be written to
  159. return false;
  160. }
  161. $fp = @fopen($file, 'wb');
  162. if (!$fp) {
  163. return false;
  164. }
  165. fwrite($fp, $this->content);
  166. fclose($fp);
  167. return true;
  168. }
  169. /**
  170. * Return the contents of the current config file.
  171. * @return string
  172. */
  173. function getFileContents() {
  174. return $this->content;
  175. }
  176. }
  177. ?>