Live-Coding : Créer un chat en Ajax de A à Z

15 mai 2020 - : Javascript Tutoriel Live-Coding - : 0 commentaire - Tutoriel Javascript Ajax PHP Live-Coding

Dernière modification le 16 mai 2020

Dans ce live-coding, nous allons créer un chat géré en Ajax.

Cette méthode permet de découvrir ou redécouvrir le fonctionnement d'Ajax.

Attention : ceci est une introduction, cette méthode ne sera pas optimale et l'utilisation des websockets, par exemple, sera plus conseillée pour les sites ayant du trafic.

Base de données

Nous utiliserons une base de données simple contenant deux tables.

La table "users" contiendra 4 champs

  • id, clé primaire
  • email
  • password, chiffré
  • pseudo

La table "messages" contiendra 4 champs

  • id, clé primaire
  • message
  • created_at, automatique
  • users_id, clé étrangère de "users"

Base de données

Fichiers de base

Nous mettons en place quelques fichiers de base, téléchargeables sur Github, qui permettront de voir l'interface de chat et de gérer la session des utilisateurs.

Ces fichiers sont structurés comme ceci

Liste des fichiers

Les fichiers sont utilisés comme suit :

  • styles.css : fichier CSS du projet
  • bdd.php : fichier de connexion à la base de données
  • footer.php : pied de pages
  • header.php : entêtes de pages
  • scripts.js : fichier qui contiendra notre code javascript
  • client_chat.sql : base de données
  • connexion.php : page de connexion utilisateur
  • deconnexion.php : page de déconnexion utilisateur
  • index.php : page d'accueil, page principale du chat
  • inscription.php : page d'inscription des utilisateurs

Envoi des messages

Une fois connecté, l'utilisateur pourra poster des messages de chat en remplissant le champ en bas de page et en validant (entrée et clic sur la coche)

Partie Javascript

Nous aurons donc besoin d'écouter 2 évènements, l'un sur la zone de texte pour la touche entrée, l'autre sur la coche pour le clic.

window.onload = () => {
    // On va chercher la zone de texte
    let texte = document.querySelector("#texte")
    texte.addEventListener("keyup", verifEntree)
    
    // On va chercher le bouton "valid"
    let valid = document.querySelector("#valid")
    valid.addEventListener("click", ajoutMessage)
}

Nous devons maintenant vérifier si la touche appuyée est la touche entrée, puis exécuter la fonction "ajoutMessage"

function verifEntree(e){
    if(e.key == "Enter"){
        ajoutMessage()
    }
}

La fonction "ajoutMessage" se chargera d'envoyer une requête Ajax à notre serveur pour enregistrer le message

function ajoutMessage() {
    // On récupère la valeur dans le champ "texte"
    let message = document.querySelector("#texte").value

    // On vérifie si on a un message
    if (message != "") {
        // On crée un objet JS pour le message
        let donnees = {}
        donnees["message"] = message

        // On convertit les données en json
        let donneesJson = JSON.stringify(donnees)

        // On envoie les données en POST en Ajax
        // On instancie XMLHttpRequest
        let xmlhttp = new XMLHttpRequest()

        // On gère la réponse
        xmlhttp.onreadystatechange = function(){
            if (this.readyState == 4) {
                if(this.status == 201) {
                    // On a une réponse
                    // On efface le champ texte
                    document.querySelector("#texte").value = ""
                }else{
                    // On reçoit une erreur, on l'affiche
                    let reponse = JSON.parse(this.response)
                    alert(reponse.message)
                }
            }
        }

        // On ouvre la requête
        xmlhttp.open("POST", "ajax/ajoutMessage.php");

        // On envoie la requête avec les données
        xmlhttp.send(donneesJson);
    }
}

Partie PHP

Une fois la partie javascript en place, nous allons devoir traiter les données reçues en PHP pour :

  • Vérifier que la méthode utilisée est la bonne
  • Vérifier que l'utilisateur est connecté
  • Vérifier qu'on a bien un message
  • Sauvegarder le message
<?php
// Ce fichier ajoute un message dans la base de données
session_start();

// On vérifie la méthode
if($_SERVER['REQUEST_METHOD'] == 'POST'){
    // Bonne méthode
    // On vérifie si l'utilisateur est connecté
    if(isset($_SESSION['user']['id'])){
        // L'utilisateur est connecté
        // On récupère les données
        $donneesJson = file_get_contents('php://input');
        // On convertit les données
        $donnees = json_decode($donneesJson);

        // On vérifie qu'il y a un message
        if(isset($donnees->message) && !empty($donnees->message)){
            // Le message n'est pas vide
            // On peut l'enregistrer
            // On se connecte
            require_once('../inc/bdd.php');

            // On écrit la requête
            $sql = 'INSERT INTO `messages`(`message`, `users_id`) VALUES (:message, :user)';

            // On prépare la requête
            $requete = $db->prepare($sql);

            // On injecte les valeurs
            $requete->bindValue(':message', strip_tags($donnees->message), PDO::PARAM_STR);
            $requete->bindValue(':user', $_SESSION['user']['id'], PDO::PARAM_INT);

            // On exécute la requête en vérifiant qu'elle fonctionne
            if($requete->execute()){
                http_response_code(201);
                echo json_encode(['message' => 'Message enregistré']);
            }else{
                http_response_code(400);
                echo json_encode(['message' => 'Une erreur est survenue']);
            }
            // On libère $db
            $db = null;
        }else{
            // Le message est indéfini ou vide
            http_response_code(400);
            echo json_encode(['message' => 'Le message est vide']);    
        }
    }else{
        // L'utilisateur n'est pas connecté
        http_response_code(400);
        echo json_encode(['message' => 'Vous n\'êtes pas connecté(e)']);
    }
}else{
    // Mauvaise méthode
    http_response_code(405);
    echo json_encode(['message' => 'Mauvaise méthode']);
}

Afficher la liste des messages

Pour afficher la liste des messages, notre page d'accueil appellera un fichier PHP en Ajax à intervalle régulier (toutes les secondes dans notre exemple) qui fonctionnera comme suit :

  • affichera les 5 derniers messages au chargement de la page
  • affichera les nouveaux messages qui auraient été publiés depuis le chargement de la page

Nous allons donc devoir conserver l'id du dernier message affiché afin de ne charger que les messages nécessaires.

Le javascript

Dans notre fichier javascript, nous commençons par créer une variable globale permettant de conserver le dernier id chargé.

// Variables globales
let lastId = 0

Nous allons ensuite exécuter une fonction "chargeMessages" toutes les secondes (par exemple) en ajoutant la ligne ci-dessous dans "window.onload"

setInterval(chargeMessages, 1000)

Enfin, notre fonction "chargeMessages" enverra l'id du dernier message en Ajax à notre fichier "chargeMessages.php" et recevra les messages nouvellement créés (ou les 5 derniers si on recharge la page) puis les affichera dans la discussion.

function chargeMessages() {
    // On charge les messages en Ajax
    // On instancie XMLHttpRequest
    let xmlhttp = new XMLHttpRequest()

    // On gère la réponse
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4) {
            if (this.status == 200) {
                // On a une réponse
                // On convertit le JSON en objet JS
                let messages = JSON.parse(this.response)

                // On retourne la liste pour traiter l'ID le plus élevé en dernier
                messages.reverse();

                // On récupère la div "discussion"
                let discussion = document.querySelector("#discussion")

                // On boucle sur les messages
                for (let message of messages) {
                    // On transforme la date en objet JS
                    let dateMessage = new Date(message.created_at)

                    // On ajoute le message avant le contenu déjà en place
                    discussion.innerHTML = `<p>${message.pseudo} a écrit le ${dateMessage.toLocaleString()} : ${message.message}</p>` + discussion.innerHTML

                    // On met à jour l'id
                    lastId = message.id
                }
            }else{
                // On gère les erreurs
                let erreur = JSON.parse(this.response)
                alert(erreur.message)
            }
        }
    }

    // On ouvre la requête
    xmlhttp.open("GET", "ajax/chargeMessages.php?lastId="+lastId)

    // On envoie la requête
    xmlhttp.send()
}

Le PHP

Il reste à créer le fichier "chargeMessages.php" qui récupérera les derniers messages publiés et les renverra en JSON.

Nous aurons 2 cas

  • L'id du dernier message est égal à 0, on vient de charger la page, on envoie les 5 derniers messages
  • L'id du dernier message est > 0, on charge les messages supérieurs à cet id (les nouveaux messages arrivés)

Le code sera le suivant

<?php
// On vérifie la méthode utilisée par la requête ajax
if($_SERVER['REQUEST_METHOD'] == 'GET'){
    // On est en GET
    // On vérifie si on a un id
    if(isset($_GET['lastId'])){
        // On récupère l'id et on nettoie
        $lastId = (int)strip_tags($_GET['lastId']);

        $filtre = ($lastId > 0) ? " WHERE `messages`.`id` > $lastId" : '';

        // On va chercher les messages
        // On se connecte à la bdd
        require_once('../inc/bdd.php');

        // On écrit la requête
        $sql = 'SELECT `messages`.`id`, `messages`.`message`, `messages`.`created_at`, `users`.`pseudo` FROM `messages` LEFT JOIN `users` ON `messages`.`users_id` = `users`.`id`'.$filtre.' ORDER BY `id` DESC LIMIT 5';

        // On exécute la requête
        $requete = $db->query($sql);

        // On récupère les données
        $messages = $requete->fetchAll();

        // On convertit en json
        $messagesJson = json_encode($messages);

        // On envoie
        echo $messagesJson;
    }
}else{
    // Mauvaise méthode
    http_response_code(405);
    echo json_encode(['message' => 'Mauvaise méthode']);
}

Et voilà, un petit chat opérationnel !

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat

Les fichiers de cet article sont disponibles sur Github

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

Ecrire un commentaire

Pas encore de commentaire

Ecrire un commentaire