Skip to content

Commit 465af9e

Browse files
staabmondrejmirtes
authored andcommitted
RegularExpressionPatternRule: validate preg_quote'd patterns
1 parent 3fad412 commit 465af9e

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

src/Rules/Regexp/RegularExpressionPatternRule.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPStan\Analyser\Scope;
1010
use PHPStan\Rules\Rule;
1111
use PHPStan\Rules\RuleErrorBuilder;
12+
use PHPStan\Type\Php\RegexExpressionHelper;
1213
use function in_array;
1314
use function sprintf;
1415
use function str_starts_with;
@@ -20,6 +21,12 @@
2021
class RegularExpressionPatternRule implements Rule
2122
{
2223

24+
public function __construct(
25+
private RegexExpressionHelper $regexExpressionHelper,
26+
)
27+
{
28+
}
29+
2330
public function getNodeType(): string
2431
{
2532
return FuncCall::class;
@@ -74,6 +81,9 @@ private function extractPatterns(FuncCall $functionCall, Scope $scope): array
7481
'preg_filter',
7582
], true)
7683
) {
84+
if ($patternNode instanceof Node\Expr\BinaryOp\Concat) {
85+
$patternType = $this->regexExpressionHelper->resolvePatternConcat($patternNode, $scope);
86+
}
7787
foreach ($patternType->getConstantStrings() as $constantStringType) {
7888
$patternStrings[] = $constantStringType->getValue();
7989
}

tests/PHPStan/Rules/Regexp/RegularExpressionPatternRuleTest.php

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPStan\Rules\Rule;
66
use PHPStan\Testing\RuleTestCase;
7+
use PHPStan\Type\Php\RegexExpressionHelper;
78
use function sprintf;
89
use const PHP_VERSION_ID;
910

@@ -15,7 +16,9 @@ class RegularExpressionPatternRuleTest extends RuleTestCase
1516

1617
protected function getRule(): Rule
1718
{
18-
return new RegularExpressionPatternRule();
19+
return new RegularExpressionPatternRule(
20+
self::getContainer()->getByType(RegexExpressionHelper::class),
21+
);
1922
}
2023

2124
public function testValidRegexPatternBefore73(): void
@@ -115,6 +118,30 @@ public function testValidRegexPatternBefore73(): void
115118
'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~',
116119
43,
117120
],
121+
[
122+
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: nok',
123+
57,
124+
],
125+
[
126+
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: nok',
127+
58,
128+
],
129+
[
130+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
131+
59,
132+
],
133+
[
134+
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: noknono',
135+
61,
136+
],
137+
[
138+
'Regex pattern is invalid: Delimiter must not be alphanumeric, backslash, or NUL in pattern: noknope',
139+
62,
140+
],
141+
[
142+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
143+
63,
144+
],
118145
],
119146
);
120147
}
@@ -221,6 +248,30 @@ public function testValidRegexPatternAfter73(): void
221248
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
222249
43,
223250
],
251+
[
252+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok', $messagePart),
253+
57,
254+
],
255+
[
256+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: nok', $messagePart),
257+
58,
258+
],
259+
[
260+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
261+
59,
262+
],
263+
[
264+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: noknono', $messagePart),
265+
61,
266+
],
267+
[
268+
sprintf('Regex pattern is invalid: Delimiter must not be %s in pattern: noknope', $messagePart),
269+
62,
270+
],
271+
[
272+
'Regex pattern is invalid: Compilation failed: missing closing parenthesis at offset 1 in pattern: ~(~',
273+
63,
274+
],
224275
],
225276
);
226277
}

tests/PHPStan/Rules/Regexp/data/valid-regex-pattern.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?php
1+
<?php namespace RegexExpressionPatterns;
22

33
$string = (function (): string {})();
44

@@ -48,3 +48,17 @@
4848
],
4949
''
5050
);
51+
52+
function doFoo(string $s) {
53+
preg_match('~ok'. preg_quote($s, '~') .'~', '');
54+
preg_match('~ok'. preg_quote($s) .'~', '');
55+
56+
// invalid preg_quote delimiters will be reported by RegularExpressionQuotingRule
57+
preg_match('nok'. preg_quote($s), '');
58+
preg_match('nok'. preg_quote($s), '');
59+
preg_match('~('. preg_quote($s, '~') .'~', '');
60+
61+
preg_replace('nok'. preg_quote($s).'nono', '');
62+
preg_replace('nok'. preg_quote($s).'nope', '');
63+
preg_replace('~('. preg_quote($s, '~') .'~', '');
64+
}

0 commit comments

Comments
 (0)