Developpez.com - PHP
X

Choisissez d'abord la catégorieensuite la rubrique :

Validation d'adresse e-mail en PHP.

Date de publication : 13 mai 2006

Date de mise à jour : 13 mai 2006

Par Alexandre TRANCHANT (CV)
Autres articles

Remerciements à Mathieu et Yogui pour leur relecture.

Ce tutoriel va vous permettre de vérifier la validité d'une adresse e-mail. Il répond à un besoin constant des webmasters qui souhaitent valider les adresses e-mails des internautes s'inscrivant sur leurs sites. Nous verrons différentes natures de validation, de la plus simple, par analyse syntaxique, à la plus complexe, par vérification du nom de serveur.

Prérequis:
  • Connaître les bases de PHP
  • Savoir manipuler des chaînes de caractères
  • Connaître PEAR
Il est conseillé de :
  • Savoir ce qu'est une expression régulière
  • Savoir installer un package PEAR
  • Connaître le principe d'un DNS
Vous allez apprendre à :
  • Valider une adresse e-mail par expression régulière
  • Valider une adresse e-mail selon la norme RFC822
  • Valider une adresse e-mail en vérifiant l'existance du nom de domaine
  • Valider une adresse e-mail par l'envoi d'un code d'activation

Sommaire

De quelle validation d'adresse e-mail a-t-on réellement besoin ?

Le but de ce tutoriel est de répondre à cette question. Plusieurs méthodes y sont présentées. Chacune possède des avantages, chacune possède des défauts. Au final, vous serez à même d'effectuer votre choix en ayant un maximum de cartes en main.

Validation rapide par expression régulière

La validation par expression régulière est sans doute la plus rapide, mais la moins précise qu'il est possible d'observer. L'analyse de la syntaxe va déterminer si l'adresse e-mail entrée dans le formulaire est une adresse valide. La méthode consiste donc à vérifier si la valeur correspond bien au masque standard d'une adresse e-mail. Le piège, par contre, réside dans la définition exacte d'une adresse e-mail standard. Cette définition est régie par un ensemble de normes :

Remarque : Pour que la fonction mail() de php soit en mesure d'envoyer un e-mail, il est nécessaire que l'adresse entrée respecte la norme RFC2822.

Ces définitions sont extrêmement complexes. Et le lecteur, au départ, y découvre que les adresses e-mails suivantes sont parfaitement valides :

  • user@host.network
  • nom@domaine.extension
  • "Full Name"@Domain
  • "Joe & J. Harvey" <ddd@Org.ltd>
  • toto

Etonnant ? Mais est-ce ce dont le webmaster lamda a réellement besoin ? Il est communément admis qu'un internaute saisissant son adresse e-mail entre une adresse semblable à notre premier exemple : "nom@domaine.extension" . Si notre but est seulement de gérer ce type d'adresse alors une expression régulière relativement simple peut régler rapidement la question. Vous en trouverez une très bien réalisée par bobocop et traduite par mathieu.


<?php
// Auteur : bobocop (arobase) bobocop (point) cz
// Traduction des commentaires par mathieu

// Le code suivant est la version du 2 mai 2005 qui respecte les RFC 2822 et 1035
// http://www.faqs.org/rfcs/rfc2822.html
// http://www.faqs.org/rfcs/rfc1035.html

$atom   '[-a-z0-9!#$%&\'*+\\/=?^_`{|}~]';   // caractères autorisés avant l'arobase
$domain '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)'// caractères autorisés après l'arobase (nom de domaine)
                               
$regex '/^' $atom '+' .   // Une ou plusieurs fois les caractères autorisés avant l'arobase
'(\.' $atom '+)*' .         // Suivis par zéro point ou plus
                                // séparés par des caractères autorisés avant l'arobase
'@' .                           // Suivis d'un arobase
'(' $domain '{1,63}\.)+' .  // Suivis par 1 à 63 caractères autorisés pour le nom de domaine
                                // séparés par des points
$domain '{2,63}$/i';          // Suivi de 2 à 63 caractères autorisés pour le nom de domaine

// test de l'adresse e-mail
if (preg_match($regex$email)) {
    echo 
"L'adresse e-mail $email est valide";
} else {
    echo 
"L'adresse e-mail $email n'est pas valide";
}
?>

La méthode consiste à écrire une expression régulière, tester avec la fonction preg_match sa validité de l'adresse e-mail passée en paramètre. La fonction retourne vrai si l'adresse e-mail est valide.

Cet exemple est extrait de la FAQ PHP en date du 18 mai 2006. La FAQ PHP est régulièrement mise à jour par un constant enrichissement de son contenu. N'hésitez pas à la consulter pour obtenir une éventuelle version plus à jour

Validation avec la classe Mail de Pear

Lors du paragraphe précédent, nous avons vu la validation d'une adresse e-mail "simple" grâce à une expression régulière. Mais pour les adresses e-mails avec un entête, la fonction retourne "faux". Alors qu'il n'en est rien.

