Mini tuto : Bien vérifié et protéger un formulaire en PHP

TheOldNoob

TheOldNoob Le 8 février 2017 à 22:21 (Édité le 25 janvier 2019 à 17:53)

Bonjour à toute et a tous !

Je me permet de posé se bout de code, qui n'est pas vraiment un tuto, mais simplement un traitement de formulaire avec un max de commentaires.

Je fait se topic, car je vois souvent vos demande qui suive les tutos de PrimFX dont je n'ai rien a redire a mon niveau.
Mais, il faut aller plus loin, car si l'un de vous souhaite mettre un formulaire tel que en ligne, ça risque de posé des problèmes de sécurité :(

<?php
require_once 'connect.php'; // Connexion a votre bdd qui doit être faite dans un fichier séparé.
// On instancie nos variables qu'on utilisera plus tard
// $post contiendra toutes nos données du formulaires nettoyées
// $error contiendra les futures erreurs et pourra être réutilisé pour l'affichage 
$post = array();
$error = array();
$displayErr = false;
$formValid = false;
// On vérifie que notre formulaire n'est pas vide
if(!empty($_POST)){
   // On recréer le tableau en le nettoyant des espaces vides en début et fin de chaine
   // et de l'éventuel code HTML / PHP
   foreach($_POST as $key => $value){ // Permet de nettoyer les données reçus
      $post[$key] = trim(strip_tags($value));
      // trim => supprime les espaces vides en début et fin de chaine
      // strip_tags => retire toutes les balises html
   }
   if(strlen($post['titre']) < 10 || strlen($post['titre']) > 50){ // Le titre doit comporter entre 10 et 50 caractères
      $error[] = 'Le titre de la news doit comporter entre 10 et 50 caractères'; // Sinon, il y a une erreur et on affiche un message
   }
   if(!filter_var($post['lien'], FILTER_VALIDATE_URL)){ // Si l'email est invalide (on note le ! devant la fonction)
      $error[] = 'Le lien de l\'image n\'est pas une URL valide';
   }
   if(empty($post['content'])){ // Le contenue de l'input n'a pas de limite en longueur, on vérifi juste qu'il est bien rempli
      $error[] = 'Le contenu de la news doit être rempli, sinon personne ne pourra la lire :-)';
   }
   if(strlen($post['phone']) != 10){ // On vérifie qu'elle n'est pas différente de 10
      $error[] = 'Le téléphone doit faire 10 caractères';
   }
   if(empty($post['reco']) && $post['reco'] != 'oui' && $post['reco'] != 'non'){
      $error[] = 'Renseignez si cet article est recommandé ou non'; // Verification sur bouton radio
   }
   else {
      // Dans la base de données, on stock un booleen. Il faut donc convertir nos valeurs
      // C'est $recommande qu'on passera dans le bindValue()
      if($post['reco'] == 'oui'){
         $recommande = 1;
      }
      elseif($post['reco'] == 'non'){
         $recommande = 0;
      }
   }
   if(count($error) > 0){
      $displayErr = true;
   }
   else {
      // Ici je suis sur de ne pas avoir d'erreurs, donc je peux faire du traitement.
      $res = $bdd->prepare('INSERT INTO news (title, link, content, phone, reco, date_add) VALUES(:titleArticle, :linkArticle, :contentArticle, 😋honeUser, :recoArticle, :dateArticle)');
      $res->bindValue(':titleArticle', $post['titre']); // Si pas de PDO, alors automatiquement PARAM_STR
      $res->bindValue(':linkArticle', $post['lien'], PDO::PARAM_STR);
      $res->bindValue(':contentArticle', $post['content'], PDO::PARAM_STR);
      $res->bindValue(':phoneUser', $post['phone'], PDO::PARAM_INT);
      $res->bindValue(':recoArticle', $recommande, PDO::PARAM_BOOL);
      $res->bindValue(':dateArticle', date('Y-m-d'), PDO::PARAM_STR);
      // retourne un booleen => true si tout est ok, false sinon
      if($res->execute()){
         $formValid = true; // Pour afficher le message de réussite si tout est bon
      }
      else {
         // Permettra d'afficher les erreurs éventuelles
         die(print_r($res->errorInfo()));
      }
   }
}
TheOldNoob

TheOldNoob Le 8 février 2017 à 22:23

Et si vous voulez aller encore plus loin, renseigné vous sur les expressions régulières  aka REGEX ////
Balatharas

Balatharas Le 22 mars 2017 à 15:20 (Édité le 22 mars 2017 à 15:21)

Salut je me permets de déterrer le sujet
A quoi sert les crochets après $error ?
+ a quoi ça sert ça:
 $res->bindValue(':titleArticle', $post['titre']); // Si pas de PDO, alors automatiquement PARAM_STR
$res->bindValue(':linkArticle', $post['lien'], PDO::PARAM_STR);
$res->bindValue(':contentArticle', $post['content'], PDO::PARAM_STR);
$res->bindValue(':phoneUser', $post['phone'], PDO::PARAM_INT);
$res->bindValue(':recoArticle', $recommande, PDO::PARAM_BOOL);
$res->bindValue(':dateArticle', date('Y-m-d'), PDO::PARAM_STR);
Zbuu

Zbuu Le 22 mars 2017 à 19:04 (Édité le 22 mars 2017 à 19:07)

Yop ! 

Les crochets permettent de faire la même chose qu'un array_push c'est à dire d'ajouter la valeur dans le tableau $error qu'il déclare au début du code. 

