Pattern Delimiters And Modifiers

ID

php.regular_expr_valid_delimiters

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Php

Tags

regex, reliability

Description

Reports a preg_* pattern that PHP cannot split into a pattern and its modifiers: an empty pattern, an alphanumeric or backslash delimiter, a missing or unbalanced closing delimiter, or a modifier letter PCRE does not have.

Unlike the other regular-expression rules, this one has no counterpart in another language, because no other language spells a pattern this way. In Java or JavaScript the pattern is the string. In PHP the string carries its own delimiters and trailing modifiers, so extracting a pattern from it is a parse that can fail on its own terms — before PCRE ever sees a metacharacter.

Rationale

// Bad
preg_match('/abc', $s);          // Warning: No ending delimiter '/' found
preg_match('aabca', $s);         // Warning: Delimiter must not be alphanumeric or backslash
preg_match('/abc/g', $s);        // Warning: Unknown modifier 'g'
preg_replace('/(\d+)/e', $r, $s); // Warning: The /e modifier is no longer supported
preg_match('', $s);              // Warning: Empty regular expression
  • Every one of these makes the call return false and match nothing, on every run and for every input, so a validation guard silently accepts nothing and a filter silently filters nothing.

  • The warning is normally invisible in production, where display_errors is off.

  • /abc/g is the most common of these by far: the trailing g is JavaScript’s global flag, which PHP does not have — preg_replace and preg_match_all already replace or match every occurrence.

Remediation

Close the pattern, pick a delimiter that is neither alphanumeric nor a backslash, and drop any modifier PCRE does not define.

// Good
preg_match('/abc/', $s);
preg_match('#^/api/v[0-9]+$#', $s);   // another delimiter, so slashes need no escaping
preg_match_all('/abc/', $s, $m);      // "match them all" is the function, not a modifier

The modifiers PCRE accepts in PHP are i, m, s, x, A, D, S, U, X, u, J and n. e was removed in PHP 7.

What is accepted

  • Both delimiter families: the bracket pairs (…​), […​], {...} and <…​>, whose nesting is tracked, and any other non-alphanumeric character repeated, such as /, # or ~.

  • A backslash-escaped delimiter inside the pattern — /^https?:\/\/\w+/ — which does not close it.

  • Whitespace before the opening delimiter and between the modifier letters, both of which PHP skips.

A pattern built at run time is not readable here and is not judged.

© 2026 Xygeni. All rights reserved