Unicode & Multibyte Regex
debt(d6/e2/b3/t7)
Closest to 'only careful code review or runtime testing' (d7), slightly better at d6 because semgrep patterns can flag regex literals missing /u flag on user input paths, but phpstan won't catch it semantically — most cases surface when non-ASCII users hit production.
Closest to 'one-line patch' (e1), bumped to e2 because quick_fix is literally adding /u flag and swapping [a-zA-Z] for \p{L} — trivial per-regex but you usually need to audit several regexes, still a parameterised single-line pattern fix.
Closest to 'localised tax' (b3), regex usage is scattered but each fix is local; no architectural pull. Mixing mb_ereg vs preg_match across codebase adds slight persistent tax but doesn't shape the system.
Closest to 'serious trap' (t7), the misconception is explicit: developers assume PCRE handles Unicode by default like modern languages (JS, Python 3, Go) but PHP treats input as bytes — contradicts behaviour of similar regex engines elsewhere, and \w silently excluding accented letters is exactly the 'obvious way is wrong' pattern.
Also Known As
TL;DR
Explanation
PHP regex without the u flag treats strings as byte sequences: \w matches only [A-Za-z0-9_], . matches any single byte. With u flag: \w matches Unicode word characters (including accented letters, CJK), \p{L} matches any Unicode letter, \p{N} any number, \p{Z} whitespace, \X matches an extended grapheme cluster (letter + combining characters). The u flag requires both pattern and subject to be valid UTF-8. Validate with mb_check_encoding() before applying u-flag regex.
Common Misconception
Why It Matters
Common Mistakes
- Validating user names or text without u flag — rejects valid non-ASCII names
- \w for word detection without u — misses Unicode letters
- Not validating that input is valid UTF-8 before applying u-flag regex
- Mixing mb_ereg and preg_match in the same codebase — different syntax and behaviour
Code Examples
// Missing u flag — rejects valid multilingual names:
$name = 'François';
if (!preg_match('/^[a-zA-Z\s]+$/', $name)) {
throw new ValidationException('Invalid name');
// Rejects François — ç not in [a-zA-Z]
}
// Unicode-aware with u flag:
$name = 'François';
if (!mb_check_encoding($name, 'UTF-8')) {
throw new ValidationException('Invalid UTF-8 input');
}
if (!preg_match('/^[\p{L}\p{Z}]+$/u', $name)) {
throw new ValidationException('Name must contain only letters and spaces');
}
// \p{L}: any Unicode letter — includes ç, é, ü, 张, etc.