Formulaire de contact avec PHPMailer

La vérification du CAPTCHA posait quelques problèmes dans sa première version. Lorsque l’utilisateur se trompait dans un des champs, le CAPTCHA se bloquait. Vous pouvez dès à présent trouver un exemple fonctionnel ainsi que sa source.

Introduction

Formulaire de contactLe formulaire de contact est le premier et le plus simple moyen de communication entre un client et le propriétaire du site. Que ce soit sur un blog pour demander un article à l’administrateur ou sur un site professionnel pour demander un devis, le formulaire de contact se doit d’être simple à remplir et surtout sécurisé pour pouvoir faire le tri entre clients et spams.

Dans cet article nous mettrons en place un formulaire très simple : nom, prénom, @mail, sujet, message. Nous y mettrons un peu d’AJAX pour le rendre plus réactif. La vérification des champs sera très simple : syntaxe mail pour le champ @mail et vérification des caractères [a-z._-] pour les autres champs. Ce qui nous assurera un formulaire sécurisé au niveau des injections de la fonction mail().

En ce qui concerne l’envoi lui-même du mail je vous conseillerai d’utiliser la classe PHPMailer qui fourni vraiment tout ce qui est nécessaire pour envoyer un mail sans se casser la tête à rédiger les entêtes ou joindre des fichiers.

Nous finirons par mettre en place un peu de sécurité contre le spam du formulaire.

Création du formulaire

Créez un formulaire tout bête avec 4 input text et un textarea :

<form id="form_contact" action="contact.php" method="post">
  <fieldset>
    <legend>Contactez-nous</legend>
 
    <label>Nom</label>
    <input type="text" name="nom" value=""/>
    <div class="clearer"></div>
 
    <label>Prénom</label>
    <input type="text" name="prenom" value=""/>
    <div class="clearer"></div>
 
    <label>@mail</label>
    <input type="text" name="mail" value=""/>
    <div class="clearer"></div>
 
    <label>Sujet</label>
    <input type="text" name="sujet" value=""/>
    <div class="clearer"></div>
 
    <label>Message</label>
    <textarea name="message" cols="45" rows="6"></textarea>
    <div class="clearer"></div>
 
    <label>&nbsp;</label>
    <input type="submit" value="envoyer"/>
    <div class="clearer"></div>
 
    <div id="result_contact"></div>
  </fieldset>
</form>

Je l’ai mis un peu en forme grâce à des LABEL et à des DIV de classe « clearer » que j’ai défini dans le style :

