Passed
Push — master ( 81ac23...a5d5f6 )
by El
03:02
created

Configuration::__construct()   D

Complexity

Conditions 27
Paths 111

Size

Total Lines 110
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 60
CRAP Score 27

Importance

Changes 0
Metric Value
dl 0
loc 110
ccs 60
cts 60
cp 1
rs 4.3724
c 0
b 0
f 0
cc 27
eloc 68
nc 111
nop 0
crap 27

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * PrivateBin
4
 *
5
 * a zero-knowledge paste bin
6
 *
7
 * @link      https://github.com/PrivateBin/PrivateBin
8
 * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
9
 * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
10
 * @version   1.1.1
11
 */
12
13
namespace PrivateBin;
14
15
use PrivateBin\Persistence\DataStore;
16
use Exception;
17
use PDO;
18
19
/**
20
 * Configuration
21
 *
22
 * parses configuration file, ensures default values present
23
 */
24
class Configuration
25
{
26
    /**
27
     * parsed configuration
28
     *
29
     * @var array
30
     */
31
    private $_configuration;
32
33
    /**
34
     * default configuration
35
     *
36
     * @var array
37
     */
38
    private static $_defaults = array(
39
        'main' => array(
40
            'name'                     => 'PrivateBin',
41
            'discussion'               => true,
42
            'opendiscussion'           => false,
43
            'password'                 => true,
44
            'fileupload'               => false,
45
            'burnafterreadingselected' => false,
46
            'instantburnafterreading'  => false,
47
            'defaultformatter'         => 'plaintext',
48
            'syntaxhighlightingtheme'  => null,
49
            'sizelimit'                => 2097152,
50
            'template'                 => 'bootstrap',
51
            'notice'                   => '',
52
            'languageselection'        => false,
53
            'languagedefault'          => '',
54
            'urlshortener'             => '',
55
            'icon'                     => 'identicon',
56
            'cspheader'                => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; referrer no-referrer; sandbox allow-same-origin allow-scripts allow-forms allow-popups',
57
            'zerobincompatibility'     => false,
58
        ),
59
        'expire' => array(
60
            'default' => '1week',
61
            'clone'   => true,
62
        ),
63
        'expire_options' => array(
64
            '5min'   => 300,
65
            '10min'  => 600,
66
            '1hour'  => 3600,
67
            '1day'   => 86400,
68
            '1week'  => 604800,
69
            '1month' => 2592000,
70
            '1year'  => 31536000,
71
            'never'  => 0,
72
        ),
73
        'formatter_options' => array(
74
            'plaintext'          => 'Plain Text',
75
            'syntaxhighlighting' => 'Source Code',
76
            'markdown'           => 'Markdown',
77
        ),
78
        'traffic' => array(
79
            'limit'  => 10,
80
            'header' => null,
81
            'dir'    => 'data',
82
        ),
83
        'purge' => array(
84
            'limit'     => 300,
85
            'batchsize' => 10,
86
            'dir'       => 'data',
87
        ),
88
        'model' => array(
89
            'class' => 'Filesystem',
90
        ),
91
        'model_options' => array(
92
            'dir' => 'data',
93
        ),
94
    );
95
96
    /**
97
     * parse configuration file and ensure default configuration values are present
98
     *
99
     * @throws Exception
100
     */
101 127
    public function __construct()
102
    {
103 127
        $config     = array();
104 127
        $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php';
105 127
        $configIni  = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
106
107
        // rename INI files to avoid configuration leakage
108 127
        if (is_readable($configIni)) {
109 2
            DataStore::prependRename($configIni, $configFile, ';');
110
111
            // cleanup sample, too
112 2
            $configIniSample = $configIni . '.sample';
113 2
            if (is_readable($configIniSample)) {
114 2
                DataStore::prependRename($configIniSample, PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php', ';');
115
            }
116
        }
117
118 127
        if (is_readable($configFile)) {
119 125
            $config = parse_ini_file($configFile, true);
120 125
            foreach (array('main', 'model', 'model_options') as $section) {
121 125
                if (!array_key_exists($section, $config)) {
122 125
                    throw new Exception(I18n::_('PrivateBin requires configuration section [%s] to be present in configuration file.', $section), 2);
123
                }
124
            }
125
        }
126
127 124
        $opts = '_options';
128 124
        foreach (self::getDefaults() as $section => $values) {
129
            // fill missing sections with default values
130 124
            if (!array_key_exists($section, $config) || count($config[$section]) == 0) {
131 6
                $this->_configuration[$section] = $values;
132 6
                if (array_key_exists('dir', $this->_configuration[$section])) {
133 6
                    $this->_configuration[$section]['dir'] = PATH . $this->_configuration[$section]['dir'];
134
                }
135 6
                continue;
136
            }
137
            // provide different defaults for database model
138
            elseif (
139 118
                $section == 'model_options' && in_array(
140 118
                    $this->_configuration['model']['class'],
141 118
                    array('Database', 'privatebin_db', 'zerobin_db')
142
                )
143
            ) {
144
                $values = array(
145 60
                    'dsn' => 'sqlite:' . PATH . 'data' . DIRECTORY_SEPARATOR . 'db.sq3',
146
                    'tbl' => null,
147
                    'usr' => null,
148
                    'pwd' => null,
149
                    'opt' => array(PDO::ATTR_PERSISTENT => true),
150
                );
151
            }
152
153
            // "*_options" sections don't require all defaults to be set
154
            if (
155 118
                $section !== 'model_options' &&
156 118
                ($from = strlen($section) - strlen($opts)) >= 0 &&
157 118
                strpos($section, $opts, $from) !== false
158
            ) {
159 118
                if (is_int(current($values))) {
160 118
                    $config[$section] = array_map('intval', $config[$section]);
161
                }
162 118
                $this->_configuration[$section] = $config[$section];
163
            }
164
            // check for missing keys and set defaults if necessary
165
            else {
166 118
                foreach ($values as $key => $val) {
167 118
                    if ($key == 'dir') {
168 118
                        $val = PATH . $val;
169
                    }
170 118
                    $result = $val;
171 118
                    if (array_key_exists($key, $config[$section])) {
172 118
                        if ($val === null) {
173 3
                            $result = $config[$section][$key];
174 118
                        } elseif (is_bool($val)) {
175 118
                            $val = strtolower($config[$section][$key]);
176 118
                            if (in_array($val, array('true', 'yes', 'on'))) {
177 1
                                $result = true;
178 118
                            } elseif (in_array($val, array('false', 'no', 'off'))) {
179 1
                                $result = false;
180
                            } else {
181 118
                                $result = (bool) $config[$section][$key];
182
                            }
183 118
                        } elseif (is_int($val)) {
184 118
                            $result = (int) $config[$section][$key];
185 118
                        } elseif (is_string($val) && !empty($config[$section][$key])) {
186 118
                            $result = (string) $config[$section][$key];
187
                        }
188
                    }
189 118
                    $this->_configuration[$section][$key] = $result;
190
                }
191
            }
192
        }
193
194
        // support for old config file format, before the fork was renamed and PSR-4 introduced
195 124
        $this->_configuration['model']['class'] = str_replace(
196 124
            'zerobin_', 'privatebin_',
197 124
            $this->_configuration['model']['class']
198
        );
199
200 124
        $this->_configuration['model']['class'] = str_replace(
201 124
            array('privatebin_data', 'privatebin_db'),
202 124
            array('Filesystem', 'Database'),
203 124
            $this->_configuration['model']['class']
204
        );
205
206
        // ensure a valid expire default key is set
207 124
        if (!array_key_exists($this->_configuration['expire']['default'], $this->_configuration['expire_options'])) {
208 1
            $this->_configuration['expire']['default'] = key($this->_configuration['expire_options']);
209
        }
210 124
    }
211
212
    /**
213
     * get configuration as array
214
     *
215
     * return array
216
     */
217 6
    public function get()
218
    {
219 6
        return $this->_configuration;
220
    }
221
222
    /**
223
     * get default configuration as array
224
     *
225
     * return array
226
     */
227 125
    public static function getDefaults()
228
    {
229 125
        return self::$_defaults;
230
    }
231
232
    /**
233
     * get a key from the configuration, typically the main section or all keys
234
     *
235
     * @param string $key
236
     * @param string $section defaults to main
237
     * @throws Exception
238
     * return mixed
239
     */
240 116
    public function getKey($key, $section = 'main')
241
    {
242 116
        $options = $this->getSection($section);
243 116
        if (!array_key_exists($key, $options)) {
244 1
            throw new Exception(I18n::_('Invalid data.') . " $section / $key", 4);
245
        }
246 115
        return $this->_configuration[$section][$key];
247
    }
248
249
    /**
250
     * get a section from the configuration, must exist
251
     *
252
     * @param string $section
253
     * @throws Exception
254
     * return mixed
255
     */
256 116
    public function getSection($section)
257
    {
258 116
        if (!array_key_exists($section, $this->_configuration)) {
259 1
            throw new Exception(I18n::_('%s requires configuration section [%s] to be present in configuration file.', I18n::_($this->getKey('name')), $section), 3);
260
        }
261 116
        return $this->_configuration[$section];
262
    }
263
}
264