RegexChecker   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 43
dl 0
loc 89
rs 10
c 0
b 0
f 0
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A validateRegex() 0 10 2
A isValidDelimiter() 0 4 2
A isValidRegexFlags() 0 15 4
A isRegexLike() 0 28 5
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\Configuration;
16
17
use function array_pop;
18
use function count;
19
use function explode;
20
use function in_array;
21
use function preg_last_error;
22
use function preg_last_error_msg;
23
use function preg_match as native_preg_match;
24
use function Safe\sprintf;
25
use function str_split;
26
use function strlen;
27
28
final class RegexChecker
29
{
30
    // Some characters are best to not be allowed as regex delimiters in order
31
    // to not result in some fancy regexes
32
    // See https://github.com/humbug/php-scoper/issues/597
33
    private const INVALID_REGEX_DELIMITERS = [
34
        '\\',
35
        '_',
36
    ];
37
38
    // https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
39
    private const PATTERN_MODIFIERS = [
40
        'i',
41
        'm',
42
        's',
43
        'x',
44
        'A',
45
        'D',
46
        'S',
47
        'U',
48
        'X',
49
        'J',
50
        'u',
51
    ];
52
53
    public function isRegexLike(string $value): bool
54
    {
55
        $valueLength = strlen($value);
56
57
        if ($valueLength < 2) {
58
            return false;
59
        }
60
61
        /** @var non-empty-string $firstCharacter */
62
        $firstCharacter = $value[0];
63
64
        if (!self::isValidDelimiter($firstCharacter)) {
65
            return false;
66
        }
67
68
        $parts = explode($firstCharacter, $value);
69
70
        if (count($parts) !== 3) {
71
            return false;
72
        }
73
74
        $lastPart = array_pop($parts);
75
76
        if (!self::isValidRegexFlags($lastPart)) {
77
            return false;
78
        }
79
80
        return true;
81
    }
82
83
    public function validateRegex(string $regex): ?string
84
    {
85
        if (@native_preg_match($regex, '') !== false) {
86
            return null;
87
        }
88
89
        return sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

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

89
        return /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
90
            'Invalid regex: %s (code %s)',
91
            preg_last_error_msg(),
92
            preg_last_error(),
93
        );
94
    }
95
96
    private static function isValidDelimiter(string $delimiter): bool
97
    {
98
        return !in_array($delimiter, self::INVALID_REGEX_DELIMITERS, true)
99
            && native_preg_match('/^\p{L}$/u', $delimiter) === 0;
100
    }
101
102
    private static function isValidRegexFlags(string $value): bool
103
    {
104
        if ('' === $value) {
105
            return true;
106
        }
107
108
        $characters = str_split($value);
109
110
        foreach ($characters as $character) {
111
            if (!in_array($character, self::PATTERN_MODIFIERS, true)) {
112
                return false;
113
            }
114
        }
115
116
        return true;
117
    }
118
}
119