/woops-src/classes/Woops/Ini/Parser.class.php

https://github.com/macmade/WOOPS · PHP · 375 lines · 150 code · 86 blank · 139 comment · 28 complexity · 82d8017418343ba93c8fa469697b92aa MD5 · raw file

  1. <?php
  2. ################################################################################
  3. # #
  4. # WOOPS - Web Object Oriented Programming System #
  5. # #
  6. # COPYRIGHT NOTICE #
  7. # #
  8. # Copyright (C) 2009 Jean-David Gadina - www.xs-labs.com #
  9. # All rights reserved #
  10. ################################################################################
  11. # $Id$
  12. /**
  13. * INI file parser
  14. *
  15. * @author Jean-David Gadina - www.xs-labs.com
  16. * @version 1.0
  17. * @package Woops.Ini
  18. */
  19. class Woops_Ini_Parser extends Woops_Core_Object
  20. {
  21. /**
  22. * The minimum version of PHP required to run this class (checked by the WOOPS class manager)
  23. */
  24. const PHP_COMPATIBLE = '5.2.0';
  25. /**
  26. * Whether the static variables are set or not
  27. */
  28. private static $_hasStatic = false;
  29. /**
  30. * The string utilities
  31. */
  32. protected static $_str = NULL;
  33. /**
  34. * The INI file object
  35. */
  36. protected $_ini = NULL;
  37. /**
  38. * The path to the INI file
  39. */
  40. protected $_filePath = '';
  41. /**
  42. * The INI configuration values
  43. */
  44. protected $_values = array();
  45. /**
  46. * Class constructor
  47. *
  48. * @param string The path to the INI file to parse
  49. * @return void
  50. * @see _parseFile
  51. */
  52. public function __construct( $path )
  53. {
  54. // Checks if the static variables are set
  55. if( !self::$_hasStatic ) {
  56. // Sets the static variables
  57. self::_setStaticVars();
  58. }
  59. // Checks if the file exists
  60. if( !file_exists( $path ) ) {
  61. // Error - The file does not exists
  62. throw new Woops_Ini_Parser_Exception(
  63. 'The INI file does not exists (path: ' . $path . ')',
  64. Woops_Ini_Parser_Exception::EXCEPTION_NO_FILE
  65. );
  66. }
  67. // Checks if the file is readable
  68. if( !is_readable( $path ) ) {
  69. // Error - The file is not readable
  70. throw new Woops_Ini_Parser_Exception(
  71. 'The INI file is not readable (path: ' . $path . ')',
  72. Woops_Ini_Parser_Exception::EXCEPTION_FILE_NOT_READABLE
  73. );
  74. }
  75. // Stores the file path
  76. $this->_filePath = $path;
  77. // Parses the INI file
  78. $this->_parseFile();
  79. }
  80. /**
  81. * Sets the needed static variables
  82. *
  83. * @return void
  84. */
  85. private static function _setStaticVars()
  86. {
  87. // Gets the instance of the string utilities
  88. self::$_str = Woops_String_Utils::getInstance();
  89. // Static variables are set
  90. self::$_hasStatic = true;
  91. }
  92. /**
  93. * Parses the INI file
  94. *
  95. * @return void
  96. * @see _processComments
  97. */
  98. protected function _parseFile()
  99. {
  100. // Gets each line of the INI file
  101. $lines = file( $this->_filePath );
  102. // No active section at the moment
  103. $section = '';
  104. // Storage for the JavaDoc-like comments
  105. $comments = array();
  106. // Creates an INI file object
  107. $this->_ini = new Woops_Ini_File();
  108. // Process each line of the file
  109. foreach( $lines as &$line ) {
  110. // Storage for the matches (preg_match)
  111. $matches = array();
  112. // Checks if the current line is a blank one
  113. if( !trim( $line ) ) {
  114. // Resets the comments storage array
  115. $comments = array();
  116. }
  117. // Checks if the current line defines is a comment
  118. if( preg_match( '/^\s*;\s*(.*)$/', $line, $matches ) ) {
  119. // Stores the current comment
  120. $comments[] = trim( $matches[ 1 ] );
  121. }
  122. // Checks if the current line defines a section
  123. if( preg_match( '/^\s*\[([^\]]+)\]/', $line, $matches ) ) {
  124. // Name of the section
  125. $section = $matches[ 1 ];
  126. // Creates the storage array for the section
  127. $this->_values[ $section ] = array();
  128. // Creates the section object
  129. $this->_ini->newSectionItem( $section );
  130. // Process the next line
  131. continue;
  132. }
  133. // Checks if the current lines defines a value
  134. if( preg_match( '/^\s*([^;=\s]+)\s*=\s+([^;\s]+)/', $line, $matches ) ) {
  135. // Gets the variable name and its value
  136. $key = $matches[ 1 ];
  137. $value = $matches[ 2 ];
  138. // Support for 'On'/'Off' values, which will be convert to boolean values
  139. if( $value === 'Off' ) {
  140. // Off - Converts to false
  141. $value = false;
  142. } elseif( $value === 'On' ) {
  143. // Off - Converts to true
  144. $value = true;
  145. }
  146. // Checks if we are in a section or not
  147. if( $section ) {
  148. // Checks if the variable name represents an array
  149. if( substr( $key, -2 ) === '[]' ) {
  150. // Gets only the variable name, without the '[]'
  151. $key = substr( $key, 0, -2 );
  152. // Checks if a value has already been added for that variable
  153. if( !isset( $this->_values[ $section ][ $key ] ) ) {
  154. // Creates the storage array
  155. $this->_values[ $section ][ $key ] = array(
  156. 'value' => array(),
  157. 'comments' => $this->_processComments( $comments )
  158. );
  159. // Creates the array object
  160. $this->_ini->getItem( $section )->newArrayItem( $key );
  161. // Resets the comments
  162. $comments = array();
  163. }
  164. // Adds the variable value
  165. $this->_values[ $section ][ $key ][ 'value' ][] = $value;
  166. $this->_ini->getItem( $section )->getItem( $key )->addValue( $value );
  167. } else {
  168. // Adds the variable value
  169. $this->_values[ $section ][ $key ] = array(
  170. 'value' => $value,
  171. 'comments' => $this->_processComments( $comments )
  172. );
  173. // Creates the value object
  174. $this->_ini->getItem( $section )->newValueItem( $key, $value );
  175. // Resets the comments
  176. $comments = array();
  177. }
  178. } else {
  179. // Checks if the variable name represents an array
  180. if( substr( $key, -2 ) === '[]' ) {
  181. // Gets only the variable name, without the '[]'
  182. $key = substr( $key, 0, -2 );
  183. // Checks if a value has already been added for that variable
  184. if( !isset( $this->_values[ $key ] ) ) {
  185. // Creates the storage array
  186. $this->_values[ $key ] = array(
  187. 'value' => array(),
  188. 'comments' => $this->_processComments( $comments )
  189. );
  190. // Creates the array object
  191. $this->_ini->newArrayItem( $key );
  192. // Resets the comments
  193. $comments = array();
  194. }
  195. // Adds the variable value
  196. $this->_values[ $key ][ 'value' ][] = $value;
  197. $this->_ini->getItem( $key )->addValue( $value );
  198. } else {
  199. // Adds the variable value
  200. $this->_values[ $key ] = array(
  201. 'value' => $value,
  202. 'comments' => $this->_processComments( $comments )
  203. );
  204. // Creates the value object
  205. $this->_ini->newValueItem( $key, $value );
  206. // Resets the comments
  207. $comments = array();
  208. }
  209. }
  210. }
  211. }
  212. }
  213. /**
  214. * Process raw INI comments, to check for JavaDoc-like instructions
  215. *
  216. * @param array An array with lines of raw INI comments
  217. * @return array An array with the processed comments
  218. */
  219. protected function _processComments( array $rawComments )
  220. {
  221. // Storage array
  222. $comments = array();
  223. // Process each comment line
  224. foreach( $rawComments as $comment ) {
  225. // Checks if we are reading a JavaDoc-like instruction or a normal comment
  226. if( substr( $comment, 0, 1 ) !== '@' ) {
  227. // Checks if the comment has to be interpreted as a title, or description (which can be multiline)
  228. if( !isset( $comments[ 'title' ] ) ) {
  229. // Adds the title
  230. $comments[ 'title' ] = $comment;
  231. } elseif( !isset( $comments[ 'description' ] ) ) {
  232. // Starts the description
  233. $comments[ 'description' ] = $comment;
  234. } else {
  235. // Checks if we must add a new line character
  236. if( substr( $comments[ 'description' ], -1 ) === '.' ) {
  237. // Adds the current line to the existing description
  238. $comments[ 'description' ] .= self::$_str->NL . $comment;
  239. } else {
  240. // Adds the current line to the existing description
  241. $comments[ 'description' ] .= ' ' . $comment;
  242. }
  243. }
  244. // Process the nex line
  245. continue;
  246. }
  247. // Checks if we are reading a @type instruction
  248. if( substr( $comment, 0, 5 ) == '@type' ) {
  249. // Sets the type
  250. $comments[ 'type' ] = trim( substr( $comment, 5 ) );
  251. }
  252. // Checks if we are reading a @required instruction
  253. if( substr( $comment, 0, 9 ) == '@required' ) {
  254. // Sets the required state
  255. $comments[ 'required' ] = true;
  256. }
  257. // Checks if we are reading an @option instruction
  258. if( substr( $comment, 0, 7 ) == '@option' ) {
  259. // Checks if options were already added or not
  260. if( !isset( $comments[ 'options' ] ) ) {
  261. // Creates the storage array for the options
  262. $comments[ 'options' ] = array();
  263. }
  264. // Adds the option
  265. $comments[ 'options' ][] = trim( substr( $comment, 7 ) );
  266. }
  267. }
  268. // Returns the processed comments
  269. return $comments;
  270. }
  271. /**
  272. * Gets an array with the INI values
  273. *
  274. * @return array An array with the INI values
  275. */
  276. public function getIniArray()
  277. {
  278. return $this->_values;
  279. }
  280. /**
  281. * Gets the INI file object
  282. *
  283. * @return Woops_Ini_File The INI file object
  284. */
  285. public function getIniObject()
  286. {
  287. return $this->_ini;
  288. }
  289. }