PEAR propose une classe MAil_RFC822 permettant de récupérer un ensemble d'adresses e-mails valides dans un texte. Cette classe, plus lourde, permet de vérifier qu'une adresse e-mail est conforme à la RFC822. Après l'éventuelle installation de PEAR, ou du moins après le téléchargement des fichiers PEAR nécessaires. Vous pourrez faire appel à cette classe en faisant :


<?php
// Auteur : Communauté PEAR
// Mise en exemple par Alexandre TRANCHANT

//La variable $mail est-elle une adresse e-mail syntaxiquement valide ?
$mail='john.doe@example.org';

require 
'PEAR.php'//Appel de la librairie PEAR
require 'Mail/RFC822.php'//Appel de la librairie Mail_RFC822

$lo_mail Mail_RFC822::parseAddressList($mailNULLFALSE);

if(
PEAR::isError($lo_mail)){
    
//$lo_mail est une erreur
    //l'adresse n'est donc pas valide
    
echo $mail.'n\'est pas une adresse e-mail valide';
} elseif (
$lo_mail[0]->host=='localhost'){
    
//le nom de domaine de cette addresse est localhost 
    //dans cet exemple on refuse tout domaine local!
    
echo $mail.'n\'est pas une adresse e-mail valide';
} else {
    echo 
$mail.' est une adresse e-mail valide';
}

//Debuggage : 
print_r($lo_mail); 

?>

Voici les résultats de quelques tests :

john.doe@domaine.ltd "Full Name"@Domain
john.doe@example.org est une adresse e-mail valide
Array
(
    [0] => stdClass Object
        (
            [personal] => 
            [comment] => Array
                (
                )

            [mailbox] => john.doe
            [host] => example.org
        )

)
                    
"Full Name"@Domain est une adresse e-mail valide
Array
(
    [0] => stdClass Object
        (
            [personal] => 
            [comment] => Array
                (
                )

            [mailbox] => "Full Name"
            [host] => Domain
        )

)                        
                    
"Joe & J. Harvey" <ddd@Org.ltd> user@host.network,john.doe@example.com
"Joe & J. Harvey" <ddd@Org.ltd> est une adresse e-mail valide
Array
(
    [0] => stdClass Object
        (
            [personal] => "Joe & J. Harvey"
            [comment] => Array
                (
                )

            [mailbox] => ddd
            [host] => Org.ltd
        )

)
                    
user@host.network,john.doe@example.com 
est une adresse e-mail valide
Array
(
    [0] => stdClass Object
        (
            [personal] => 
            [comment] => Array
                (
                )

            [mailbox] => user
            [host] => host.network
        )

    [1] => stdClass Object
        (
            [personal] => 
            [comment] => Array
                (
                )

            [mailbox] => john.doe
            [host] => example.com
        )

)
                    

Validation avec interrogation du serveur

Les deux paragraphes précédents permettent uniquement de savoir si l'adresse e-mail est syntaxiquement valide. Mais rien ne garantit que le nom de domaine donné existe réellement. Pour ceux qui voudraient aller encore plus loin, et vérifier cela, nous allons appronfondir le sujet et tester l'existance du nom de domaine. Pour cela, nous allons vérifier que :

  • L'adresse d'e-mail est syntaxiquement valide
  • Puis nous récupérons le nom de domaine
  • Puis nous testons si ce nom de domaine est valide

La première étape est similaire au second exemple.


<?php
// Auteur : Communauté PEAR
// Mise en exemple par Alexandre TRANCHANT

//La variable $mail est-elle une adresse e-mail syntaxiquement valide ?
$mail='john.doe@example.org';

require 
'PEAR.php'//Appel de la librairie PEAR
require 'Mail/RFC822.php'//Appel de la librairie Mail_RFC822

$lo_mail Mail_RFC822::parseAddressList($mailNULLFALSE);

if(
PEAR::isError($lo_mail)){
    
//$lo_mail est une erreur
    //l'adresse e-mail n'est donc pas valide
    
echo $mail.'n\'est pas une adresse e-mail valide';
    die();
} elseif (
$lo_mail[0]->host=='localhost'){
    
//le nom de domaine de cette adresse est localhost 
    //dans cet exemple on refuse ce genre de mail !
    
echo $mail.'n\'est pas une adresse valide';
    die();
} else {
    echo 
$mail.' est une adresse e-mail SYNTAXIQUEMENT valide';
}

//$lo_mail contient l'adresse e-mail stockée dans un tableau

?>

La seconde étape extrait le nom de domaine de l'adresse e-mail entré.


<?php

/*
Voici le contenu de $lo_mail
Array
(
    [0] => stdClass Object
        (
            [personal] => 
            [comment] => Array
                (
                )

            [mailbox] => john.doe
            [host] => example.org
        )

)*/

$ls_domaine=$lo_mail[0]->host;

//$ls_domaine contient example.org

