PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/wee/app/weeConfigFile.class.php

https://github.com/extend/wee
PHP | 322 lines | 148 code | 61 blank | 113 comment | 31 complexity | 3060c376c8cdf28e08b6c16dfc0e9e39 MD5 | raw file
  1. <?php
  2. /**
  3. Web:Extend
  4. Copyright (c) 2006-2010 Dev:Extend
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. if (!defined('ALLOW_INCLUSION')) die;
  18. /**
  19. Loader of Web:Extend's .cnf configuration files.
  20. @see share/conf/sample.cnf for an example configuration file
  21. */
  22. class weeConfigFile implements Mappable
  23. {
  24. /**
  25. Contains the configuration data.
  26. */
  27. protected $aConfig = array();
  28. /**
  29. The stack of the files being currently parsed.
  30. Used to .include other configuration files inside themselves.
  31. */
  32. protected $aFilesStack = array();
  33. /**
  34. Load the specified configuration file.
  35. @param $sFilename Path and filename to the configuration file
  36. */
  37. public function __construct($sFilename)
  38. {
  39. $this->parseFile($sFilename);
  40. }
  41. /**
  42. Cache-aware configuration loading.
  43. If a cache file is available, load directly the configuration array from the cache.
  44. Otherwise, create a weeConfigFile object, retrieve the configuration as an array,
  45. save that array into a cache file and return it.
  46. No cached data is loaded if DEBUG or NO_CACHE is defined.
  47. @param $sFilename The configuration file's filename.
  48. @param $sCacheFilename The configuration file's cache filename.
  49. @return array The configuration data that has been loaded.
  50. */
  51. public static function cachedLoad($sFilename, $sCacheFilename)
  52. {
  53. $bCacheEnabled = !(defined('DEBUG') || defined('NO_CACHE'));
  54. // Load from the cache if possible
  55. if ($bCacheEnabled && is_readable($sCacheFilename))
  56. return require($sCacheFilename);
  57. // Delete the cache file if it exists and DEBUG or NO_CACHE is enabled.
  58. // This eases the transition from one mode to another without having to clean-up files manually.
  59. if (is_file($sCacheFilename))
  60. unlink($sCacheFilename);
  61. // Load the configuration file
  62. $oConfigFile = new weeConfigFile($sFilename);
  63. $aConfig = $oConfigFile->toArray();
  64. // Configuration file has been loaded, cache it for later if possible
  65. if ($bCacheEnabled && is_writable(dirname($sCacheFilename))) {
  66. file_put_contents($sCacheFilename, '<?php return ' . var_export($aConfig, true) . ';');
  67. chmod($sCacheFilename, 0600);
  68. }
  69. return $aConfig;
  70. }
  71. /**
  72. Return the filename of the configuration file which is to be included.
  73. If the path of the configuration file begins with {{{ "//" }}} the path is relative to ROOT_PATH,
  74. if it begins with "./", then it is relative to the current file being parsed,
  75. otherwise the standard behaviour is adopted, working directory being the one of the process.
  76. @param $sPath The path of the configuration file.
  77. @return string The filename of the configuration file.
  78. */
  79. protected function getIncludeFilename($sPath)
  80. {
  81. $sPrefix = substr($sPath, 0, 2);
  82. if ($sPrefix == '//')
  83. return ROOT_PATH . substr($sPath, 2);
  84. if ($sPrefix == './')
  85. return dirname(end($this->aFilesStack)) . '/' . substr($sPath, 2);
  86. return $sPath;
  87. }
  88. /**
  89. Return the table of target functions.
  90. @return array The table of the functions supported by the class in targets.
  91. */
  92. protected function getTargetFunctions()
  93. {
  94. static $aFunc = array(
  95. 'os' => 'php_uname("s") == ":1"',
  96. 'host' => 'php_uname("n") == ":1"',
  97. 'phpver' => 'phpversion() == ":1"',
  98. 'extver' => 'phpversion(":1") == ":2"',
  99. 'sapi' => 'php_sapi_name() == ":1"',
  100. 'path' => 'dirname(dirname(dirname(__FILE__))) == ":1"',
  101. 'isfile' => 'is_file(":1")',
  102. 'isdir' => 'is_dir(":1")',
  103. );
  104. return $aFunc;
  105. }
  106. /**
  107. Check if the system targeted is the same as the one currently used.
  108. Configuration lines can begin with a $(instruction). command.
  109. The 'instruction' is a list of words, following this schema:
  110. * function [param1] [param2] [...] target
  111. With function one of these:
  112. * os: Operating System name, e.g. NetBSD.
  113. * host: Hostname, like localhost.example.com.
  114. * phpver: PHP version.
  115. * extver: PHP extension version. Needs one parameter: the extension's name.
  116. * sapi: Type of interface between web server and PHP.
  117. * path: The path to the folder containing the bootstrap file.
  118. * isfile: Whether the given file exists and is a regular file.
  119. * isdir: Whether the given directory exists and is a directory.
  120. And target is the value wanted.
  121. If you need to group some words to form the parameters, surround them with double quotes.
  122. @param $sInstruction The 'instruction' string
  123. @return bool Whether this system is the targeted system
  124. @warning The function name must not have spaces
  125. */
  126. protected function isTargetedSystem($sInstruction)
  127. {
  128. $sInstruction = substr($sInstruction, 2);
  129. $i = strpos($sInstruction, ')');
  130. $i !== false
  131. or burn('UnexpectedValueException',
  132. _WT('The targeted system instruction is missing the closing parenthesis.'));
  133. $sInstruction = trim(substr($sInstruction, 0, $i));
  134. $aFuncs = $this->getTargetFunctions();
  135. $i = strpos($sInstruction, ' ');
  136. empty($i) and burn('UnexpectedValueException',
  137. _WT('The instruction does not have a target function.'));
  138. $sFunction = substr($sInstruction, 0, $i);
  139. isset($aFuncs[$sFunction])
  140. or burn('UnexpectedValueException',
  141. sprintf(_WT('The target function "%s" does not exist.'), $sFunction));
  142. $sInstruction = substr($sInstruction, $i + 1);
  143. $aArgs = array();
  144. while ($sInstruction)
  145. {
  146. if ($sInstruction[0] == '"')
  147. {
  148. $sInstruction = substr($sInstruction, 1);
  149. $i = strpos($sInstruction, '"');
  150. $i !== false
  151. or burn('UnexpectedValueException',
  152. _WT('A closing double quote is missing.'));
  153. }
  154. else
  155. {
  156. $i = strpos($sInstruction, ' ');
  157. if ($i === false)
  158. {
  159. $aArgs[] = $sInstruction;
  160. break;
  161. }
  162. }
  163. $aArgs[] = substr($sInstruction, 0, $i);
  164. $sInstruction = substr($sInstruction, $i + 1);
  165. }
  166. $sEval = $aFuncs[$sFunction];
  167. $iExpectedArgs = substr_count($sEval, ':');
  168. $iActualArgs = count($aArgs);
  169. $iExpectedArgs == $iActualArgs
  170. or burn('UnexpectedValueException',
  171. sprintf(_WT('The target function expects %d arguments but %d were given.'), $iExpectedArgs, $iActualArgs));
  172. // Special case for isfile and isdir, the argument is a filename
  173. if ($sFunction == 'isfile' || $sFunction == 'isdir')
  174. $aArgs[0] = $this->getIncludeFilename($aArgs[0]);
  175. foreach ($aArgs as $i => $sArg)
  176. $sEval = str_replace(':' . ($i + 1), addslashes($sArg), $sEval);
  177. return eval('return ' . $sEval . ';');
  178. }
  179. /**
  180. Parse the specified configuration file.
  181. @param $sFilename Path and filename to the configuration file.
  182. */
  183. protected function parseFile($sFilename)
  184. {
  185. file_exists($sFilename) or burn('FileNotFoundException',
  186. sprintf(_WT('The file "%s" does not exist.'), $sFilename));
  187. $sRealpath = realpath($sFilename);
  188. in_array($sRealpath, $this->aFilesStack) and burn('UnexpectedValueException',
  189. sprintf(_WT('The configuration file "%s" is already in the parsing stack. There may be a recursive inclusion.'), $sRealpath));
  190. $rFile = fopen($sFilename, 'r');
  191. $this->aFilesStack[] = $sRealpath;
  192. while (!feof($rFile))
  193. $this->parseLine(fgets($rFile));
  194. fclose($rFile);
  195. array_pop($this->aFilesStack);
  196. }
  197. /**
  198. Parse a configuration line.
  199. @param $sLine The configuration line.
  200. */
  201. protected function parseLine($sLine)
  202. {
  203. $sLine = trim($sLine);
  204. // Empty lines and comments
  205. if (empty($sLine) || $sLine[0] == '#')
  206. return;
  207. // Target instructions
  208. if (substr($sLine, 0, 2) == '$(')
  209. {
  210. if (!$this->isTargetedSystem($sLine))
  211. return;
  212. $sLine = ltrim(substr($sLine, strpos($sLine, ').') + 2));
  213. }
  214. // Inclusions
  215. if (substr($sLine, 0, 7) == 'include')
  216. {
  217. $sParam = ltrim(substr($sLine, 7));
  218. empty($sParam) and burn('UnexpectedValueException',
  219. _WT('The parameter of the include instruction is missing.'));
  220. if ($sParam[0] != '=')
  221. {
  222. $this->parseFile($this->getIncludeFilename(ltrim(substr($sLine, 7))));
  223. return;
  224. }
  225. }
  226. $i = strpos($sLine, '=');
  227. $i === false and burn('UnexpectedValueException',
  228. _WT('The assignement instruction does not have an equal sign.'));
  229. $sLeft = rtrim(substr($sLine, 0, $i));
  230. $sRight = ltrim(substr($sLine, $i + 1));
  231. $this->aConfig[$sLeft] = $sRight;
  232. }
  233. /**
  234. Returns the data as array, since we can't cast weeConfigFile to retrieve the array's data.
  235. @return array Object's data.
  236. */
  237. public function toArray()
  238. {
  239. return $this->aConfig;
  240. }
  241. }