Les bindValue est juste l'une des manières d'associé une valeur à ta requête  
$res = $bdd->prepare('INSERT INTO news (title, link, content, phone, reco, date_add) VALUES(:titleArticle, :linkArticle, :contentArticle, honeUser, :recoArticle, :dateArticle)');
$res->bindValue(':titleArticle', $post['titre']); // Si pas de PDO, alors automatiquement PARAM_STR
$res->bindValue(':linkArticle', $post['lien'], PDO::PARAM_STR);
// ETC...
$res->execute();
Autre manière avec bindParam avec des marqueurs nommés :

$res = $bdd->prepare('INSERT INTO news (title, link, content, phone, reco, date_add) VALUES(:titleArticle, :linkArticle, :contentArticle, honeUser, :recoArticle, :dateArticle)');
$res->bindParam(':titleArticle', $post['titre']); // Si pas de PDO, alors automatiquement PARAM_STR
$res->bindParam(':linkArticle', $post['lien'], PDO::PARAM_STR);
// ETC...
$res->execute();
Avec bindParam avec des marqueurs interrogatif (pas sur du nom) :

$res = $bdd->prepare('INSERT INTO news (title, link, content, phone, reco, date_add) VALUES(?, ?, ?, ?, ?, ?)');
$res->bindParam(1, $post['titre']); // Si pas de PDO, alors automatiquement PARAM_STR
$res->bindParam(2, $post['lien'], PDO::PARAM_STR);
// ETC...
$res->execute();

En passant directement les paramêtres dans un la fonction execute

$res->execute(array(
   ':titleArticle' => $_POST['titre'],
   ':linkArticle' => $_POST['lien'],
   // ETC...
));
Balatharas

Balatharas Le 22 mars 2017 à 19:20

En passant directement les paramêtres dans un la fonction execute

$res->execute(array(
   ':titleArticle' => $_POST['titre'],
   ':linkArticle' => $_POST['lien'],
   // ETC...
));

Je me suis contenté de ça et ça a marché
$ins = $bdd->prepare('INSERT INTO c_messages(id_convo, id_sender, id_receiver, content, lu_sender, lu_receiver, datesend) VALUES(:idconvo, :idsender, :idreceiver, :content, :lusender, :lureceiver, NOW())');
$ins->bindValue(':idconvo', $getid, PDO::PARAM_INT);
$ins->bindValue(':idsender', $user['id'], PDO::PARAM_INT);
$ins->bindValue(':idreceiver', $idreceivmsg, PDO::PARAM_INT);
$ins->bindValue(':content', $post['message'], PDO::PARAM_STR);
$ins->bindValue(':lusender', 1, PDO::PARAM_INT);
$ins->bindValue(':lureceiver', 0, PDO::PARAM_INT);
$ins->execute();
Ca ne pose pas de problème si ?
TheOldNoob

TheOldNoob Le 22 mars 2017 à 20:17

Voilà, j'ai rien a dire sur mon tuto, tout et expliquer par Zbuu 😀
Zbuu

Zbuu Le 23 mars 2017 à 02:17

Je me suis contenté de ça et ça a marché 
$ins = $bdd->prepare('INSERT INTO c_messages(id_convo, id_sender, id_receiver, content, lu_sender, lu_receiver, datesend) VALUES(:idconvo, :idsender, :idreceiver, :content, :lusender, :lureceiver, NOW())');$ins->bindValue(':idconvo', $getid, PDO::PARAM_INT);$ins->bindValue(':idsender', $user['id'], PDO::PARAM_INT);$ins->bindValue(':idreceiver', $idreceivmsg, PDO::PARAM_INT);$ins->bindValue(':content', $post['message'], PDO::PARAM_STR);$ins->bindValue(':lusender', 1, PDO::PARAM_INT);$ins->bindValue(':lureceiver', 0, PDO::PARAM_INT);$ins->execute();
Ca ne pose pas de problème si ?
Ça peut poser problème (je prends en exemple ta requête) seulement si le type que tu as renseigné ne correspond pas à la valeur donnée.

Pour être plus clair (désolé c'est pas mon fort les explications) si tu mets PDO::PARAM_INT alors que la valeur est "salut tout le monde" (donc une string) alors tu aura une erreur
Balatharas

Balatharas Le 23 mars 2017 à 17:54

Oui donc c'est bien ce que je dis, le contenu de execute() n'est pas obligé d'être sous la forme que tu as donné (avec un tableau etc) ^^
TheOldNoob

TheOldNoob Le 23 mars 2017 à 20:12

Rien n'est jamais vraiment obligatoire. L'idée que je propose c'est un formulaire sécurisé. Après libre a vous de l'adapter 😀
Zbuu

Zbuu Le 23 mars 2017 à 22:24

Oui donc c'est bien ce que je dis, le contenu de execute() n'est pas obligé d'être sous la forme que tu as donné (avec un tableau etc) ^^
Je n'ai pas dit que c'était obligatoire, je n'ai fais que répondre à tes questions, et te montré les différentes manières de faire :) 

Et comme le dit @TheOldNoob rien n'est jamais vraiment obligatoire (surtout en PHP qui est langage pas très stricte 😀)
Balatharas

Balatharas Le 24 mars 2017 à 20:58

Oui merci du coup 😋
Vous devez être connecté pour poster une réponse. Se connecter ou Créer un compte