Formulaire d'Inscription (vue)

Afin de créer une ligne dans notre base de donnée, nous allons commencer par créer un Formulaire d'inscription basique contenant 4 champs et un bouton.

  • Un nom d'utilisateur
  • Un email
  • Un mot de passe
  • Une confirmation de mot de passe
  • Le bouton de validation

<form action="" method="post">

    <label for="username">Nom d'utilisateur :</label>
    <input type="text" name="username" id="username" value="<?php echo $username ?>" required>
    <span class="erreur"><?php echo  $error["username"]??""  ?></span><br>

    <label for="email">Adresse Mail :</label>
    <input type="email" name="email" id="email" value="<?php echo $email ?>" required>
    <span class="erreur"><?php echo  $error["email"]??""  ?></span><br>

    <label for="password">Mot de Passe :</label>
    <input type="password" name="password" id="password" required>
    <span class="erreur"><?php echo  $error["password"]??""  ?></span><br>

    <label for="passwordBis">Confirmation de Mot de Passe :</label>
    <input type="password" name="passwordBis" id="passwordBis" required>
    <span class="erreur"><?php echo  $error["passwordBis"]??""  ?></span><br>

    <input type="submit" value="Inscription">
</form>


On laisse ici l'attribut action de la balise <form> vide. Dans de vieux navigateurs, cela pourrait poser problème, et On devrait indiquer obligatoirement une adresse. Mais de nos jours grâce à HTML 5, laisser l'attribut action vide rechargera la même page.

On pourra voir des balises <span> et les values du nom d'utilisateur et de l'adresse mail rempli avec du code php :


/* Si la variable $error["username"] n'existe pas, 
alors affiche une chaîne de caractère vide. */
<?php echo  $error["username"]??"" ?>
<?php echo $username ?>


        

le code php à l'interieur des values sert à donner par défaut la valeur précédement entré par l'utilisateur en cas d'erreur. Cela évitera à l'utilisateur de rentrer à nouveau son nom et son email si jamais il s'est trompé.

Le php dans les spans lui affichera un message d'erreur correspondant au champ qui le précède.
Par défaut, toute ces variables rendent des chaînes de caractère vide.

Traitement du Formulaire (contrôleur)

On commence ici par déclarer toute les variables qu'On utilisera par la suite.
une par champ de notre formulaire, chacune pour contenir la valeur du champ correspondant.
$error servira à vérifier si il y a eu une erreur.


<?php
// On déclare nos variables.
$username = $email = $password = '';
$error = array();
/* regex pour mot de passe avec:
    -cractère spécial;
    -chiffre;
    -majuscule;
    -minuscule;
contenant entre 8 et 20 caractère. */
$regex = "/^(?=.*[!@#$%^&*+-])(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z]).{8,20}$/";


Ensuite On crée une fonction qui aura pour but de nettoyer et sécuriser ce que l'utilisateur écrira.
Elle peut être déclaré en bas de notre code php sans poser problème par le fait de l'appeler avant la déclaration.

   
// On déclare une fonction servant à sécuriser mes champs
function clean($field){
    // retire les caractères d'espacement avant et après la chaîne de caractère
    $field = trim($field);
    // retire les anti slashes \ 
    $field = stripslashes($field);
    // transforme les caractères spéciaux html en une version non interprété :
    // par exemple "<" devient "&lt;"
    $field = htmlspecialchars($field);
    return $field;
}


    

Pour faciliter l'exemple stripslahes et htmlspecialchars sont utilisés en même temps que trim. Mais ils ces deux là n'ont d'intérêt que pour afficher les input de l'utilisateur dans le code html. Ils n'ont aucun intérêt pour l'enregistrement en base de donnée si On fait une requête préparé. (voir plus bas)

On va placer toute la suite de notre code dans la condition suivante en oubliant pas d'inclure dans notre contrôleur, la vue et le modèle.


// Si on arrive sur la page en méthode POST.
if($_SERVER["REQUEST_METHOD"] == "POST"){
    // J'inclus notre modèle gérant les utilisateurs.
    include("../models/user-model.php");
    # Ici tout le traitement de notre formulaire #
    # .......................................... #
}
// Je n'oublie pas d'incluere ma vue.
include("../views/inscription.php");
?>


        

Ensuite, dans notre condition réservé à la méthode POST.
Pour chacun de nos champs, on va vérifier si il est vide et si il correspond à nos attentes.


// On vérifie si j'ai bien des données venant du 
// champ d'attribut name "username"
if(empty($_POST["username"])){
    // On crée un message d'erreur.
    $error["username"] = "Veuillez saisir un username.";
}else{
    // j'ai bien un contenu, On le passe dans ma fonction 
    // précédement créé avant de la ranger dans sa variable.
    $username = clean($_POST["username"]);
    // J'utilise une regex pour vérifier la validité
    // de l'username selon mes choix.
    if(!preg_match("/^[a-zA-Z' \-]*$/",$username)){
        $error["username"]  = "Votre username doit contenir uniquement des lettres.";
    }
}


    

