Passed
Push — master ( 79149c...dd37f9 )
by Richard
05:12 queued 11s
created

Config_File   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 351
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 56
eloc 139
dl 0
loc 351
rs 5.5199
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A get_section_names() 0 9 2
B get() 0 28 8
A _trigger_error_msg() 0 3 1
A load_file() 0 19 5
B _set_config_var() 0 26 9
A get_file_names() 0 3 1
A get_key() 0 5 1
A clear() 0 6 3
A get_var_names() 0 14 4
A set_path() 0 12 6
A set_file_contents() 0 4 1
C parse_contents() 0 71 13

How to fix   Complexity   

Complex Class

Complex classes like Config_File often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Config_File, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Config_File class.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 *
20
 * For questions, help, comments, discussion, etc., please join the
21
 * Smarty mailing list. Send a blank e-mail to
22
 * [email protected] 
23
 *
24
 * @link http://www.smarty.net/
25
 * @version 2.6.25-dev
26
 * @copyright Copyright: 2001-2005 New Digital Group, Inc.
27
 * @author Andrei Zmievski <[email protected]>
28
 * @access public
29
 * @package Smarty
30
 */
31
32
/* $Id$ */
33
34
/**
35
 * Config file reading class
36
 * @package Smarty
37
 */
38
class Config_File {
39
    /**#@+
40
     * Options
41
     * @var boolean
42
     */
43
    /**
44
     * Controls whether variables with the same name overwrite each other.
45
     */
46
    var $overwrite        =    true;
47
48
    /**
49
     * Controls whether config values of on/true/yes and off/false/no get
50
     * converted to boolean values automatically.
51
     */
52
    var $booleanize        =    true;
53
54
    /**
55
     * Controls whether hidden config sections/vars are read from the file.
56
     */
57
    var $read_hidden     =    true;
58
59
    /**
60
     * Controls whether or not to fix mac or dos formatted newlines.
61
     * If set to true, \r or \r\n will be changed to \n.
62
     */
63
    var $fix_newlines =    true;
64
    /**#@-*/
65
66
    /** @access private */
67
    var $_config_path    = "";
68
    var $_config_data    = array();
69
    /**#@-*/
70
71
    /**
72
     * Constructs a new config file class.
73
     *
74
     * @param string $config_path (optional) path to the config files
75
     */
76
    public function __construct($config_path = NULL)
77
    {
78
        if (isset($config_path))
79
            $this->set_path($config_path);
80
    }
81
82
83
    /**
84
     * Set the path where configuration files can be found.
85
     *
86
     * @param string $config_path path to the config files
87
     */
88
    function set_path($config_path)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
89
    {
90
        if (!empty($config_path)) {
91
            if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) {
0 ignored issues
show
introduced by
The condition is_string($config_path) is always true.
Loading history...
92
                $this->_trigger_error_msg("Bad config file path '$config_path'");
93
                return;
94
            }
95
            if(substr($config_path, -1) != DIRECTORY_SEPARATOR) {
96
                $config_path .= DIRECTORY_SEPARATOR;
97
            }
98
99
            $this->_config_path = $config_path;
100
        }
101
    }
102
103
104
    /**
105
     * Retrieves config info based on the file, section, and variable name.
106
     *
107
     * @param string $file_name config file to get info for
108
     * @param string $section_name (optional) section to get info for
109
     * @param string $var_name (optional) variable to get info for
110
     * @return string|array a value or array of values
111
     */
112
    function get($file_name, $section_name = NULL, $var_name = NULL)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
113
    {
114
        if (empty($file_name)) {
115
            $this->_trigger_error_msg('Empty config file name');
116
            return;
117
        } else {
118
            $file_name = $this->_config_path . $file_name;
119
            if (!isset($this->_config_data[$file_name]))
120
                $this->load_file($file_name, false);
121
        }
122
123
        if (!empty($var_name)) {
124
            if (empty($section_name)) {
125
                return $this->_config_data[$file_name]["vars"][$var_name];
126
            } else {
127
                if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]))
128
                    return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name];
129
                else
130
                    return array();
131
            }
132
        } else {
133
            if (empty($section_name)) {
134
                return (array)$this->_config_data[$file_name]["vars"];
135
            } else {
136
                if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"]))
137
                    return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"];
138
                else
139
                    return array();
140
            }
141
        }
142
    }
143
144
145
    /**
146
     * Retrieves config info based on the key.
147
     *
148
     * @param $file_name string config key (filename/section/var)
149
     * @return string|array same as get()
150
     * @uses get() retrieves information from config file and returns it
151
     */
152
    function &get_key($config_key)
153
    {
154
        list($file_name, $section_name, $var_name) = explode('/', $config_key, 3);
155
        $result = &$this->get($file_name, $section_name, $var_name);
156
        return $result;
157
    }
158
159
    /**
160
     * Get all loaded config file names.
161
     *
162
     * @return array an array of loaded config file names
163
     */
164
    function get_file_names()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
165
    {
166
        return array_keys($this->_config_data);
167
    }
168
169
170
    /**
171
     * Get all section names from a loaded file.
172
     *
173
     * @param string $file_name config file to get section names from
174
     * @return array an array of section names from the specified file
175
     */
176
    function get_section_names($file_name)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
177
    {
178
        $file_name = $this->_config_path . $file_name;
179
        if (!isset($this->_config_data[$file_name])) {
180
            $this->_trigger_error_msg("Unknown config file '$file_name'");
181
            return;
182
        }
183
184
        return array_keys($this->_config_data[$file_name]["sections"]);
185
    }
186
187
188
    /**
189
     * Get all global or section variable names.
190
     *
191
     * @param string $file_name config file to get info for
192
     * @param string $section_name (optional) section to get info for
193
     * @return array an array of variables names from the specified file/section
194
     */
195
    function get_var_names($file_name, $section = NULL)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
196
    {
197
        if (empty($file_name)) {
198
            $this->_trigger_error_msg('Empty config file name');
199
            return;
200
        } else if (!isset($this->_config_data[$file_name])) {
201
            $this->_trigger_error_msg("Unknown config file '$file_name'");
202
            return;
203
        }
204
205
        if (empty($section))
206
            return array_keys($this->_config_data[$file_name]["vars"]);
207
        else
208
            return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]);
209
    }
210
211
212
    /**
213
     * Clear loaded config data for a certain file or all files.
214
     *
215
     * @param string $file_name file to clear config data for
216
     */
217
    function clear($file_name = NULL)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
218
    {
219
        if ($file_name === NULL)
220
            $this->_config_data = array();
221
        else if (isset($this->_config_data[$file_name]))
222
            $this->_config_data[$file_name] = array();
223
    }
224
225
226
    /**
227
     * Load a configuration file manually.
228
     *
229
     * @param string $file_name file name to load
230
     * @param boolean $prepend_path whether current config path should be
231
     *                              prepended to the filename
232
     */
