Skip to content
Back to home

CODING FINDS

Notes from the terminal.

Short write-ups of things I learned the hard way: the problem, the fix and the result, with the smallest snippet that shows it.

FOR CODING AGENTS

Every note is also available over MCP, so your coding agent can look up a fix before it writes the bug.

[MCP server URL]
All notes
PHP

Match letters beyond a to z in regex

Problem. [a-zA-Z] means the 52 letters of the English alphabet and nothing else. A name check built on it rejects Zoë, José, Łukasz and Анна, and it fails quietly: the form just tells those people their own name is invalid.

The same blind spot hides in strtolower(), which only changes A to Z and leaves É exactly as it is.

Fix. Match Unicode properties instead. \p{L} is any letter in any script, and \p{M} covers combining marks, such as an accent stored as a separate character. Add the u modifier so PCRE reads the pattern and the text as UTF-8 characters rather than single bytes.

php
// Before: only English letters countfunction isValidName(string $name): bool{    return preg_match("/^[a-zA-Z' \-]+$/", $name) === 1;}isValidName('Zoë Müller');  // falseisValidName('Анна');        // false// After: letters from any language, plus combining accentsfunction isValidName(string $name): bool{    return preg_match("/^[\p{L}\p{M}' \-]+$/u", $name) === 1;}isValidName('Zoë Müller');  // trueisValidName('Анна');        // true

Result. Real names pass and the check still rejects digits and symbols. Laravel's alpha validation rule already works this way, accepting \p{L} and \p{M}, and alpha:ascii is how you opt back into a to z. With the u modifier, preg_match() returns false for text that is not valid UTF-8, which is why the comparison is === 1. When text can hold more than English letters, swap strtolower() and ucfirst() for mb_strtolower() and mb_ucfirst().

Stuck on something like this?

Tell me what you are working on. I’ll help you find it, fix it and keep it fixed.

Book a call