Un échec de connexion dû à une incohérence dans le stockage des numéros de téléphone a révélé une faille. Le compte d'un utilisateur a été bloqué parce que la base de données contenait le même numéro de mobile allemand sous deux formes — 0171 5550134 dans une ligne et +49 171 5550134 dans une autre — le système les a donc considérés comme des entrées distinctes. Résultat : l'OTP n'est jamais arrivé, et le bouton « envoyer le code » est devenu un coup de dé.

Pourquoi les numéros de téléphone sont plus complexes que les dates

Les développeurs font souvent confiance à une regex pour maîtriser la saisie des numéros de téléphone. Cette confiance s'effondre dès qu'un numéro traverse une frontière ou qu'un plan national change. Les dates suivent un calendrier prévisible ; les numéros de téléphone mutent selon les opérateurs, les réglementations et les conventions culturelles.

Le coût caché des chaînes de caractères brutes

Stocker un numéro de téléphone sous forme de simple chaîne de caractères semble sans risque — jusqu'à ce que deux représentations pointent vers la même ligne. Les systèmes OTP qui interrogent la base de données pour trouver « le » numéro finissent par envoyer un code à un doublon qui n'atteint jamais l'utilisateur.

Le problème s'aggrave lorsque les numéros sont stockés dans des champs numériques. Une colonne BIGINT supprime le + initial et les zéros non significatifs, transformant +49 171 5550134 en 491715550134. Sans le signe plus, reconstruire le format d'origine devient une supposition.

Le contrat E.164

Le plan de numérotation téléphonique international, E.164, définit une représentation unique et portable :

  • Commence par un +
  • Suivi d'un code pays de 1 à 3 chiffres
  • Puis le numéro d'abonné
  • Pas plus de 15 chiffres au total
  • Pas d'espaces, de points ou de tirets

L'E.164 ne garantit pas que le numéro soit actif ; il garantit seulement que la chaîne respecte un modèle structurel valide. Considérez-le comme un contrat de format, et non comme un oracle de joignabilité.

Pièges courants qu'une regex ne peut pas corriger

  • Stockage numérique – BIGINT supprime le + et les zéros initiaux. Utilisez plutôt une colonne de type texte (TEXT ou VARCHAR).
  • Regex codées en dur – Les plans nationaux changent. Le Mexique a supprimé son préfixe de trunk en 2019 ; l'Argentine exige désormais un 9 après le code pays pour les lignes mobiles. Un modèle statique devient rapidement obsolète.
  • Suppression aveugle des zéros – Les lignes fixes italiennes conservent un zéro initial, contrairement aux lignes allemandes. Une règle générale de « suppression des zéros initiaux » corrompt les données italiennes tout en laissant les numéros allemands intacts.
  • Supposer que le format garantit la délivrabilité – libphonenumber valide la structure mais ne peut pas dire si le téléphone est allumé ou si le numéro a été porté.

Construire un pipeline fiable

  1. Demander le pays – Ajoutez un sélecteur de pays dans les formulaires d'inscription et transmettez cette région au parseur.
  2. Afficher le formatage en temps réel – Utilisez un formatage de type « AsYouType » pour que les utilisateurs voient le modèle correct pendant qu'ils tapent.
  3. Valider lors de la perte de focus (on blur) – Exécutez la validation après que l'utilisateur a quitté le champ plutôt qu'à chaque frappe de touche ; cela réduit les frictions.
  4. Ne persister que la chaîne E.164 – Stockez le numéro normalisé avec le préfixe + dans la base de données.
  5. Formater en périphérie – Ne reconvertissez le numéro dans un format lisible par l'humain que dans l'interface utilisateur ou les modèles d'e-mails.

Lors de la migration de données héritées (legacy), conservez les lignes qui échouent à la validation. Analysez chaque entrée existante dans une nouvelle colonne, signalez les échecs et générez un rapport. Les suppressions silencieuses créent des tickets de support qui se transforment plus tard en corrections coûteuses.

Une check-list rapide pour les développeurs

  • Stockez les numéros en tant que TEXT/VARCHAR au format E.164.
  • Utilisez la bibliothèque libphonenumber de Google ; elle gère la réalité complexe des plans mondiaux.
  • Fournissez une région par défaut pour les utilisateurs qui omettent le code pays.
  • Appelez is_valid_number pour les inscriptions en direct ; cela vérifie que le numéro respecte les règles régionales.
  • Utilisez is_possible_number lors du nettoyage de données en masse ; cela permet de détecter les entrées manifestement malformées sans rejeter les cas limites.

Une gestion correcte des numéros de téléphone n'est pas un simple bonus ; c'est un prérequis pour tout système reposant sur un contact utilisateur fiable. En normalisant vers l'E.164 et en déléguant l'analyse à une bibliothèque éprouvée, les développeurs éliminent une classe de bugs qui érodent silencieusement la confiance et les revenus. Traitez les numéros de téléphone comme des données structurées, et non comme du texte libre, et laissez les standards faire le gros du travail.