Formulaire HTML de prise de contact sécurisé en PHP

Tutoriel sur la création simple et rapide d'un formulaire sécurisé de prise de contact en PHP. Avec insertion des demandes dans une base de données via PDO.

  Publié le

Introduction

L'objectif de cet article est d'expliquer comment créer un formulaire de prise de contact en PHP et de manière simple et sécuriser. La création d'un formulaire PHP uniquement est impossible et requiert l'aide du HTML (HyperText Markup Language).

 

Dans cet exemple, nous stockerons simplement la demande de prise de contact en base de données (si vous souhaitez envoyer un email, reportez-vous à cette publication).

 

Nb : Le HTML est un langage structuré de balisage qui permet de concevoir l'architecture visuelle d'un site.

La construction du formulaire HTML

Le noeud form contient l'attribut method, qui définit si il faut envoyer la demande en GET (visible dans l'url finale) ou en POST (invisible dans l'url finale). Et l'attribut action, qui cible le script PHP à appeler.

Le premier noeud input de type email attendra une donnée de type email toute autre format sera refusé.

Le second noeud input de type text attendra n'importe quelle donnée.

Le noeud button de type submit permettra de soumettre le formulaire HTML à la page spécifiée par l'attribut action.

<form method="post" action="contact.php">
   <input type="email" name="email" placeholder="nom.prenom@exemple.fr" />
   <input type="text" name="content" placeholder="Votre message" />
   <button type="submit">Envoyer</button>
</form>

La sécurité et le HTML

Règle d'or : en aucun cas, un formulaire HTML ne doit être considéré comme sur.

En cas de modification du formulaire HTML (via l'explorateur de code) il est possible de remplacer le type d'un input par un autre, ainsi un utilisateur mal intentionné pourrait à sa guise transformer un champ email en champ texte et envoyer les données qu'il souhaite.

De même, les données transmises en POST bien qu'invisibles dans l'URL du navigateur sont visibles en cas d'analyse via la console (raccourcie F12 > onglets console > requêtes)

Il est donc fondamental de bien comprendre que tout ce qui émane du client est à considérer comme fallacieux et doit par la suite être contrôlé dans le code sur serveur (ici en php).

Le code PHP du fichier contact.php

//Initialisation de l'objet PDO et ouverture de la connexion pour appel à la base de données
$Pdo_Object = new PDO("mysql:host=127.0.0.1;dbname=DataBase","user","password",array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )); 

try {
   //Contrôle de l'éxistance des deux paramètres email et content
   if(!isset($_POST['email'])) throw new Exception("Le paramètre email est absent");
   if(!isset($_POST['content'])) throw new Exception("Le paramètre content est absent");
   
   //Contrôle des formats des deux paramètres via les expressions régulières
   $Format_Email = '#[a-z0-9]{1,}[\-\_\.a-z0-9]{0,}@[a-z]{2,}[\-\_\.a-z0-9]{0,}\.[a-z]{2,6}$#';
   $Format_Content = '#^[a-zA-Z0-9áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ\.\_\-\s]{5,500}$#'
   if(!preg_match($Format_Email, $_POST['email']))  throw new Exception("Le paramètre email ne correspond pas au format attendu");
   if(!preg_match($Format_Content , $_POST['content']))  throw new Exception("Le paramètre content ne correspond pas au format attendu - limite de 500 caractères");
 
  //Tableau associatif pour requête d'insertion 
  $Arr_Key_Value = array(
                         'email' => $_POST['email'],
                         'content' => $_POST['content']);
  //Requête d'insertion
  $Sql_Query = "INSERT INTO contact(email,content) VALUES (:email,:content)";
  
  //Préparation de la requête (sécurisation des variables du tableau associatif)
  $Request= $Pdo_Object->prepare($Sql_Query);
  
  //Exécution de la requête 
  $Request->execute($Arr_Key_Value);
} catch (Exception $e) {
   echo $e->getMessage(); 
}
finally{
 //Attention le finaly ne fonctionne que sur php 5.6 et supérieur 
 //Fermeture de la connexion en détruisant la référence mémoire à l'objet PDO
 $Pdo_Object = null;
}

Décomposition du code et explications :

Ouverture de la connexion à la base de données MySQL présente à l'adresse IP 127.0.0.1 et accessible via le port TCP par défaut 3306 pour login "user" et pour mot de pass" password". On précise à l'objet de remonter les erreurs mysql sous forme de nouvelle exception.

$Pdo_Object = new PDO("mysql:host=127.0.0.1;dbname=DataBase","user","password",array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )); 

Contrôle de la présence des deux paramètres respectivement email et content, en cas d'absence de l'un ou l'autre des paramètres le script PHP retourne une erreur à l'utilisateur.

if(!isset($_POST['email'])) throw new Exception("Le paramètre email est absent");
if(!isset($_POST['content'])) throw new Exception("Le paramètre content est absent");

Définition des modèles d'expression régulière pour filtrer l'email et le contenu de l'email.

   $Format_Email = '#[a-z0-9]{1,}[\-\_\.a-z0-9]{0,}@[a-z]{2,}[\-\_\.a-z0-9]{0,}\.[a-z]{2,6}$#';
   $Format_Content = '#^[a-zA-Z0-9áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœÁÀÂÄÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸÆŒ\.\_\-\s]{5,500}$#'

Dans le bloc de code suivant, nous contrôlons les formats des données envoyées par l'utilisateur depuis le front. En cas de discordance, le script PHP lève une erreur à l'utilisateur.

 

if(!preg_match($Format_Email, $_POST['email']))  throw new Exception("Le paramètre email ne correspond pas au format attendu");
if(!preg_match($Format_Content , $_POST['content']))  throw new Exception("Le paramètre content ne correspond pas au format attendu - limite de 500 caractères");

Si les deux paramètres correspondent bien au format respectif attendu, création d'un tableau associatif en prévision de la requête SQL.

$Arr_Key_Value = array('email' => $_POST['email'],'content' => $_POST['content']);

Ecriture de la requête d'insertion avec les paramètres :email et :content correspondant aux clés du tableau de la variable $Arr_Key_Value prefixée de de deux points. Puis à l'aide de l'objet PDO préparer la requête pour éviter les risques d'injections SQL.

$Sql_Query = "INSERT INTO contact(email,content) VALUES (:email,:content)";
$Request= $Pdo_Object->prepare($Sql_Query);

Exécution de la requête SQL avec le tableau associatif précédement créée.

$Request->execute($Arr_Key_Value);

Quoiqu'il arrive, nous fermons la connexion avec la base de données, en détruisant la référence mémoire à l'objet PDO.

 

$Pdo_Object = null;