L’essentiel à retenir avant de mesurer une chaîne
- `strlen()` compte des octets, pas des caractères.
- `mb_strlen($texte, 'UTF-8')` est le bon réflexe pour du texte utilisateur en UTF-8.
- `grapheme_strlen()` sert quand tu veux compter ce qu’un humain perçoit comme un caractère.
- Pour du contenu binaire ou des contraintes de transport, `strlen()` reste pertinent.
- En validation, il faut toujours aligner la fonction avec l’encodage et la règle métier.
Ce que mesure vraiment une longueur en PHP
Le premier réflexe à garder en tête, c’est que la longueur n’est pas une notion unique. En PHP, une chaîne peut être mesurée en octets, en caractères ou en graphèmes, et ces trois unités ne donnent pas forcément le même résultat. La documentation officielle PHP rappelle d’ailleurs que strlen() renvoie le nombre d’octets, pas le nombre de caractères.
Dans une chaîne ASCII simple, les trois visions se confondent souvent. Dès qu’il y a des accents, des caractères non latins ou des emojis, les écarts apparaissent. Par exemple, cafe et café n’occupent pas le même nombre d’octets en UTF-8, alors que pour un lecteur, la différence ne saute pas toujours aux yeux. C’est là que beaucoup de validations déraillent: le code compte une unité, l’utilisateur en voit une autre.
Je préfère raisonner ainsi: que veux-tu mesurer exactement? La taille brute d’une donnée, le nombre de caractères dans un champ, ou le nombre de symboles visibles pour l’utilisateur? Une fois cette question claire, le choix de la fonction devient presque mécanique. La suite permet justement de faire ce tri sans hésitation.
Choisir entre bytes, caractères et graphèmes
| Fonction | Ce qu’elle compte | Quand je l’utilise | Limite principale |
|---|---|---|---|
strlen() |
Les octets | Données binaires, protocoles, tailles brutes, contenu non textuel | Peut surprendre sur du texte UTF-8 |
mb_strlen($texte, 'UTF-8') |
Les caractères selon l’encodage | Texte utilisateur, formulaires, titres, pseudos, commentaires | Ne mesure pas toujours ce que l’œil perçoit comme un seul symbole |
grapheme_strlen() |
Les graphèmes | Emojis, caractères composés, affichage orienté UX | Dépend de l’extension intl et du UTF-8 valide |
La nuance la plus utile est celle-ci: un caractère visible n’est pas toujours un seul caractère technique. Un accent combiné, une ligature ou un emoji peuvent être découpés en plusieurs unités internes. Si ton besoin est de compter ce que l’utilisateur voit réellement, grapheme_strlen() est souvent le meilleur outil. Si ton besoin est de valider un champ texte standard en UTF-8, mb_strlen() suffit dans la majorité des cas.
Je conseille aussi de passer l’encodage explicitement, surtout sur les projets web où les entrées viennent de plusieurs sources. mb_strlen($texte, 'UTF-8') est plus lisible et plus robuste qu’un réglage implicite. Si toute ton application repose sur UTF-8, cette petite discipline t’évite des écarts difficiles à repérer lors d’un changement de serveur ou d’environnement.
Des exemples concrets pour un site, une API ou un formulaire
Dans un formulaire d’inscription, l’objectif n’est presque jamais de compter les octets. Tu veux généralement limiter la longueur perçue par l’utilisateur, donc mb_strlen() est le bon choix. Voici le cas le plus classique:
$pseudo = trim($_POST['pseudo'] ?? '');
if (mb_strlen($pseudo, 'UTF-8') > 20) {
$errors[] = 'Le pseudo ne doit pas dépasser 20 caractères.';
}
Ce code est simple, mais il colle à la règle métier: 20 caractères pour un pseudo, pas 20 octets. La différence compte dès qu’un utilisateur tape un accent, un tiret typographique ou un emoji. C’est précisément le genre de détail qui fait passer une validation de “fonctionne en test” à “fonctionne pour de vrais utilisateurs”.
Pour un texte affiché dans une interface, par exemple un titre de carte ou un extrait de commentaire, je regarde souvent les graphèmes plutôt que les caractères Unicode bruts. Cela évite de couper un symbole visuellement unique en plein milieu:
$titre = trim($_POST['titre'] ?? '');
if (grapheme_strlen($titre) > 40) {
$errors[] = 'Le titre doit rester court et lisible.';
}
À l’inverse, pour une charge binaire ou une limite technique, strlen() reste parfaitement légitime. Si tu contrôles la taille d’un payload avant de le stocker, de le transmettre ou de le signer, les octets sont souvent la vraie unité à respecter:
$payload = base64_decode($data, true);
if ($payload !== false && strlen($payload) > 1048576) {
throw new RuntimeException('Payload trop volumineux.');
}
Je vois souvent une erreur de cadrage: utiliser la même fonction pour un champ de saisie, une donnée binaire et une limite de base de données. Ce mélange crée des comportements incohérents. La bonne pratique, c’est de faire correspondre la fonction à la contrainte réelle du système. La section suivante montre les pièges qui reviennent le plus souvent.
Les pièges qui faussent le comptage
Le piège numéro un, c’est de supposer que strlen() mesure le nombre de caractères “comme un humain les compte”. Ce n’est pas son rôle. Si ton texte contient des accents, des idéogrammes ou des emojis, le résultat peut sembler étrange alors qu’il est techniquement exact. Ce n’est donc pas la fonction qui est fausse, c’est l’unité choisie qui ne correspond pas au besoin.
Le deuxième piège, plus subtil, consiste à laisser l’encodage implicite. Avec mb_strlen(), l’encodage peut venir du contexte interne si tu ne le précises pas. Sur un petit script, ça peut passer. Dans un projet maintenu par plusieurs personnes, c’est une source de dérive inutile. Je préfère écrire l’encodage attendu dans l’appel lui-même pour rendre l’intention évidente.
Il y a aussi les cas où l’on confond vide, null et chaîne de longueur nulle. Depuis PHP 8.0, passer null à strlen() est déprécié. Si la valeur peut être absente, je préfère une vérification explicite:
$message = $_POST['message'] ?? null;
if ($message === null || $message === '') {
$errors[] = 'Le message est obligatoire.';
}
Enfin, il ne faut pas négliger la base de données. Un champ VARCHAR(200) ne raconte pas la même histoire selon qu’il est limité en caractères ou en octets. Si ton schéma, ton ORM et ta validation PHP ne parlent pas la même unité, tu risques des refus côté serveur ou des troncatures silencieuses. La règle utile ici est simple: la validation doit mesurer la même chose que le stockage ou l’interface cible.
Mes règles simples pour garder un code fiable
Quand je travaille sur une base PHP moderne, je garde quelques règles très concrètes. Elles couvrent la majorité des cas sans rendre le code lourd ou abstrait.
-
Texte utilisateur en UTF-8 : j’utilise
mb_strlen($texte, 'UTF-8'). -
Affichage orienté UX : je passe à
grapheme_strlen()si les emojis ou les caractères composés comptent vraiment. -
Octets, fichiers, payloads, sécurité transport : je reste sur
strlen(). - Encodage flou : je le rends explicite au lieu de le déduire.
-
Valeur potentiellement absente : je teste
nullet chaîne vide séparément.
Je recommande aussi de tester tes règles avec plusieurs entrées réalistes: un mot simple, un mot accentué, un emoji, une chaîne vide et une valeur nulle. En pratique, ces cinq cas suffisent souvent à révéler une validation bancale avant qu’elle n’atteigne la production. C’est un test très modeste, mais il élimine une grande partie des mauvaises surprises.
Si tu dois retenir une seule chose, c’est celle-ci: ne demande pas à PHP de “compter une chaîne” sans préciser ce que tu veux compter. Dès que l’unité est claire, la bonne fonction devient évidente, et ton code gagne en fiabilité comme en lisibilité.
La règle la plus utile pour éviter les mauvaises surprises
Pour la plupart des projets web, je pars d’un principe simple: je compte en caractères pour le texte utilisateur, en graphemes pour l’affichage fin, et en octets pour tout ce qui est technique. Cette séparation évite presque toutes les confusions autour de la longueur d’une chaîne en PHP.
Autre réflexe utile: j’écris l’encodage explicitement, je teste les accents dès le début, et je fais correspondre la validation au stockage final. Avec ces trois gestes, tu évites les écarts les plus courants sans alourdir ton code. C’est une petite discipline, mais en développement web, c’est souvent elle qui fait la différence entre un comportement correct et un bug intermittent difficile à traquer.