On répète le processus pour tout les champs, variant selon le besoin la regex. De plus on vérifiera que l'utilisateur a rentré deux fois le même mot de passe. Ou bien que l'adresse email existe déjà.


    # vérification de l'email. #
if(empty($_POST["email"])){
    $error["email"] = "Veuillez saisir un email.";
}else{
    $email = clean($_POST["email"]);
    // On fait appel à une fonction de notre modèle que je montrerais plus tard.
    if(selectByEmail($email)){
        $error["email"] = "Cet email existe déjà.";
    }
    /* Utilise la fonction filter_var pour vérifier si l'adresse mail est valide 
    grâce au paramètre FILTER_VALIDATE_EMAIL. Cela peut aussi être fait avec une REGEX */
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
        $error["email"] = "Veuillez saisir un email valide.";
    }
}
    # vérification du mot de passe #
if(empty($_POST["password"])){
    $error["password"] = "Veuillez saisir un mot de passe.";
}else{
    $password = clean($_POST["password"]);
    // vérifie si les mots de passe sont bien identique.
    if($password !== clean($_POST["passwordBis"])){
        $error["passwordBis"] = "Mots de passe différents";
    }else{
        // utilise la regex dans la variable $regex déclaré plus haut.
        if(!preg_match($regex, $password)){
            $error["password"] = "Veuillez saisir un mot de passe valide.";
        }else{
            // crée hachage du mot de passe.
            $password = password_hash($password, PASSWORD_DEFAULT);
        }
    }
    
}


    

Il est important de hacher le mot de passe, afin de ne pas l'enregistrer en clair dans la base de donnée. En cas de fuite de la BDD, il sera très difficile de connaître un mot de passe haché.

Dernière partie pour ce fichier, on va faire appel à notre modèle pour insérer notre nouvel utilisateur en base de donnée.


// Si il n'y a aucune erreur, on fait appel à 
// la fonction ajout (voir plus bas).
if(empty($error)){
    ajout($username, $email, $password);
}


    

La connexion à la base de donnée (modèle)