?>

La dernière étape, plus complexe, va interroger le serveur distant. Pour cela, nous allons faire appel à une autre classe de la bibliothèque PEAR.


<?php

//Rappel : La valeur ci dessous a normalement été initialisée dans la partie 2 du script
$ls_domaine 'developpez.com';

//Inscrivez dans ce tableau les serveurs de noms de votre FAI.
$la_serveur_de_nom=array(
    
'212.27.32.5',      //Adresse IP du serveur de noms primaire de mon FAI (Free)
    
'212.27.32.176',    //Adresse IP du serveur de noms secondaire de mon FAI (Free)
    
'212.27.32.177'     //Adresse IP du serveur de noms tertiaire de mon FAI (Free)
);

//Appel de la bibliothèque PEAR : Net DNS
require_once 'Net/DNS.php';

//Les fonctions ne peuvent pas s'appeler de façon statitique cette fois
//On crée donc une instance de classe Net_DNS_Resolver
$lo_resolver = new Net_DNS_Resolver();

//Décommentez cette ligne pour afficher le debuggage
//$lo_resolver->debug=1;

//On précise nos noms de serveurs
$lo_resolver->nameservers=$la_serveur_de_nom;

//On lance une requête, on précise MX pour identifier un éventuel serveur de mail
$lo_response $lo_resolver->query($ls_domaine,'MX');

//on teste la réponse
if ($lo_response) {
  foreach (
$lo_response->answer as $lo_rr) {
    
//On affiche le résultat pour l'exemple, mais c'est inutile dans l'aboslu
    
$lo_rr->display();
    echo 
"Nom de serveur de mail $ls_domaine valide";
  }
} else {
    echo 
"Nom de serveur de mail $ls_domaine inconnu";
}
?>

Désormais, nous savons si l'adresse e-mail est valide et si le nom de domaine répond bel et bien. Vous pouvez trouver sur le web plusieurs variantes à cette méthode. Certaines vont envoyer un ping via icmp sur le port 8 de la machine. D'autres méthodes vont tester la présence d'un serveur web sur le port 80. Mais ces solutions sont moins fiables, voire médiocre. En effet, un firewall peut occulter ces ports et bloquer toute réponse.

Pour cela, il faut une méthode fiable. Et les serveurs de noms sont là pour nous donner toutes les informations que nous souhaitons! Alors nous allons les interroger au moyen d'une autre classe PEAR : Net_DSN. La classe Net_DSN, ouvre un socket dans le but de directement interroger les seveurs de noms. Et ceci garantit des résultats fiables contrairement à une interrogation de ports aléatoires.

Quelle solution adopter ?

Comme nous avons pu le voir, la validation d'une adresse e-mail peut-être plus ou moins complexe à mettre en oeuvre. En fait, le plus important, comme d'ailleurs dans tout développement, est de bien discerner nos propres besoins et de choisir la solution la plus adaptée.

  • La première méthode est très rapide, peu gournamde en ressources, et gère 99.99% des adresses e-mails d'internautes.
  • La seconde méthode permet de stocker des adresses e-mails de la façon suivante : "Prénom Nom" <prenom.nom@domain.ltd>.
  • La dernière méthode est assez lourde en ressources, mais permet des contrôles supplémentaires.

Une solution très fiable : l'activation par retour d' e-mail !

Ces trois méthodes ont chacune défauts et avantages, mais elles ne vous garantissent qu'une chose : Votre serveur ne tentera pas d'envoyer un e-mail alors que l'adresse est syntaxiquement fausse, ou que le nom de domaine n'est que pure fiction. En effet, rien ne garantit que l'adresse e-mail entrée par l'internaute ne soit pas une adresse "bidon" appartenant à une malheureuse tierce personne, voire à personne !

C'est pourquoi, désormais, les webmasters vérifient l'adresse e-mail, puis stockent l'utilisateur dans une base de données. Ils joignent à cet utilisateur un code d'activation aléatoirement généré. Cependant les webmasters ne permettent pas encore à l'internaute d'utiliser leur site. Par exemple, pour une inscription sur un forum, l'utilisateur est enregistré mais n'a pas encore l'autorisation de poster de messages, de voter, etc.. En fait, les webmasters envoient un e-mail à l'adresse fournie : cet e-mail contient le code d'activation. Si l'internaute a fourni sa véritable adresse, alors il recevra l'e-mail contenant le code d'activation. Il sera en mesure de se rendre sur le site, et d'activer son compte via un formulaire ou un lien. C'est après vérification du code que son compte s'activera. Si tel n'est pas le cas, généralement, à court terme, l'inscription est supprimée de la base de données.

En conclusion, choisissez l'une des trois méthodes. Si l'adresse e-mail est syntaxiquement correcte, alors envoyer un e-mail contenant un code d'activation vous garantira que l'internaute a bel et bien entré sa propre adresse.

Contacter le responsable de la rubrique PHP