Valider une adresse email avec php
Un petit article pour indiquer qu'il est très simple de valider les adresse mails saisies par un utilisateur lors d'une inscription à une section membre par exemple. C'est une question qui revient assez souvent sur les forums les plus populaires malgré le nombre d'informations qu'on peut trouver la dessus. Hélas souvent on trouve pas mal de regex de tous genres dans les réponses, qui se valent plus ou moins toutes les unes les autres, et pour certaines, beaucoup moins en fait :)
Une fonction PHP peut éviter de s'encombrer de regex approximatives, c'est filter_var() qui permet de filtrer une variable avec un filtre spécifique. Dans notre cas la variable sera une chaine représentant une adresse mail bien sur. Cette fonction est assez puissante et d'autant plus longue a expliquer et décrire dans son intégralité, nous nous contenterons d'utiliser le filtre de base concernant la validation d'une adresse email.
$email1 = "mauvaise.adresse@sansndd"; // email non valide $email2 = "bonne@adresse.mail"; // email valide $clean_email1 = filter_var($email1, FILTER_VALIDATE_EMAIL); // $clean_email1 = false $clean_email2 = filter_var($email2, FILTER_VALIDATE_EMAIL); // $clean_email2 = bonne@adresse.mail
Il me semble que les regex utilisées par "le moteur PHP" sont issues des travaux d'un certain Michael, qui a passé beaucoup de son temps a étudier le problème des validations. Il a notamment écrit un article qui résume bien les différents cas de figures et les solutions qui vont avec en terme de regex. Et au pire des cas, si la regex utilisée nativement par le filtre ne vous plait pas, vous pouvez la personaliser dans le fichier repertoire-php/ext/filter/logical_filter.c à la ligne 533 et recompiler PHP.
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { // ---- const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD"; // ---- }
Cette fonction a été critiquée pas mal de fois quand elle a été implémentée car ils semblerait que des bugs aient étés relevés par la communauté au niveau du code source de php version 5.2.5. En fait, la regex qui se chargeait de valider les adresses emails n'était pas complètement juste, elle bloquait par exemple les adresses contenant des chiffres comme adre55e@mail.fr. Si ces petits bugs ont rapidement étés corrigés, cette fonction ne valide pas les noms de domaines c'est a dire que si votre adresse est clara@morgan.panpan alors elle sera validée, même si papan n'est pas un TLD valide. Pourtant il est aussi possible de valider l'adresse email et de vérifier dans un second temps si le domaine est un MX valide (pour éviter que adresse@email.fake ne soit validée par exemple) en utilisant la fonction checkdnsrr(). C'est pas sorcier et ca rajoute une couche de plus dans l'étape de validation.
function CheckAndValidateEmail($mail){ if(filter_var($mail, FILTER_VALIDATE_EMAIL)) { // ici déja le format de l'email est valide list($user,$domaine)=explode("@",$mail,2); if(!checkdnsrr($domaine,"MX")&& !checkdnsrr($domaine,"A")){ echo 'Email valide mais domaine invalide'; } else { echo'Email valide'; } } else { //no echo 'Email invalide'; } }
Voila, avec ça en principe ça devrait aller pour vérifier la syntaxe et la correspondance du nom de domaine saisi, ce qui pourra surement suffire dans 95% des cas, à mon avis. Cela dit si vous avez envie de faire plus compliqué c'est possible aussi, vous pouvez même utiliser une classe dédiée à la gestion de ces adresses. Sur sa page Michael propose aussi un exemple de classe qui va bien, donc n'hésitez pas a copier ou télécharger son fichier (2.70Ko) puisqu'il le propose...
Aller bon courage avec vos mails :)
++
Retour a la liste