Invalid Regular Expression
ID |
php.bad_regex_syntax |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Php |
Tags |
regex, reliability |
Description
Reports a preg_* pattern that PCRE cannot compile: an unbalanced group or character class, a *, + or ? with no atom to repeat, quantifier bounds in the wrong order, or an out-of-order character-class range.
Rationale
PCRE compiles the pattern on every call. A pattern it rejects therefore never matches anything — but the call does not stop the script:
// Bad
if (preg_match('/(unclosed/', $input)) {
$this->accept($input);
}
-
preg_matchemits a warning and returnsfalse, which is falsy, so the branch is never taken. -
A validation guard written this way accepts nothing, and a filter written this way filters nothing — silently, on every run, for whichever value of
$inputarrives. -
The warning is normally invisible in production, where
display_errorsis off.
Remediation
Fix the pattern. Escape a metacharacter that was meant literally, close what was opened, and put quantifier and range bounds in ascending order.
// Good
if (preg_match('/\(unclosed/', $input)) { // a literal parenthesis
$this->accept($input);
}
preg_match('/x{1,3}/', $s); // ascending bounds
preg_match('/[a-z]/', $s); // ascending range
What is not reported
The PCRE grammar is not the JDK one, and several constructs that other engines reject are ordinary PHP. None of these is reported:
Two further carve-outs keep the rule quiet on valid patterns. A straight after a bare ( is left alone, because ( opens a control verb such as (*SKIP). And character-class balance is not judged at all once a [ appears inside a class, because the shared tokenizer reads that as a nested class while PCRE reads it as a literal bracket.
A dangling backslash is not checked because it cannot reach PCRE: PHP’s delimiter scan honours backslash escapes, so a backslash before the closing delimiter escapes it and the literal is reported by php.regular_expr_valid_delimiters instead.