Configuration::__construct()   F
last analyzed

Complexity

Conditions 35
Paths 434

Size

Total Lines 139
Code Lines 93

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 85
CRAP Score 36.4302

Importance

Changes 0
Metric Value
cc 35
eloc 93
nc 434
nop 0
dl 0
loc 139
ccs 85
cts 95
cp 0.8947
crap 36.4302
rs 0.7861
c 0
b 0
f 0

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.7.2
11
 */
12
13
namespace PrivateBin;
14
15
use Exception;
16
use PDO;
17
18
/**
19
 * Configuration
20
 *
21
 * parses configuration file, ensures default values present
22
 */
23
class Configuration
24
{
25
    /**
26
     * parsed configuration
27
     *
28
     * @var array
29
     */
30
    private $_configuration;
31
32
    /**
33
     * default configuration
34
     *
35
     * @var array
36
     */
37
    private static $_defaults = array(
38
        'main' => array(
39
            'name'                     => 'PrivateBin',
40
            'basepath'                 => '',
41
            'discussion'               => true,
42
            'opendiscussion'           => false,
43
            'discussiondatedisplay'    => true,
44
            'password'                 => true,
45
            'fileupload'               => false,
46
            'burnafterreadingselected' => false,
47
            'defaultformatter'         => 'plaintext',
48
            'syntaxhighlightingtheme'  => '',
49
            'sizelimit'                => 10485760,
50
            'template'                 => 'bootstrap',
51
            'info'                     => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
52
            'notice'                   => '',
53
            'languageselection'        => false,
54
            'languagedefault'          => '',
55
            'urlshortener'             => '',
56
            'qrcode'                   => true,
57
            'email'                    => true,
58
            'icon'                     => 'identicon',
59
            'cspheader'                => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
60
            'zerobincompatibility'     => false,
61
            'httpwarning'              => true,
62
            'compression'              => 'zlib',
63
        ),
64
        'expire' => array(
65
            'default' => '1week',
66
        ),
67
        'expire_options' => array(
68
            '5min'   => 300,
69
            '10min'  => 600,
70
            '1hour'  => 3600,
71
            '1day'   => 86400,
72
            '1week'  => 604800,
73
            '1month' => 2592000,
74
            '1year'  => 31536000,
75
            'never'  => 0,
76
        ),
77
        'formatter_options' => array(
78
            'plaintext'          => 'Plain Text',
79
            'syntaxhighlighting' => 'Source Code',
80
            'markdown'           => 'Markdown',
81
        ),
82
        'traffic' => array(
83
            'limit'     => 10,
84
            'header'    => '',
85
            'exempted'  => '',
86
            'creators'  => '',
87
        ),
88
        'purge' => array(
89
            'limit'     => 300,
90
            'batchsize' => 10,
91
        ),
92
        'model' => array(
93
            'class' => 'Filesystem',
94
        ),
95
        'model_options' => array(
96
            'dir' => 'data',
97
        ),
98
        'yourls' => array(
99
            'signature' => '',
100
            'apiurl'    => '',
101
        ),
102
    );
103
104
    /**
105
     * parse configuration file and ensure default configuration values are present
106
     *
107
     * @throws Exception
108
     */
109 163
    public function __construct()
110
    {
111 163
        $basePaths  = array();
112 163
        $config     = array();
113 163
        $configPath = getenv('CONFIG_PATH');
114 163
        if ($configPath !== false && !empty($configPath)) {
115 1
            $basePaths[] = $configPath;
116
        }
117 163
        $basePaths[] = PATH . 'cfg';
118 163
        foreach ($basePaths as $basePath) {
119 163
            $configFile = $basePath . DIRECTORY_SEPARATOR . 'conf.php';
120 163
            if (is_readable($configFile)) {
121 161
                $config = parse_ini_file($configFile, true);
122 161
                foreach (array('main', 'model', 'model_options') as $section) {
123 161
                    if (!array_key_exists($section, $config)) {
124 4
                        throw new Exception(I18n::_('PrivateBin requires configuration section [%s] to be present in configuration file.', $section), 2);
125
                    }
126
                }
127 157
                break;
128
            }
129
        }
130
131 159
        $opts = '_options';
132 159
        foreach (self::getDefaults() as $section => $values) {
133
            // fill missing sections with default values
134 159
            if (!array_key_exists($section, $config) || count($config[$section]) == 0) {
135 147
                $this->_configuration[$section] = $values;
136 147
                if (array_key_exists('dir', $this->_configuration[$section])) {
137 6
                    $this->_configuration[$section]['dir'] = PATH . $this->_configuration[$section]['dir'];
138
                }
139 147
                continue;
140
            }
141
            // provide different defaults for database model
142
            elseif (
143 153
                $section == 'model_options' && in_array(
144 153
                    $this->_configuration['model']['class'],
145 153
                    array('Database', 'privatebin_db', 'zerobin_db')
146 153
                )
147
            ) {
148 58
                $values = array(
149 58
                    'dsn' => 'sqlite:' . PATH . 'data' . DIRECTORY_SEPARATOR . 'db.sq3',
150 58
                    'tbl' => null,
151 58
                    'usr' => null,
152 58
                    'pwd' => null,
153 58
                    'opt' => array(PDO::ATTR_PERSISTENT => true),
154 58
                );
155
            } elseif (
156 153
                $section == 'model_options' && in_array(
157 153
                    $this->_configuration['model']['class'],
158 153
                    array('GoogleCloudStorage')
159 153
                )
160
            ) {
161 36
                $values = array(
162 36
                    'bucket'     => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
163 36
                    'prefix'     => 'pastes',
164 36
                    'uniformacl' => false,
165 36
                );
166
            } elseif (
167 153
                $section == 'model_options' && in_array(
168 153
                    $this->_configuration['model']['class'],
169 153
                    array('S3Storage')
170 153
                )
171
            ) {
172
                $values = array(
173
                    'region'                  => null,
174
                    'version'                 => null,
175
                    'endpoint'                => null,
176
                    'accesskey'               => null,
177
                    'secretkey'               => null,
178
                    'use_path_style_endpoint' => null,
179
                    'bucket'                  => null,
180
                    'prefix'                  => '',
181
                );
182
            }
183
184
            // "*_options" sections don't require all defaults to be set
185
            if (
186 153
                $section !== 'model_options' &&
187 153
                ($from = strlen($section) - strlen($opts)) >= 0 &&
188 153
                strpos($section, $opts, $from) !== false
189
            ) {
190 153
                if (is_int(current($values))) {
191 153
                    $config[$section] = array_map('intval', $config[$section]);
192
                }
193 153
                $this->_configuration[$section] = $config[$section];
194
            }
195
            // check for missing keys and set defaults if necessary
196
            else {
197 153
                foreach ($values as $key => $val) {
198 153
                    if ($key == 'dir') {
199 60
                        $val = PATH . $val;
200
                    }
201 153
                    $result = $val;
202 153
                    if (array_key_exists($key, $config[$section])) {
203 153
                        if ($val === null) {
204 36
                            $result = $config[$section][$key];
205 153
                        } elseif (is_bool($val)) {
206 153
                            $val = strtolower($config[$section][$key]);
207 153
                            if (in_array($val, array('true', 'yes', 'on'))) {
208 1
                                $result = true;
209 153
                            } elseif (in_array($val, array('false', 'no', 'off'))) {
210 2
                                $result = false;
211
                            } else {
212 153
                                $result = (bool) $config[$section][$key];
213
                            }
214 153
                        } elseif (is_int($val)) {
215 153
                            $result = (int) $config[$section][$key];
216 153
                        } elseif (is_string($val) && !empty($config[$section][$key])) {
217 153
                            $result = (string) $config[$section][$key];
218
                        }
219
                    }
220 153
                    $this->_configuration[$section][$key] = $result;
221
                }
222
            }
223
        }
224
225
        // support for old config file format, before the fork was renamed and PSR-4 introduced
226 159
        $this->_configuration['model']['class'] = str_replace(
227 159
            'zerobin_', 'privatebin_',
228 159
            $this->_configuration['model']['class']
229 159
        );
230
231 159
        $this->_configuration['model']['class'] = str_replace(
232 159
            array('privatebin_data', 'privatebin_db'),
233 159
            array('Filesystem', 'Database'),
234 159
            $this->_configuration['model']['class']
235 159
        );
236
237
        // ensure a valid expire default key is set
238 159
        if (!array_key_exists($this->_configuration['expire']['default'], $this->_configuration['expire_options'])) {
239 1
            $this->_configuration['expire']['default'] = key($this->_configuration['expire_options']);
240
        }
241
242
        // ensure the basepath ends in a slash, if one is set
243
        if (
244 159
            !empty($this->_configuration['main']['basepath']) &&
245 159
            substr_compare($this->_configuration['main']['basepath'], '/', -1) !== 0
246
        ) {
247 3
            $this->_configuration['main']['basepath'] .= '/';
248
        }
249
    }
250
251
    /**
252
     * get configuration as array
253
     *
254
     * @return array
255
     */
256 6
    public function get()
257
    {
258 6
        return $this->_configuration;
259
    }
260
261
    /**
262
     * get default configuration as array
263
     *
264
     * @return array
265
     */
266 160
    public static function getDefaults()
267
    {
268 160
        return self::$_defaults;
269
    }
270
271
    /**
272
     * get a key from the configuration, typically the main section or all keys
273
     *
274
     * @param string $key
275
     * @param string $section defaults to main
276
     * @throws Exception
277
     * @return mixed
278
     */
279 152
    public function getKey($key, $section = 'main')
280
    {
281 152
        $options = $this->getSection($section);
282 152
        if (!array_key_exists($key, $options)) {
283 1
            throw new Exception(I18n::_('Invalid data.') . " $section / $key", 4);
284
        }
285 151
        return $this->_configuration[$section][$key];
286
    }
287
288
    /**
289
     * get a section from the configuration, must exist
290
     *
291
     * @param string $section
292
     * @throws Exception
293
     * @return mixed
294
     */
295 152
    public function getSection($section)
296
    {
297 152
        if (!array_key_exists($section, $this->_configuration)) {
298 1
            throw new Exception(I18n::_('%s requires configuration section [%s] to be present in configuration file.', I18n::_($this->getKey('name')), $section), 3);
299
        }
300 152
        return $this->_configuration[$section];
301
    }
302
}
303