La dernière étape est notre connexion à la base de donnée.
étape importante, où l'on va devoir faire attention aux injections SQL.
(Pour l'étape de connexion, voir le chapitre dédié)
Cette fonction est celle qui va nous permettre d'ajouter notre nouvel utilisateur.


function ajout($username, $email, $password){
    // On appelle la fonction de connexion
    $pdo = connexion();
    // On prépare ma requête, elle est interprêté maintenant, sans les 
    // valeurs de mes variables.
    $prep = $pdo->prepare(
        'INSERT INTO user(username, email, password) 
        VALUES(:user, :em, :pass)'
        );
    // On lance l'exécution de la requête avec les variables
    // passé en paramètre de ma requête préparé.
    $prep->execute([
        "user"=>$username,
        "em"=>$email,
        "pass"=>$password
    ]);
}


        

Les requêtes préparés permettent d'éviter les injections SQL, bien que légèrement plus gourmande que des requêtes classiques, elles sont le meilleur moyen de se protéger de ce genre d'attaque.
Le principe étant que la requête est interprété en avance puis les variables ajoutés après en tant que simple chaîne de caractère.

Dans notre contrôleur, nous faisons appel à une seconde fonction appelé selectByEmail, elle nous permet de sélectionné un utilisateur par son email.
Par ce fait, si on obtient un résultat, on renvoi une erreur pour indiquer que l'utilisateur existe déjà en base de donnée.


// On défini une fonction permettant de retrouver un utilisateur 
// via son email.
function selectByEmail($email){
    // On appelle notre fonction de connexion
    $pdo = connexion();
    // On prépapre notre requête.
    $prep = $pdo->prepare(
        'SELECT username, email, password FROM user WHERE email = :em'
    );
    // On executé notre requête.
    $prep->execute([
        "em" => $email
    ]);
    // On retourne ce que l'on a trouvé :
    return $prep->fetch();
}


        

Fichiers complets :

  • Modèle
  • Vue
  • Contrôleur

# ---- Ici la connexion rangé dans la variable $pdo ---- #
function ajout($username, $email, $password){
    // On appelle la variable ayant notre connexion pour valeur
    $pdo = connexion();
    // On prépare ma requête, elle est interprêté maintenant, sans les 
    // valeurs de mes variables.
    $prep = $pdo->prepare(
        'INSERT INTO user(username, email, password) 
        VALUES(:user, :em, :pass)'
        );
    // On lance l'exécution de la requête avec les variables
    // passé en paramètre de ma requête préparé.
    $prep->execute([
        "user"=>$username,
        "em"=>$email,
        "pass"=>$password
    ]);
}
// On défini une fonction permettant de retrouver un utilisateur 
// via son email.
function selectByEmail($email){
    // On récupère notre connexion
    $pdo = connexion();
    // On prépapre notre requête.
    $prep = $pdo->prepare(
        'SELECT username, email, password FROM user WHERE email = :em'
    );
    // On executé notre requête.
    $prep->execute([
        "em" => $email
    ]);
    // On retourne ce que l'on a trouvé :
    return $prep->fetch();
}

                

<form action="" method="post">

    <label for="username">Nom d'utilisateur :</label>
    <input type="text" name="username" id="username" value="<?php echo $username ?>" required>
    <span class="erreur"><?php echo  $error["username"]??""  ?></span><br>

    <label for="email">Adresse Mail :</label>
    <input type="email" name="email" id="email" value="<?php echo $email ?>" required>
    <span class="erreur"><?php echo  $error["email"]??""  ?></span><br>

    <label for="password">Mot de Passe :</label>
    <input type="password" name="password" id="password" required>
    <span class="erreur"><?php echo  $error["password"]??""  ?></span><br>

    <label for="passwordBis">Confirmation de Mot de Passe :</label>
    <input type="password" name="passwordBis" id="passwordBis" required>
    <span class="erreur"><?php echo  $error["passwordBis"]??""  ?></span><br>

    <input type="submit" value="Inscription">
</form>

                

<?php
// On déclare nos variables.
$username = $email = $password = '';
$error = array();
/* regex pour mot de passe avec:
    -cractère spécial;
    -chiffre;
    -majuscule;
    -minuscule;
contenant entre 8 et 20 caractère. */
$regex = "/^(?=.*[!@#$%^&*+-])(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z]).{8,20}$/";
// On déclare une fonction servant à sécuriser mes champs
function clean($field){
    // retire les caractères d'espacement avant et après la chaîne de caractère
    $field = trim($field);
    // retire les anti slashes \ 
    $field = stripslashes($field);
    // transforme les caractères spéciaux html en une version non interprété :
    // par exemple "<" devient "<"
    $field = htmlspecialchars($field);
    return $field;
}
// Si on arrive sur la page en méthode POST.
if($_SERVER["REQUEST_METHOD"] == "POST"){
    // J'inclus notre modèle gérant les utilisateurs.
    include("../models/user-model.php");
    // On vérifie si j'ai bien des données venant du 
    // champ d'attribut name "username"
    if(empty($_POST["username"])){
        // On crée un message d'erreur.
        $error["username"] = "Veuillez saisir un username.";
    }else{
        // j'ai bien un contenu, On le passe dans ma fonction 
        // précédement créé avant de la ranger dans sa variable.
        $username = clean($_POST["username"]);
        // J'utilise une regex pour vérifier la validité
        // de l'username selon mes choix.
        if(!preg_match("/^[a-zA-Z' \-]*$/",$username)){
            $error["username"]  = "Votre username doit contenir uniquement des lettres.";
        }
    }
    # vérification de l'email. #
    if(empty($_POST["email"])){
        $error["email"] = "Veuillez saisir un email.";
    }else{
        $email = clean($_POST["email"]);
        // On fait appel à une fonction de notre modèle que je montrerais plus tard.
        if(selectByEmail($email)){
            $error["email"] = "Cet email existe déjà.";
        }
        /* Utilise la fonction filter_var pour vérifier si l'adresse mail est valide 
        grâce au paramètre FILTER_VALIDATE_EMAIL. Cela peut aussi être fait avec une REGEX */
        if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
            $error["email"] = "Veuillez saisir un email valide.";
        }
    }
        # vérification du mot de passe #
    if(empty($_POST["password"])){
        $error["password"] = "Veuillez saisir un mot de passe.";
    }else{
        $password = clean($_POST["password"]);
        // vérifie si les mots de passe sont bien identique.
        if($password !== clean($_POST["passwordBis"])){
            $error["passwordBis"] = "Mots de passe différents";
        }else{
            // utilise la regex dans la variable $regex déclaré plus haut.
            if(!preg_match($regex, $password)){
                $error["password"] = "Veuillez saisir un mot de passe valide.";
            }else{
                // crée hachage du mot de passe.
                $password = password_hash($password, PASSWORD_DEFAULT);
            }
        }
    }
    // Si il n'y a aucune erreur, on fait appel à 
    // la fonction ajout (voir plus bas).
    if(empty($error)){
        ajout($username, $email, $password);
    }
}
// Je n'oublie pas d'incluere ma vue.
include("../views/inscription.php");
?>