PluginProbe
TablePress – Tables in WordPress made easy / 3.2.1
TablePress – Tables in WordPress made easy v3.2.1
3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.4.4 All 44 releases
tablepress / libraries / vendor / composer / pcre / PHPStan / InvalidRegexPatternRule.php

InvalidRegexPatternRule.php in TablePress – Tables in WordPress made easy 3.2.1, at libraries/vendor/composer/pcre/PHPStan/InvalidRegexPatternRule.php

143 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types = 1);
2
3 namespace TablePress\Composer\Pcre\PHPStan;
4
5 use TablePress\Composer\Pcre\Preg;
6 use TablePress\Composer\Pcre\Regex;
7 use TablePress\Composer\Pcre\PcreException;
8 use Nette\Utils\RegexpException;
9 use Nette\Utils\Strings;
10 use PhpParser\Node;
11 use PhpParser\Node\Expr\StaticCall;
12 use PhpParser\Node\Name\FullyQualified;
13 use PHPStan\Analyser\Scope;
14 use PHPStan\Rules\Rule;
15 use PHPStan\Rules\RuleErrorBuilder;
16 use function in_array;
17 use function sprintf;
18
19 /**
20 * Copy of PHPStan's RegularExpressionPatternRule
21 *
22 * @implements Rule<StaticCall>
23 */
24 class InvalidRegexPatternRule implements Rule
25 {
26 public function getNodeType(): string
27 {
28 return StaticCall::class;
29 }
30
31 public function processNode(Node $node, Scope $scope): array
32 {
33 $patterns = $this->extractPatterns($node, $scope);
34
35 $errors = [];
36 foreach ($patterns as $pattern) {
37 $errorMessage = $this->validatePattern($pattern);
38 if ($errorMessage === null) {
39 continue;
40 }
41
42 $errors[] = RuleErrorBuilder::message(sprintf('Regex pattern is invalid: %s', $errorMessage))->identifier('regexp.pattern')->build();
43 }
44
45 return $errors;
46 }
47
48 /**
49 * @return string[]
50 */
51 private function extractPatterns(StaticCall $node, Scope $scope): array
52 {
53 if (!$node->class instanceof FullyQualified) {
54 return [];
55 }
56 $isRegex = $node->class->toString() === Regex::class;
57 $isPreg = $node->class->toString() === Preg::class;
58 if (!$isRegex && !$isPreg) {
59 return [];
60 }
61 if (!$node->name instanceof Node\Identifier || !Preg::isMatch('{^(match|isMatch|grep|replace|split)}', $node->name->name)) {
62 return [];
63 }
64
65 $functionName = $node->name->name;
66 if (!isset($node->getArgs()[0])) {
67 return [];
68 }
69
70 $patternNode = $node->getArgs()[0]->value;
71 $patternType = $scope->getType($patternNode);
72
73 $patternStrings = [];
74
75 foreach ($patternType->getConstantStrings() as $constantStringType) {
76 if ($functionName === 'replaceCallbackArray') {
77 continue;
78 }
79
80 $patternStrings[] = $constantStringType->getValue();
81 }
82
83 foreach ($patternType->getConstantArrays() as $constantArrayType) {
84 if (
85 in_array($functionName, [
86 'replace',
87 'replaceCallback',
88 ], true)
89 ) {
90 foreach ($constantArrayType->getValueTypes() as $arrayKeyType) {
91 foreach ($arrayKeyType->getConstantStrings() as $constantString) {
92 $patternStrings[] = $constantString->getValue();
93 }
94 }
95 }
96
97 if ($functionName !== 'replaceCallbackArray') {
98 continue;
99 }
100
101 foreach ($constantArrayType->getKeyTypes() as $arrayKeyType) {
102 foreach ($arrayKeyType->getConstantStrings() as $constantString) {
103 $patternStrings[] = $constantString->getValue();
104 }
105 }
106 }
107
108 return $patternStrings;
109 }
110
111 private function validatePattern(string $pattern): ?string
112 {
113 try {
114 $msg = null;
115 $prev = set_error_handler(function (int $severity, string $message, string $file) use (&$msg): bool {
116 $msg = preg_replace("#^preg_match(_all)?\\(.*?\\): #", '', $message);
117
118 return true;
119 });
120
121 if ($pattern === '') {
122 return 'Empty string is not a valid regular expression';
123 }
124
125 Preg::match($pattern, '');
126 if ($msg !== null) {
127 return $msg;
128 }
129 } catch (PcreException $e) {
130 if ($e->getCode() === PREG_INTERNAL_ERROR && $msg !== null) {
131 return $msg;
132 }
133
134 return preg_replace('{.*? failed executing ".*": }', '', $e->getMessage());
135 } finally {
136 restore_error_handler();
137 }
138
139 return null;
140 }
141
142 }
143