290

Structure d'un formulaire

Créez site8 en copiant site7.

  1. /cms
    1. ...
    2. site7
    3. site8

Dans ce chapitre, nous allons ajouter une page de contact avec un formulaire d'envoi d'un email au webmestre du site.

Pour tester le résultat en ligne, entrez http://www.frasq.org/cms/site8 dans la barre d'adresse de votre navigateur. Remplissez le formulaire et envoyez-le. Essayez d'envoyer le formulaire avec des champs vides ou une adresse d'email invalide.

Commencez par créer une action appelée contact en ajoutant le fichier contact.php dans le dossier actions avec le contenu suivant :

  1. /cms/site8
    1. actions
      1. contact.php
  1. function contact($lang) {
  2.     head('title', translate('contact:title', $lang));
  3.     head('description', false);
  4.     head('keywords', false);
  5.     head('robots', 'noindex, nofollow');
  6.  
  7.     $banner = build('banner', $lang);
  8.  
  9.     $mailme = build('mailme', $lang);
  10.  
  11.     $content = view('contact', $lang, compact('mailme'));
  12.  
  13.     $output = layout('standard', compact('banner', 'content'));
  14.  
  15.     return $output;
  16. }

Remarquez que la page de contact n'a pas de description ou de mots clés. La balise robots demande aux moteurs de recherche d'ignorer cette page.

Pour donner l'accès au formulaire, ajoutez un alias par langue dans le fichier includes/aliases.inc :

  1. $aliases = array(
  2.     'fr' => array(
  3.         'accueil'               => 'home',
  4.         'contact'               => 'contact',
  5.     ),
  6.     'en' => array(
  7.         'home'                  => 'home',
  8.         'contact'               => 'contact',
  9.     ),
  10. );

Ajoutez le titre de la page dans le fichier includes/strings.inc.

En français dans le tableau 'fr' :

  1.         'contact:title'         => 'Nous contacter',

En anglais dans le tableau 'en' :

  1.         'contact:title'         => 'Contact us',

Ajoutez la vue de la page de contact dans les dossiers views/fr pour la version en français et views/en pour la version en anglais.

  1. /cms/site8
    1. views
      1. fr
        1. contact.phtml
      2. en
        1. contact.phtml
  1. <h3>Contact</h3>
  2. <?php echo $mailme; ?>
  1. <h3>Contact</h3>
  2. <?php echo $mailme; ?>

La vue est identique en français et en anglais et vous pourriez la sauvegarder directement dans views mais si la ligne de titre change ou si vous ajoutez une autre langue plus tard, les vues seront différentes. Tenez-vous en donc au plan général.

Le formulaire d'envoi d'un email est dans un bloc. Commencez par écrire la vue du bloc, d'abord dans une langue :

  1. /cms/site8
    1. views
      1. fr
        1. contact.phtml
        2. mailme.phtml
  1. <div class="form" id="mailme_form">
  2. <form action="" method="post">
  3. <div class="fields">
  4. <p class="label">Quelle est votre adresse d'email ?</p>
  5. <p class="input"><input type="text" name="mailme_mail" id="mailme_mail" size="50" maxlength="100" title="Email" value="<?php echo htmlspecialchars($mail, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  6. <p class="info">Votre adresse d'email est strictement confidentielle.</p>
  7. <p class="label">Tapez le sujet et le texte de votre message&nbsp;:</p>
  8. <p class="input"><input class="monospace" type="text" name="mailme_subject" id="mailme_subject" size="60" maxlength="100" title="Sujet" value="<?php echo htmlspecialchars($subject, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  9. <p class="input"><textarea class="monospace" name="mailme_message" id="mailme_message" cols="70" rows="8" title="Texte"><?php echo htmlspecialchars($message, ENT_COMPAT, 'UTF-8'); ?></textarea></p>
  10. <p class="submit"><button type="submit" name="mailme_send" id="mailme_send">Envoyer</button></p>
  11. </div>
  12. </form>

Le formulaire comprend 3 champs de saisie : adresse d'email de l'expéditeur, sujet du message et texte du message. 3 variables sont nécessaires : $mail, $subject et $message. Tous les noms des champs sont préfixés par mail_. Le formulaire a un seul bouton appelé mailme_send.