233
    function load_file($file_name, $prepend_path = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
234
    {
235
        if ($prepend_path && $this->_config_path != "")
236
            $config_file = $this->_config_path . $file_name;
237
        else
238
            $config_file = $file_name;
239
240
        ini_set('track_errors', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $newvalue of ini_set(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

240
        ini_set('track_errors', /** @scrutinizer ignore-type */ true);
Loading history...
241
        $fp = @fopen($config_file, "r");
242
        if (!is_resource($fp)) {
243
            $this->_trigger_error_msg("Could not open config file '$config_file'");
244
            return false;
245
        }
246
247
        $contents = ($size = filesize($config_file)) ? fread($fp, $size) : '';
248
        fclose($fp);
249
250
        $this->_config_data[$config_file] = $this->parse_contents($contents);
251
        return true;
252
    }
253
254
    /**
255
     * Store the contents of a file manually.
256
     *
257
     * @param string $config_file file name of the related contents
258
     * @param string $contents the file-contents to parse
259
     */
260
    function set_file_contents($config_file, $contents)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
261
    {
262
        $this->_config_data[$config_file] = $this->parse_contents($contents);
263
        return true;
264
    }
265
266
    /**
267
     * parse the source of a configuration file manually.
268
     *
269
     * @param string $contents the file-contents to parse
270
     */
271
    function parse_contents($contents)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
272
    {
273
        if($this->fix_newlines) {
274
            // fix mac/dos formatted newlines
275
            $contents = preg_replace('!\r\n?!', "\n", $contents);
276
        }
277
278
        $config_data = array();
279
        $config_data['sections'] = array();
280
        $config_data['vars'] = array();
281
282
        /* reference to fill with data */
283
        $vars =& $config_data['vars'];
284
285
        /* parse file line by line */
286
        preg_match_all('!^.*\r?\n?!m', $contents, $match);
287
        $lines = $match[0];
288
        for ($i=0, $count=count($lines); $i<$count; $i++) {
289
            $line = $lines[$i];
290
            if (empty($line)) continue;
291
292
            if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) {
293
                /* section found */
294
                if (substr($match[1], 0, 1) == '.') {
295
                    /* hidden section */
296
                    if ($this->read_hidden) {
297
                        $section_name = substr($match[1], 1);
298
                    } else {
299
                        /* break reference to $vars to ignore hidden section */
300
                        unset($vars);
301
                        $vars = array();
302
                        continue;
303
                    }
304
                } else {                    
305
                    $section_name = $match[1];
306
                }
307
                if (!isset($config_data['sections'][$section_name]))
308
                    $config_data['sections'][$section_name] = array('vars' => array());
309
                $vars =& $config_data['sections'][$section_name]['vars'];
310
                continue;
311
            }
312
313
            if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) {
314
                /* variable found */
315
                $var_name = rtrim($match[1]);
316
                if (strpos($match[2], '"""') === 0) {
317
                    /* handle multiline-value */
318
                    $lines[$i] = substr($match[2], 3);
319
                    $var_value = '';
320
                    while ($i<$count) {
321
                        if (($pos = strpos($lines[$i], '"""')) === false) {
322
                            $var_value .= $lines[$i++];
323
                        } else {
324
                            /* end of multiline-value */
325
                            $var_value .= substr($lines[$i], 0, $pos);
326
                            break;
327
                        }
328
                    }
329
                    $booleanize = false;
330
331
                } else {
332
                    /* handle simple value */
333
                    $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2]));
334
                    $booleanize = $this->booleanize;
335
336
                }
337
                $this->_set_config_var($vars, $var_name, $var_value, $booleanize);
338
            }
339
            /* else unparsable line / means it is a comment / means ignore it */
340
        }
341
        return $config_data;
342
    }
343
344
    /**#@+ @access private */
345
    /**
346
     * @param array &$container
347
     * @param string $var_name
348
     * @param mixed $var_value
349
     * @param boolean $booleanize determines whether $var_value is converted to
350
     *                            to true/false
351
     */
352
    function _set_config_var(&$container, $var_name, $var_value, $booleanize)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
353
    {
354
        if (substr($var_name, 0, 1) == '.') {
355
            if (!$this->read_hidden)
356
                return;
357
            else
358
                $var_name = substr($var_name, 1);
359
        }
360
361
        if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) {
362
            $this->_trigger_error_msg("Bad variable name '$var_name'");
363
            return;
364
        }
365
366
        if ($booleanize) {
367
            if (preg_match("/^(on|true|yes)$/i", $var_value))
368
                $var_value = true;
369
            else if (preg_match("/^(off|false|no)$/i", $var_value))
370
                $var_value = false;
371
        }
372
373
        if (!isset($container[$var_name]) || $this->overwrite)
374
            $container[$var_name] = $var_value;
375
        else {
376
            settype($container[$var_name], 'array');
377
            $container[$var_name][] = $var_value;
378
        }
379
    }
380
381
    /**
382
     * @uses trigger_error() creates a PHP warning/error
383
     * @param string $error_msg
384
     * @param integer $error_type one of
385
     */
386
    function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
387
    {
388
        trigger_error("Config_File error: $error_msg", $error_type);
389
    }
390
    /**#@-*/
391
}
392
393
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
394