.clearer{clear:both;}
legend{font-size:1.3em;}
fieldset{float:left;width:40%;}
a{color:#0000FF;}
label{float:left;width:120px;}
input{width:200px;}

Mise en place de l’AJAX

Créons d’abord la fonction qui va capturer l’envoi du formulaire puis le stopper afin de nous laisser la main pour traiter l’envoi nous-même :

document.addEvent('domready', function(){
  $('form_contact').addEvent('submit', function(e){
 
    e.stop();
    /* Ici on enverra le formulaire nous-même */
 
  });
});

On prépare la requête AJAX en définissant les fonctions à exécuter en cas de réussite, échec, réponse, et lors de l’envoi :

var button = this.getElement('input[type=submit]');
this.set('send', {
    onRequest: function(){
      button.morph({opacity:0});
      $('result_contact').set('html','');
    },
    onComplete: function(){
      button.morph({opacity:1});
    },
 
    onSuccess: function(responseText, responseXML){
      // On définira en dessous ce qui se passe ici
    },
    onFailure: function(xhr){
      button.morph({opacity:1});
      $('result_contact').set('html','Erreur lors de la communication avec le serveur.');
    }
});

Traitement du XML

Maintenant attaquons nous à la lecture de la réponse du serveur. Pour mon exemple j’ai choisi d’utiliser le XML qui nous permettra de recevoir des données uniquement et de définir nous même quelle mise en forme utiliser.

Le fichier suivant nous montre quel genre de XML nous traiterons et comment l’utiliser :

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <error>no</error>
  <uneliste>
    <item>blah</item>
    <item>bleh</item>
    <item>blih</item>
  </uneliste>
</root>

Pour trouver « no » qui se trouve dans <error> il faut utiliser le code ci-dessous :

var error = $(responseXML).getElement('root error').get('text');

Pour traiter tous les <item>, utiliser la méthode « each » fournit par Mootools :

$(responseXML).getElements('root uneliste item').each(function(element){
  // Faites le traitement ici
}

Maintenant utilisons le code qui suit pour traiter la réponse du serveur.

onSuccess: function(responseText, responseXML){
  var type = $(responseXML).getElement('root error').get('text');
  switch(type){
    case 'field':
      $('result_contact').set('html','Les champs ci-dessous sont mal remplis.');
      $(responseXML).getElements('root fields field').each(function(el){
        $('result_contact').adopt(new Element('div', {html:el.get('text')}));
      });
    break;
 
    case 'envoi':
      $('result_contact').set('html','Problème lors de l\'envoi avec PHPMailer.<br/>');
      $('result_contact').adopt(new Element('div', {html:$(responseXML).getElements('root exception').get('text')}));
    break;
 
    case 'time':
      var secondes = $(responseXML).getElements('root seconds').get('text');
      $('result_contact').set('html','Vous devez attendre '+secondes+' secondes avant d\'enoyer un nouveau message.');
    break;
 
    case 'session':
      $('result_contact').set('html','Votre navigateur n\'est pas compatible avec les sessions.');
    break;
 
    case 'no':
      $('result_contact').set('html','Message envoyé.');
    break;
 
    default:
      $('result_contact').set('html','Erreur de type inconnu.');
    break;
  }
}

Analyse du formulaire

Par défaut nous mettrons la variable $type (qui défini le type d’erreur) à ‘no’ qui indique qu’aucune erreur n’est apparu lors du traitement.

Pour vérifier qu’un champ ne contienne que les caractères autorisés, utilisez le code ci-dessous. Il n’autorise que les lettres ainsi que les ._- mais ca permet de limiter un maximum les tentatives de fraudes. Si vous voulez autoriser plus que ça, c’est tout à fait autorisé. Mais interdisez à tout pris les saut de lignes, ce sont les plus dangereus pour les injections mail().

if(!preg_match('#^[a-z._-]+$#i', $_POST['nom'])){$fields[] = 'Nom'; $type='field';}

Et pour vérifier l’adresse électronique vous pouvez utiliser l’expression régulière ci-dessous :

if(!preg_match('#^[a-zA-Z0-9]+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$#', $_POST['mail']))
  {$fields[] = '@mail'; $type='field';}

Envoi du mail

Une fois tous les champs vérifiés, nous pouvons procéder à l’envoi du mail. Comme je vous l’expliquai dans l’introduction de ce chapitre, nous allons utiliser une classe PHP qui est très facile à installer et à utiliser. Vous n’avez besoin d’inclure qu’un seul fichier dans votre code pour pouvoir l’utiliser.

include_once 'phpmailer.class.php';

Nous pouvons maintenant crée un objet PHPMailer puis l’utiliser :

try{
 
  $mailer->AddAddress(YOUR_MAIL, YOU);
  $mailer->AddReplyTo($_POST['mail'], $_POST['prenom'].' '.$_POST['nom']);
  $mailer->SetFrom($_POST['mail'], $_POST['prenom'].' '.$_POST['nom']);
  $mailer->Subject = $_POST['sujet'];
  $mailer->AltBody = 'Votre client mail n\'est pas compatible HTML.';
  $mailer->MsgHTML($_POST['message']);
 
  $mailer->Send();
}catch(phpmailerException $e){
 
  $type = 'envoi';
 
}

Sécurité contre le spam

Pour se protéger contre le spam il existe 2 techniques : vérifier que la personne qui rempli le formulaire n’est pas un robot et limiter la fréquence d’envoi des mails.

Se protéger des robots

Pour se protéger contre les robots il faut forcer l’utilisateur à faire une action qui ne pourrait pas être faite par un robot (ou peu de robots). Je vous proposerai aujourd’hui de faire copier un texte contenu dans une image. Peu de robots en sont capables pour le moment.

Vous avez la possibilité d’utiliser d’autres techniques :

mathématiques -> (3 x 4 + 5) = ?
logique -> 1 3 5 7 ?
générale -> en quelle année a eu lieu la prise de la bastille ?

Pour réaliser cette protection je vous conseillerai d’utiliser le même générateur de captcha que moi, il est hyper simple à utiliser.

Dans votre formulaire ajoutez les lignes suivantes pour faire apparaitre l’image à copier.

<img src="img-captcha.php"/>
<input type="text" name="capa"/>

Lors de l’envoi du formulaire, vérifiez que le code copié soit correct. Le deuxième paramètre de la méthodes rends la vérification insensible à la casse.

if( PhpCaptcha::Validate($_POST['capa'], true) ){
 //true
}

Créez maintenant le fichier img-captacha.php :

<?php
  ini_set('display_errors','0');
  include_once 'captcha.class.php';
  $fonts = array('arial.ttf');
  $captcha = new PhpCaptcha($fonts, 180, 40);
  $captcha->Create();
?>

La première ligne du code ci-dessus permet de ne pas afficher les erreurs et d’afficher dans tous les cas un image valide.

Limiter la fréquence

Pour limiter la fréquence d’utilisation du formulaire de contact, nous allons utiliser la session. Tout d’abord, pour s’assurer que le navigateur mémorise bien les sessions, avant d’afficher le formulaire il faut stocker une valeur en session :

$_SESSION['use_session'] = 'yes';

Après l’envoi du mail, il faut créer une variable en session qui mémorisera la date de l’envoi du dernier mail

$_SESSION['contact'] = time();

Ainsi, on vérifiera toujours qu’il y ai au moins 5 minutes entre chaque envoi :

if($_SESSION['contact'] && (time()-$_SESSION['contact'] < 5*60)){
  $type = 'time';
}else{
  // Ici on pourra envoyer le mail
}

Tester un exemple

Comme d’habitude, vous pouvez tester ce formulaire de contact directement dans mon laboratoire ou télécharger la source.

Tagués avec : , , , , , , , , , , , ,
Publié dans Mootools, PHP
6 commentaires pour “Formulaire de contact avec PHPMailer
  1. sdz dit :

    sisi trés bon tuto merci bcp !

  2. serge dit :

    L’exemple en ligne ne marche pas ;: l’adresse mes-tests.myeasyprog.fr/formulaire-contact-phpmailer/ n’est pas valable.
    J’ai téléchargé les sources et j’ai testé sur mon site, mais ça ne marche pas ! le formulaire, le capcha etc. s’affichent bien mais rien ne se passe quand on clique sur « envoyer ». La console web de firefox dit :
    « aucun élément trouvé » contact.php ligne 5
    $(responseXML).getElement(« root error ») is null @ /script.js:16
    firebug signale la meme erreur ligne 16…

  3. Olivier PEREZ dit :

    Merci pour l’info de l’erreur 404. Je viens de corriger ça, tout devrait rentrer dans l’autres assez rapidement.
    Pour l’histoire du « aucun élément trouvé » contact.php, est-ce que le fichier php se trouve bien derrière un apache ou autre serveur d’application ? Le fichier doit être interprété par un interpréteur PHP.

  4. fred dit :

    Merci pour le tuto !!!

    Mais j’ai un problème avec les sources. Je les ai testé sur mon site, mais ça ne marche pas.
    Quand je clique sur envoyé, il affiche « Message envoyé. Vous pourrez envoyer un nouveau message dans 5 minutes. ». Mais je ne reçois pas le mail !!!!

  5. Gérald dit :

    Bonjour,
    Je découvre votre script mais n’arrive pas à le faire fonctionner.
    Après un simple copier/coller de vos fichiers sources sur un serveur mutualisé OVH ainsi que la modification des paramètres du fichier « conf.php », le formulaire semble fonctionner (car aucune erreur renvoyée aussi bien du formulaire que de la console Web de Firefox) mais je ne reçois rien sur le webmail.
    Y aurait-il d’autres paramètres que ceux du fichier config.php à modifier ?
    Merci !!

  6. Olivier PEREZ dit :

    Dans la page d’exemple que je met à votre disposition, la ligne qui envoi le mail ($mailer->Send();) est supprimée, c’est pourquoi vous ne recevez pas le mail (je n’ai pas vraiment envie que mon blog devienne une plateforme de spam).

    Pour la même raison, la version que je vous propose de télécharger mets cette ligne en commentaire. Pour que vos mails s’envoi, il faut dé-commenter cette ligne dans le fichier contact.php.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*