Le reste de la vue gère tous les messages d'erreur ou d'information. Les erreurs possibles sont $missing_mail, $bad_mail, $missing_message, $missing_subject, $bad_subject et $internal_error. Si $email_sent est true, le formulaire signale à l'utilisateur que le message a bien été envoyé.

  1. <?php if ($errors):
  2. extract($errors);
  3. ?>
  4. <div class="errors">
  5. <?php if ($missing_mail): ?>
  6. <p>Vous n'avez pas donné votre adresse d'email.</p>
  7. <?php elseif ($bad_mail): ?>
  8. <p>L'adresse d'email est invalide.</p>
  9. <?php endif; ?>
  10. <?php if ($missing_message): ?>
  11. <p>Le message est vide.</p>
  12. <?php endif; ?>
  13. <?php if ($missing_subject): ?>
  14. <p>N'oubliez pas le sujet.</p>
  15. <?php elseif ($bad_subject): ?>
  16. <p>Le sujet du message est invalide.</p>
  17. <?php endif; ?>
  18. <?php if ($internal_error): ?>
  19. <p>Une erreur interne s'est produite.</p>
  20. <?php endif; ?>
  21. </div>
  22. <?php endif; ?>
  23. <?php if ($infos):
  24. extract($infos);
  25. ?>
  26. <div class="infos">
  27. <?php if ($email_sent): ?>
  28. <p>Votre message a bien été envoyé. Pour revenir à la page d'accueil, <a href="<?php echo $home_page; ?>">cliquez ici</a>.</p>
  29. <?php endif; ?>
  30. </div>
  31. <?php endif; ?>
  32. </div>

