1: <?php
2: /**
3: * IniReader
4: *
5: * PHP 5
6: *
7: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8: * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
9: *
10: * Licensed under The MIT License
11: * Redistributions of files must retain the above copyright notice.
12: *
13: * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
14: * @link http://cakephp.org CakePHP(tm) Project
15: * @package Cake.Configure
16: * @since CakePHP(tm) v 2.0
17: * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
18: */
19:
20: /**
21: * Ini file configuration parser. Since IniReader uses parse_ini_file underneath,
22: * you should be aware that this class shares the same behavior, especially with
23: * regards to boolean and null values.
24: *
25: * In addition to the native parse_ini_file features, IniReader also allows you
26: * to create nested array structures through usage of `.` delimited names. This allows
27: * you to create nested arrays structures in an ini config file. For example:
28: *
29: * `db.password = secret` would turn into `array('db' => array('password' => 'secret'))`
30: *
31: * You can nest properties as deeply as needed using `.`'s. In addition to using `.` you
32: * can use standard ini section notation to create nested structures:
33: *
34: * {{{
35: * [section]
36: * key = value
37: * }}}
38: *
39: * Once loaded into Configure, the above would be accessed using:
40: *
41: * `Configure::read('section.key');
42: *
43: * You can combine `.` separated values with sections to create more deeply
44: * nested structures.
45: *
46: * IniReader also manipulates how the special ini values of
47: * 'yes', 'no', 'on', 'off', 'null' are handled. These values will be
48: * converted to their boolean equivalents.
49: *
50: * @package Cake.Configure
51: * @see http://php.net/parse_ini_file
52: */
53: class IniReader implements ConfigReaderInterface {
54:
55: /**
56: * The path to read ini files from.
57: *
58: * @var array
59: */
60: protected $_path;
61:
62: /**
63: * The section to read, if null all sections will be read.
64: *
65: * @var string
66: */
67: protected $_section;
68:
69: /**
70: * Build and construct a new ini file parser. The parser can be used to read
71: * ini files that are on the filesystem.
72: *
73: * @param string $path Path to load ini config files from.
74: * @param string $section Only get one section, leave null to parse and fetch
75: * all sections in the ini file.
76: */
77: public function __construct($path, $section = null) {
78: $this->_path = $path;
79: $this->_section = $section;
80: }
81:
82: /**
83: * Read an ini file and return the results as an array.
84: *
85: * @param string $file Name of the file to read. The chosen file
86: * must be on the reader's path.
87: * @return array
88: * @throws ConfigureException
89: */
90: public function read($file) {
91: $filename = $this->_path . $file;
92: if (!file_exists($filename)) {
93: $filename .= '.ini';
94: if (!file_exists($filename)) {
95: throw new ConfigureException(__d('cake_dev', 'Could not load configuration files: %s or %s', substr($filename, 0, -4), $filename));
96: }
97: }
98: $contents = parse_ini_file($filename, true);
99: if (!empty($this->_section) && isset($contents[$this->_section])) {
100: $values = $this->_parseNestedValues($contents[$this->_section]);
101: } else {
102: $values = array();
103: foreach ($contents as $section => $attribs) {
104: if (is_array($attribs)) {
105: $values[$section] = $this->_parseNestedValues($attribs);
106: } else {
107: $parse = $this->_parseNestedValues(array($attribs));
108: $values[$section] = array_shift($parse);
109: }
110: }
111: }
112: return $values;
113: }
114:
115: /**
116: * parses nested values out of keys.
117: *
118: * @param array $values Values to be exploded.
119: * @return array Array of values exploded
120: */
121: protected function _parseNestedValues($values) {
122: foreach ($values as $key => $value) {
123: if ($value === '1') {
124: $value = true;
125: }
126: if ($value === '') {
127: $value = false;
128: }
129: if (strpos($key, '.') !== false) {
130: $values = Set::insert($values, $key, $value);
131: } else {
132: $values[$key] = $value;
133: }
134: }
135: return $values;
136: }
137: }
138: