GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 5018c7...c440df )
by Miles
03:57
created

ValueParser::isNumber()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * This file is part of the m1\env library
5
 *
6
 * (c) m1 <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @package     m1/env
12
 * @version     0.2.0
13
 * @author      Miles Croxford <[email protected]>
14
 * @copyright   Copyright (c) Miles Croxford <[email protected]>
15
 * @license     http://github.com/m1/env/blob/master/LICENSE.md
16
 * @link        http://github.com/m1/env/blob/master/README.md Documentation
17
 */
18
19
namespace M1\Env\Parser;
20
21
use M1\Env\Exception\ParseException;
22
23
/**
24
 * The value parser for Env
25
 *
26
 * @since 0.2.0
27
 */
28
class ValueParser extends AbstractParser
29
{
30
    /**
31
     * The regex to get variables '$(VARIABLE)' in .env
32
     * Unescaped: ${(.*?)}
33
     *
34
     * @var string REGEX_ENV_VARIABLE
35
     */
36
    const REGEX_ENV_VARIABLE = '\\${(.*?)}';
37
38
    /**
39
     * The regex to get the content between double quote (") strings, ignoring escaped quotes.
40
     * Unescaped: "(?:[^"\\]*(?:\\.)?)*"
41
     *
42
     * @var string REGEX_QUOTE_DOUBLE_STRING
43
     */
44
    const REGEX_QUOTE_DOUBLE_STRING = '"(?:[^\"\\\\]*(?:\\\\.)?)*\"';
45
46
    /**
47
     * The regex to get the content between single quote (') strings, ignoring escaped quotes
48
     * Unescaped: '(?:[^'\\]*(?:\\.)?)*'
49
     *
50
     * @var string REGEX_QUOTE_SINGLE_STRING
51
     */
52
    const REGEX_QUOTE_SINGLE_STRING = "'(?:[^'\\\\]*(?:\\\\.)?)*'";
53
54
    /**
55
     * The bool variants available in .env
56
     *
57
     * @var array $bool_variants
58
     */
59
    private static $bool_variants = array(
60
        'true', 'false', 'yes', 'no'
61
    );
62
63
    /**
64
     * The map to convert escaped characters into real characters
65
     *
66
     * @var array $character_map
67
     */
68
    private static $character_map = array(
69
        "\\n" => "\n",
70
        "\\\"" => "\"",
71
        '\\\'' => "'",
72
        '\\t' => "\t"
73
    );
74
75
    /**
76
     * The line num of the current value
77
     *
78
     * @var int $line_num
79
     */
80
    private $line_num;
81
82
    /**
83
     * The current parsed values/lines
84
     *
85
     * @var array $lines
86
     */
87
    private $lines;
88
89
    /**
90
     * Parses a .env value
91
     *
92
     * @param string $value    The value to parse
93
     * @param array  $lines    The array of already parsed lines
94
     * @param int    $line_num The line num of the value
95
     *
96
     * @return string|null The parsed key, or null if the key is a comment
97
     */
98 30
    public function parse($value, $lines, $line_num)
99
    {
100 30
        $this->lines = $lines;
101 30
        $this->line_num = $line_num;
102
103 30
        $value = trim($value);
104
105 30
        if ($this->startsWith('#', $value)) {
106 3
            return null;
107
        }
108
109 30
        if ($this->isString($value)) {
110 12
            $value = $this->parseString($value);
111 9
            $value = $this->parseVariables($value, true);
112
113 9
        } else {
114 27
            $value = $this->stripComments($value);
115
116 27
            if ($this->isBool($value)) {
117 6
                $value = $this->parseBool($value);
118
119 27
            } elseif ($this->isNumber($value)) {
120 6
                $value = $this->parseNumber($value);
121
122 24
            } elseif ($this->isNull($value)) {
123 3
                $value = null;
124
125 3
            } else {
126 24
                $value = $this->parseUnquotedString($value);
127 24
                $value = $this->parseVariables($value);
128
129
            }
130
        }
131
132 24
        return $value;
133
    }
134
135
    /**
136
     * Parses a .env variable
137
     *
138
     * @param string $value         The value to parse
139
     * @param bool   $quoted_string Is the value in a quoted string
140
     *
141
     * @return string The parsed value
142
     */
143 24
    private function parseVariables($value, $quoted_string = false)
144
    {
145 24
        $matches = $this->fetchVariableMatches($value);
146
147 24
        if (is_array($matches)) {
148 6
            $replacements = array();
149
150 6
            if ($this->isVariableClone($value, $matches, $quoted_string)) {
151 6
                return $this->fetchVariable($value, $matches[1][0], $matches, $quoted_string);
152
            }
153
154 3
            for ($i = 0; $i <= (count($matches[0]) - 1); $i++) {
155 3
                $replacement = $this->fetchVariable($value, $matches[1][$i], $matches, $quoted_string);
156 3
                $replacements[$matches[0][$i]] = $replacement;
157 3
            }
158
159 3
            if (!empty($replacements)) {
160 3
                $value = strtr($value, $replacements);
161 3
            }
162 3
        }
163
164 21
        return $value;
165
    }
166
167
    /**
168
     * Get variable matches inside a string
169
     *
170
     * @param string $value The value to parse
171
     *
172
     * @return array The variable matches
173
     */
174 24
    private function fetchVariableMatches($value)
175
    {
176 24
        preg_match_all('/'.self::REGEX_ENV_VARIABLE.'/', $value, $matches);
177
178 24
        if (!is_array($matches) || !isset($matches[0]) || empty($matches[0])) {
179 21
            return false;
180
        }
181
182 6
        return $matches;
183
    }
184
185
    /**
186
     * Parses a .env variable
187
     *
188
     * @param string $value         The value to parse
189
     * @param string $variable_name The variable name to get
190
     * @param array  $matches       The matches of the variables
191
     * @param bool   $quoted_string Is the value in a quoted string
192
     *
193
     * @throws \M1\Env\Exception\ParseException If the variable can not be found
194
     *
195
     * @return string The parsed value
196
     */
197 6
    private function fetchVariable($value, $variable_name, $matches, $quoted_string)
198
    {
199
200 6
        if (!isset($this->lines[$variable_name])) {
201 3
            throw new ParseException(
202 3
                sprintf('Variable has not been defined: %s', $variable_name),
203 3
                $this->origin_exception,
204 3
                $this->file,
205 3
                $value,
206 3
                $this->line_num
207 3
            );
208
        }
209
210 3
        $replacement = $this->lines[$variable_name];
211
212 3
        if (is_bool($replacement) &&
213 3
            ($quoted_string || count($matches[0]) >= 2)) {
214 3
            $replacement = ($replacement) ? 'true' : 'false';
215 3
        }
216
217 3
        return $replacement;
218
    }
219
220
    /**
221
     * Parses a .env string
222
     *
223
     * @param string $value    The value to parse
224
     *
225
     * @throws \M1\Env\Exception\ParseException If the string has a missing end quote
226
     *
227
     * @return string The parsed string
228
     */
229 12
    private function parseString($value)
230
    {
231 12
        if ($this->startsWith('\'', $value)) {
232 9
            $regex =  self::REGEX_QUOTE_SINGLE_STRING;
233 9
            $symbol = "'";
234 9
        } else {
235 6
            $regex = self::REGEX_QUOTE_DOUBLE_STRING;
236 6
            $symbol = '"';
237
        }
238
239 12
        if (!preg_match('/'.$regex.'/', $value, $matches)) {
240 3
            throw new ParseException(
241 3
                sprintf('Missing end %s quote', $symbol),
242 3
                $this->origin_exception,
243 3
                $this->file,
244 3
                $value,
245 3
                $this->line_num
246 3
            );
247
        }
248
249 9
        $value = trim($matches[0], $symbol);
250 9
        $value = strtr($value, self::$character_map);
251
252 9
        return $value;
253
    }
254
255
    /**
256
     * Parses a .env unquoted string
257
     *
258
     * @param string $value The value to parse
259
     *
260
     * @return string The parsed string
261
     */
262 24
    private function parseUnquotedString($value)
263
    {
264 24
        if ($value == "") {
265 3
            return null;
266
        }
267
268 21
        return $value;
269
    }
270
271
    /**
272
     * Parses a .env bool
273
     *
274
     * @param string $value The value to parse
275
     *
276
     * @return bool The parsed bool
277
     */
278 6
    private function parseBool($value)
279
    {
280 6
        switch (strtolower($value)) {
281 6
            case 'true':
282 6
            case 'yes':
283 6
                $value = true;
284 6
                break;
285 3
            case 'false':
286 3
            case 'no':
287 3
            default:
288 3
                $value = false;
289 3
                break;
290 6
        }
291
292 6
        return $value;
293
    }
294
295
    /**
296
     * Parses a .env number
297
     *
298
     * @param string $value The value to parse
299
     *
300
     * @return int|float The parsed bool
301
     */
302 6
    private function parseNumber($value)
303
    {
304 6
        if (strpos($value, '.') !== false) {
305 6
            return (float) $value;
306
        }
307
308 6
        return (int) $value;
309
    }
310
311
    /**
312
     * Strips comments from a value
313
     *
314
     * @param string $value The value to strip comments from
315
     *
316
     * @return string value
317
     */
318 27
    private function stripComments($value)
319
    {
320 27
        return trim(explode("#", $value, 2)[0]);
321
    }
322
323
    /**
324
     * Returns if value is a string
325
     *
326
     * @param string $value The value to test
327
     *
328
     * @return bool Is a value a string
329
     */
330 30
    private function isString($value)
331
    {
332 30
        return $this->startsWith('\'', $value) || $this->startsWith('"', $value);
333
    }
334
335
    /**
336
     * Returns if value is a bool
337
     *
338
     * @param string $value The value to test
339
     *
340
     * @return bool Is a value a bool
341
     */
342 27
    private function isBool($value)
343
    {
344 27
        return in_array(strtolower($value), self::$bool_variants);
345
    }
346
347
    /**
348
     * Returns if value is number
349
     *
350
     * @param string $value The value to test
351
     *
352
     * @return bool Is a value a number
353
     */
354 24
    private function isNumber($value)
355
    {
356 24
        return is_numeric($value);
357
    }
358
359
    /**
360
     * Returns if value is null
361
     *
362
     * @param string $value The value to test
363
     *
364
     * @return bool Is a value null
365
     */
366 24
    private function isNull($value)
367
    {
368 24
        return $value === 'null';
369
    }
370
371
    /**
372
     * Returns if variable value is a clone, e.g. BOOL = $(BOOL_1)
373
     *
374
     * @param string $value         The value to test
375
     * @param array  $matches       The matches of the variables
376
     * @param bool   $quoted_string If the value is in a quoted string
377
     *
378
     * @return bool Is a value null
379
     */
380 6
    private function isVariableClone($value, $matches, $quoted_string)
381
    {
382 6
        return count($matches[0] === 1) && $value == $matches[0][0] && !$quoted_string;
383
    }
384
}