Quelques retouches à la feuille de style :

  1. img {vertical-align:middle;}
  2.  
  3. .monospace {font-family:monospace;}
  1. .info {color:#666666;font-size:smaller;font-style:normal;}
  2. .error {color:#df6f6f;font-size:smaller;font-style:italic;}
  3.  
  4. .input .monospace {font-size:medium;}
  5. .errors {color:#df6f6f;font-size:small;font-style:normal;}
  6. .infos {font-style:normal;}

Pour valider la vue, écrivez une première version de la fonction mailme qui se limite à l'affichage du formulaire :

  1. /cms/site8
    1. blocks
      1. mailme.php
  1. function mailme($lang) {
  2.     $mail=$subject=$message=false;
  3.  
  4.     $missing_mail=false;
  5.     $bad_mail=false;
  6.  
  7.     $missing_subject=false;
  8.     $bad_subject=false;
  9.  
  10.     $missing_message=false;
  11.  
  12.     $email_sent=false;
  13.     $home_page=url('home', $lang);
  14.  
  15.     $internal_error=false;
  16.  
  17.     $errors = compact('missing_mail', 'bad_mail', 'missing_subject', 'bad_subject', 'missing_message', 'internal_error');
  18.     $infos = compact('email_sent', 'home_page');
  19.  
  20.     $output = view('mailme', $lang, compact('mail', 'subject', 'message', 'errors', 'infos'));
  21.  
  22.     return $output;
  23. }

Entrez http://localhost/cms/site8/fr/contact dans la barre d'adresse de votre navigateur. Éditez la fonction mailme. Donnez des valeurs aux variables des champs de saisie. Mettez toutes les variables d'erreur et d'information à true. Vérifiez le lien sur la page d'accueil.

Ajoutez la vue en anglais :

  1. /cms/site8
    1. views
      1. en
        1. contact.phtml
        2. mailme.phtml
  1. <div class="form" id="mailme_form">
  2. <form action="" method="post">
  3. <div class="fields">
  4. <p class="label">What is your email address?</p>
  5. <p class="input"><input type="text" name="mailme_mail" id="mailme_mail" size="50" maxlength="100" title="Email" value="<?php echo htmlspecialchars($mail, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  6. <p class="info">Your email address is strickly confidential.</p>
  7. <p class="label">Type in the subject and the text of your message:</p>
  8. <p class="input"><input class="monospace" type="text" name="mailme_subject" id="mailme_subject" size="60" maxlength="100" title="Subject" value="<?php echo htmlspecialchars($subject, ENT_COMPAT, 'UTF-8'); ?>" /></p>
  9. <p class="input"><textarea class="monospace" name="mailme_message" id="mailme_message" cols="70" rows="8" title="Text"><?php echo htmlspecialchars($message, ENT_COMPAT, 'UTF-8'); ?></textarea></p>
  10. <p class="submit"><button type="submit" name="mailme_send" id="mailme_send">Send</button></p>
  11. </div>
  12. </form>
  13. <?php if ($errors):
  14. extract($errors);
  15. ?>
  16. <div class="errors">
  17. <?php if ($missing_mail): ?>
  18. <p>You haven't given your email address.</p>
  19. <?php elseif ($bad_mail): ?>
  20. <p>The email address is invalid.</p>
  21. <?php endif; ?>
  22. <?php if ($missing_message): ?>
  23. <p>The message is empty.</p>
  24. <?php endif; ?>
  25. <?php if ($missing_subject): ?>
  26. <p>Don't forget the subject.</p>
  27. <?php elseif ($bad_subject): ?>
  28. <p>The subject of the message is invalid.</p>
  29. <?php endif; ?>
  30. <?php if ($internal_error): ?>
  31. <p>An internal error has occurred.</p>
  32. <?php endif; ?>
  33. </div>
  34. <?php endif; ?>
  35. <?php if ($infos):
  36. extract($infos);
  37. ?>
  38. <div class="infos">
  39. <?php if ($email_sent): ?>
  40. <p>Your message has been sent. To return to the home page, <a href="<?php echo $home_page; ?>">click here</a>.</p>
  41. <?php endif; ?>
  42. </div>
  43. <?php endif; ?>
  44. </div>

Entrez http://localhost/cms/site8/en/contact dans la barre d'adresse de votre navigateur pour valider la version anglaise.

Une fois la mise au point des vues terminée, vous pouvez passer à l'analyse de la saisie. Bien structurer le code est très important. Le déroulement est toujours le même :

  1. Déterminer l'action demandée et initialiser les variables du formulaire.
  2. Lire les champs de saisie et assigner les variables du formulaire.
  3. Initialiser les variables d'erreur et d'information puis filtrer et valider les données.
  4. Exécuter l'action demandée si aucune erreur n'a été détectée.
  5. Générer la vue du formulaire selon les valeurs calculées.

Complétez mailme avec le code suivant :

  1. require_once 'readarg.php';
  2. require_once 'validatemail.php';
  3. require_once 'ismailinjected.php';

Charge le code des fonctions readarg, validate_mail et is_mail_injected. Chaque fonction est définie dans un fichier séparé dans le dossier library :

  1. /cms/site8
    1. library
      1. readarg.php
      2. validatemail.php
      3. ismailinjected.php
  1. function readarg($s, $trim=true) {
  2.     if ($trim) {
  3.         $s = trim($s);
  4.     }
  5.  
  6.     return $s;
  7. }

Si $trim vaut true, ce qui est le cas par défaut, readarg retire aussi les espaces au début ou à la fin de $s. Appelez systématiquement cette fonction pour filtrer tous les champs retournés par un formulaire.

  1. function readarg($s, $trim=true) {
  2.     if ($trim) {
  3.         $s = trim($s);
  4.     }
  5.     return get_magic_quotes_gpc() ? stripslashes($s) : $s;
  6. }

Dans cette version utilisée avant PHP 7, readarg retire les \ (BACKSLASH) de $s ajoutés automatiquement par PHP dans les variables $_GET et $_POST si le paramètre de configuration magic_quotes_gpc est à true.

  1. function validate_mail($email) {
  2.     return preg_match('/^[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}$/', $email);
  3. }

validate_mail retourne true si $email est une adresse d'email valide, false dans le cas contraire.

  1. function is_mail_injected($s) {
  2.     $injections = array(
  3.     '(\n+)',
  4.     '(\r+)',
  5.     '(\t+)',
  6.     '(%0A+)',
  7.     '(%0D+)',
  8.     '(%08+)',
  9.     '(%09+)'
  10.     );
  11.     $reg = implode('|', $injections);
  12.     $reg = "/$reg/";
  13.  
  14.     return preg_match($reg, $s);
  15. }

is_mail_injected retourne true si $s contient des caractères susceptibles de permettre une injection dans le contenu d'un email, false si $s est sans danger.

  1. function mailme($lang) {
  2.     $action='init';
  3.     if (isset($_POST['mailme_send'])) {
  4.         $action='send';
  5.     }
  6.  
  7.     $mail=$subject=$message=false;

mailme commence par initialiser $action à 'send' si l'utilisateur a appuyé sur le bouton Envoyer ou à 'init' par défaut, quand le formulaire est directement affiché.

  1.     switch($action) {
  2.         case 'send':
  3.             if (isset($_POST['mailme_mail'])) {
  4.                 $mail=strip_tags(readarg($_POST['mailme_mail'], true));
  5.             }
  6.             if (isset($_POST['mailme_subject'])) {
  7.                 $subject=strip_tags(readarg($_POST['mailme_subject'], true));
  8.             }
  9.             if (isset($_POST['mailme_message'])) {
  10.                 $message=strip_tags(readarg($_POST['mailme_message'], true));
  11.             }
  12.             break;
  13.         default:
  14.             break;
  15.     }

Lit les champs de saisie et les filtre avec readarg puis la fonction strip_tags de PHP qui retire toutes les balises potentiellement dangereuses.

  1.     $missing_mail=false;
  2.     $bad_mail=false;
  3.  
  4.     $missing_subject=false;
  5.     $bad_subject=false;
  6.  
  7.     $missing_message=false;
  8.  
  9.     $email_sent=false;
  10.     $home_page=url('home', $lang);
  11.  
  12.     $internal_error=false;
  13.  
  14.     switch($action) {
  15.         case 'send':
  16.             if (!$mail) {
  17.                 $missing_mail=true;
  18.             }
  19.             else if (!validate_mail($mail)) {
  20.                 $bad_mail=true;
  21.             }
  22.             if (!$subject) {
  23.                 $missing_subject=true;
  24.             }
  25.             else if (is_mail_injected($subject)) {
  26.                 $bad_subject=true;
  27.             }
  28.             if (!$message) {
  29.                 $missing_message=true;
  30.             }
  31.  
  32.             break;
  33.         default:
  34.             break;
  35.     }

Initialise toutes les variables d'erreur et d'information avant de valider les données envoyées par le formulaire.

  1.     switch($action) {
  2.         case 'send':
  3.             if ($missing_mail or $bad_mail or $missing_subject or $bad_subject or $missing_message) {
  4.                 break;
  5.             }
  6.  
  7.             require_once 'emailme.php';
  8.  
  9.             $r = emailme($subject, $message, $mail);
  10.  
  11.             if (!$r) {
  12.                 $internal_error=true;
  13.                 break;
  14.             }
  15.  
  16.             $subject=$message=false;
  17.             $email_sent=true;
  18.  
  19.             break;
  20.         default:
  21.             break;
  22.     }

Vérifie qu'aucune erreur n'a été détectée et envoie un courrier au webmestre avec la fonction emailme.

  1.     $errors = compact('missing_mail', 'bad_mail', 'missing_subject', 'bad_subject', 'missing_message', 'internal_error');
  2.     $infos = compact('email_sent', 'home_page');
  3.  
  4.     $output = view('mailme', $lang, compact('mail', 'subject', 'message', 'errors', 'infos'));
  5.  
  6.     return $output;
  7. }

Prépare tous les paramètres de la vue, la génère et retourne son contenu.

Créez la fonction emailme dans le fichier library/emailme.php avec le contenu suivant :

  1. function emailme($subject, $msg, $sender=false) {
  2.     global $webmaster, $mailer;
  3.  
  4.     if (empty($sender)) {
  5.         $sender = $webmaster;
  6.     }
  7.  
  8.     $headers = <<<_SEP_
  9. From: $sender
  10. Return-Path: $sender
  11. Content-Type: text/plain; charset=utf-8
  12. X-Mailer: $mailer
  13. _SEP_;
  14.  
  15.     return @mail($webmaster, $subject, $msg, $headers);
  16. }

Les variables globales $webmaster et $mailer sont définies dans le fichier de configuration includes/config.inc :

  1. global $sitename, $webmaster, $mailer;
  2.  
  3. $sitename = 'frasq.org';
  4. $webmaster = 'nobody@frasq.org';
  5. $mailer = 'Frasq';

Remplacez l'adresse nobody@frasq.org par webmaster@localhost. Vous pouvez aussi changer le nom du mailer.

Éditez le fichier /etc/aliases et rediriger le courrier local envoyé à webmaster vers votre compte personnel :

webmaster:	frasq

NOTE : Remplacez frasq par votre nom de connexion. Notifiez le service :

$ sudo newaliases

Lisez l'article Les outils du développeur web pour apprendre comment installer un service de courrier local.

Entrez http://localhost/cms/site8/fr/contact dans la barre d'adresse de votre navigateur. Remplissez le formulaire et envoyez-le. Vérifiez si vous avez reçu un email à webmaster@localhost. Éditez le code source du courrier et vérifiez les champs de l'en-tête MIME. Essayez d'envoyer le formulaire avec des champs vides, d'entrer une adresse d'email invalide, etc.

La dernière étape consiste à ajouter un menu dans le bandeau de la page d'accueil avec un bouton Contact et un lien dans le pied de page.

  1. /cms/site8
    1. views
      1. fr
        1. footer.phtml
      2. en
        1. footer.phtml
  1. <div id="footer">
  2. <p>&copy;2010-2011 frasq.org - Tous droits réservés - <a href="http://www.frasq.org">www.frasq.org</a></p>
  3. <p><a href="<?php echo $contact_page; ?>">Contact</a>&nbsp;|&nbsp;<img src="<?php echo $base_path; ?>/images/ubuntu.png" alt="" width="16" height="16" />&nbsp;<a href="http://www.ubuntu.com" target="_blank">Ubuntu</a></p>
  4. </div>
  1. <div id="footer">
  2. <p>&copy;2010-2011 frasq.org - All rights reserved - <a href="http://www.frasq.org">www.frasq.org</a></p>
  3. <p><a href="<?php echo $contact_page; ?>">Contact</a>&nbsp;|&nbsp;<img src="<?php echo $base_path; ?>/images/ubuntu.png" alt="" width="16" height="16"/>&nbsp;<a href="http://www.ubuntu.com" target="_blank">Ubuntu</a></p>
  4. </div>

La variable $contact_page est définie par l'action home :

  1. function home($lang) {
  2.     head('title', translate('home:title', $lang));
  3.    
  4.     $languages='home';
  5.     $contact=true;
  6.     $banner = build('banner', $lang, compact('languages', 'contact'));
  7.  
  8.     $contact_page=url('contact', $lang);
  9.     $footer = view('footer', $lang, compact('contact_page'));
  10.  
  11.     $content = view('home', $lang);
  12.  
  13.     $output = layout('standard', compact('banner', 'footer', 'content'));
  14.  
  15.     return $output;
  16. }

home passe l'URL de la page de contact à la vue footer et ajoute contact à la liste des composants du bandeau.

  1. function banner($lang, $components=false) {
  2.     $home_page=url('home', $lang);
  3.     $logo = view('logo', $lang, compact('home_page'));
  4.  
  5.     $menu=$contact=false;
  6.     $languages=false;
  7.     $contact_page=false;
  8.    
  9.     if ($components) {
  10.         foreach ($components as $v => $param) {
  11.             switch ($v) {
  12.                 case 'languages':
  13.                     if ($param) {
  14.                         $languages = build('languages', $lang, $param);
  15.                     }
  16.                     break;
  17.                 case 'contact':
  18.                     $contact_page=url('contact', $lang);
  19.                     $contact = true;
  20.                     break;
  21.                 default:
  22.                     break;
  23.             }
  24.         }
  25.     }
  26.  
  27.     if ($contact) {
  28.         $menu = view('bannermenu', $lang, compact('contact', 'contact_page'));
  29.     }
  30.  
  31.     $output = view('banner', false, compact('logo', 'menu', 'languages'));
  32.  
  33.     return $output;
  34. }

banner passe l'URL de la page de contact à la vue bannermenu qui génère le menu.

  1. /cms/site8
    1. views
      1. fr
        1. bannermenu.phtml
      2. en
        1. bannermenu.phtml
  1. <div id="bannermenu">
  2. <ul class="menu menubar">
  3. <?php if (isset($contact) and $contact): ?>
  4. <li><a id="mail" href="<?php echo $contact_page; ?>" title="Nous contacter"><span>Contact</span></a></li>
  5. <?php endif; ?>
  6. </ul>
  7. </div>
  1. <div id="bannermenu">
  2. <ul class="menu menubar">
  3. <?php if (isset($contact) and $contact): ?>
  4. <li><a id="mail" href="<?php echo $contact_page; ?>" title="Contact us"><span>Contact</span></a></li>
  5. <?php endif; ?>
  6. </ul>
  7. </div>

Modifiez la feuille de style pour afficher un bouton à la place du lien Contact et recentrer les menus :

  1. #bannermenu {width:160px;float:left;margin-top:13px;margin-left:40px;}
  2. #bannermenu #mail {width:24px;height:24px;float:right;margin-left:6px;background:transparent url(../buttons/mail.png) no-repeat center center;}
  3.  
  4. #languages {width:100px;float:left;margin-top:13px;margin-left:20px;}

Copiez l'icône pour le bouton Contact dans le dossier buttons :

  1. /cms/site8
    1. buttons
      1. mail.png

  1. <div id="banner">
  2. <?php
  3. echo $logo;
  4. if (isset($menu)) {
  5.     echo $menu;
  6. }
  7. if (isset($languages)) {
  8.     echo $languages;
  9. }
  10. ?>
  11. </div>

La vue ajoute le code du menu au bandeau si $menu est défini.

Entrez http://localhost/cms/site8 dans la barre d'adresse de votre navigateur.

Commentaires

Votre commentaire :
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip aide 2000

Entrez un maximum de 2000 caractères.
Améliorez la présentation de votre texte avec les balises de formatage suivantes :
[p]paragraphe[/p], [b]gras[/b], [i]italique[/i], [u]souligné[/u], [s]barré[/s], [quote]citation[/quote], [pre]tel quel[/pre], [br]à la ligne,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]commande[/code], [code=langage]code source en c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].