Alain Barraud Mémento informatique  
 
Accueil Logithèque - SE Photo - vidéo Internet - protocoles Site Web PC - Réseau Archives
Page ouverte le 05/03/2010
retour sommaire PHP
Logo PHP
Partie 3 : TP : un Mini-Chat

Passons un peu à l'application. On peut faire des scripts intéressants : Mini-Chat (ce qu'on va faire), livre d'or et même un script de news !
Ces scripts sont similaires, mais le plus simple est le Mini-Chat ou Tribune libre.
Sommaire

Réalisation du Mini-Chat

Etape 1 : prérequis
On va utiliser les notions suivantes :
  • Transmission de variables via un formulaire
  • Lire dans une table
  • Ecrire dans une table
On verra que la transmission de variables par formulaire est très importante. Pour l'instant, on a rapidement vu comment ça marchait dans le chapitre sur les variables. Mais, dans la partie III, on verra cela plus en détail car il y a beaucoup de choses intéressantes à savoir.
Etape 2 : préparation du script
Comme vu au précédent TP, on commence par faire un brouillon.
question Quelles seront les fonctionnalités de mon Mini-Chat ?
On va commencer par quelque chose de basique.
On souhaite avoir, sur la même page, deux zones de texte en haut : une pour écrire son pseudo, une autre pour écrire son petit message. Ensuite, un bouton "Envoyer" permettra d'envoyer les données à MySQL, pour qu'il les enregistre dans une table de la Base de Données.
En-dessous, le script devra afficher les 10 derniers messages qui ont été enregistrés (parce que si on les affiche tous et qu'on a 1000 messages ça risque d'être un peu long !) en allant du plus récent au plus ancien.
Voilà à quoi doit ressembler la page PHP une fois terminée :

Mini-Chat

Bon, comme à chaque fois que l'on se servira d'une base de données, on commencera par étudier la forme de la table (quels seront les champs).

Voici un petit tableau mis sur une feuille de papier brouillon :
IDpseudomessage
1TomIl fait beau aujourd'hui vous trouvez pas ?
2JohnOuais, ça faisait un moment qu'on n'avait pas vu la lumière du soleil !
3PatriceCa vous tente d'aller à la plage aujourd'hui ? Y'a de super vagues !
4TomCool bonne idée ! J'amène ma planche !
5JohnComptez sur moi !
On a un champ ID de type INT (comme toujours) qui permettra de savoir dans quel ordre ont été postés les messages. Il faudra le mettre en auto_increment pour que les numéros s'écrivent tout seuls, et ne pas oublier de sélectionner "Primaire" (ça dit à MySQL que c'est le champ qui numérote les entrées).
Pour les champs "pseudo" et "message", on utilisera le type VARCHAR (penser à indiquer une taille limite dans le champ texte d'à côté : 255 caractères, c'est suffisant, on n'est pas là pour écrire un roman !).
Commençons par créer cette table dans notre base de données. On l'appellera "minichat".

Un fois que c'est fait, comme pour la page protégée par mot de passe, on n'utilisera qu'une seule page. le code ressemblera en gros à cela :

Mini-Chat
Le formulaire doit renvoyer sur la même page. Si notre page s'appelle "minichat.php", alors notre balise de formulaire sera :
<form action="minichat.php" method="post">
Ca rechargera la même page ! Oui, mais cette fois il se passera quelque chose de différent ! En effet, 2 variables seront créées (par exemple $_POST['pseudo'] et $_POST['message']), et on va pouvoir vérifier si elles contiennent quelque chose. SI elles contiennent quelque chose, ALORS on enregistre les données. Sinon, on ne fait rien (je ne veux pas voir de else dans notre code !).

En résumé, lorsque la page se charge, il y a 2 cas :
  • L'utilisateur a posté un message, $_POST['pseudo'] et $_POST['message'] ne sont pas vides. On enregistre ces informations, puis on affiche les 2 zones de texte et les 10 derniers messages.
  • L'utilisateur n'a pas posté de message, $_POST['pseudo'] et $_POST['message'] sont vides. Alors on ne fait rien, on se contente d'afficher les 2 zones de texte et les 10 derniers messages.
alt On aura besoin de deux conditions pour vérifier si nos variables ne sont pas vides :
1) Utiliser un isset pour vérifier si les variables existent (comme dans le premier TP).
2) Puis, si les variables existent, vérifier si elles ne sont pas vides (NULL).
Si ces 2 conditions sont remplies, alors on peut envoyer le message dans la base de données sans crainte.
Ah si… il peut y avoir un problème quand même !
erreur Aleeerte ! Ce n'est pas fini, il reste un point important à voir.
Il faut savoir que si on ne fait pas attention un tel script peut poser problème pour la sécurité du site !
Oui, c'est très important. Ce n'est pas quelque chose de compliqué, pourtant beaucoup de monde l'oublie et ça peut poser problème sur certains sites.
question QUOOIIII ? Je vais me faire hacker mon site à cause de ce script !?
Disons qu'il y a un petit danger.
En effet, si le visiteur poste dans son message du code HTML, celui-ci sera enregistré dans la base de données. Lorsque que quelqu'un affichera son message, le code HTML sera lu !
OK, si le visiteur a posté une balise inoffensive du style <em>, on ne risque rien. Mais il pourrait très bien insérer un code javascript qui affiche une boîte de dialogue (très gênant) ou même qui pourrait scanner nos cookies et récupérer des informations confidentielles !

Bon, assez peur comme ça.
Pour régler le problème en un tour de main, on utilisera une fonction PHP toute prête : htmlspecialchars (déjà vu en partie 2). On l'appliquera aux 2 variables $_POST['pseudo'] et $_POST['message'] :
Code PHP
$message = htmlspecialchars ($_POST['message']);
$pseudo = htmlspecialchars ($_POST['pseudo']);
Ceci permettra d'éviter que le visiteur puisse poster du HTML ou (pire) du Javascript.
Pour être totalement sécurisé ça ne suffit pas. On ne va pas rentrer dans le détail pour le moment (parce que c'est limite un cours de hacking qu'il faudrait après) mais il faut aussi se protéger des injections sql, c'est-à-dire des gens qui, par une technique précise, pourraient essayer d'introduire du code SQL dans le message. C'est particulièrement dangereux.
Pour éviter ça, là encore il suffit d'appliquer une fonction. Le code parfaitement sécurisé à utiliser sera donc :
Code PHP
$message = mysql_real_escape_string(htmlspecialchars($_POST['message']));
$pseudo = mysql_real_escape_string(htmlspecialchars($_POST['pseudo']));
Etape 3 : à nous de jouer !
Là, on est censé travailler !
Etape 4 : correction
Code PHP
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> // voir nécessité d'ajouter lang="fr"
    <head>
        <title>Mini-chat</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <style type="text/css">
    form
    {
    text-align:center;
    }
    </style>
    <body>


<?php
if (isset($_POST['pseudo']) AND isset($_POST['message'])) // Si les variables existent
{
    if ($_POST['pseudo'] != NULL AND $_POST['message'] != NULL) // Si on a quelque chose à enregistrer
    {
        // D'abord, on se connecte à MySQL
        mysql_connect("localhost", "sdz", "mot_de_passe");
        mysql_select_db("coursphp");

        // On utilise les fonctions PHP mysql_real_escape_string et htmlspecialchars pour la sécurité
        $message = mysql_real_escape_string(htmlspecialchars($_POST['message']));
        $pseudo = mysql_real_escape_string(htmlspecialchars($_POST['pseudo']));

        // Ensuite on enregistre le message
        mysql_query("INSERT INTO minichat VALUES('', '$pseudo', '$message')");

        // On se déconnecte de MySQL
        mysql_close();
    }
}


// Que l'on ait enregistré des données ou pas...
// On affiche le formulaire puis les 10 derniers messages

// Tout d'abord le formulaire :
?>



<form action="minichat.php" method="post">

<p>
Pseudo : <input type="text" name="pseudo" /><br />
Message : <input type="text" name="message" /><br />

<input type="submit" value="Envoyer" />
</p>

</form>



<?php

// Maintenant on doit récupérer les 10 dernières entrées de la table
// On se connecte d'abord à MySQL
mysql_connect("localhost", "sdz", "mot_de_passe");
mysql_select_db("coursphp");

// On utilise la requête suivante pour récupérer les 10 derniers messages :
$reponse = mysql_query("SELECT * FROM minichat ORDER BY ID DESC LIMIT 0,10");

// On se déconnecte de MySQL
mysql_close();

// Puis on fait une boucle pour afficher tous les résultats :
while ($donnees = mysql_fetch_array($reponse) )
{
?>

<p><strong><?php echo $donnees['pseudo']; ?></strong> : <?php echo $donnees['message']; ?></p>



<?php
}
// Fin de la boucle, le script est terminé !
?>


    </body>
</html>
Evidemment, pour que le script fonctionne en local, il faut avoir créé la table "minichat".
Comment marche ce script ?
  1. Tout d'abord, on fait un isset sur les deux variables $_POST['pseudo'] et $_POST['message'] pour vérifier si les variables existent. Si elles n'existent pas, on ne va pas plus loin. Si elles existent, on procède à un deuxième test…
  2. La seconde condition vérifie si les variables $_POST['pseudo'] et $_POST['message'] contiennent quelque chose. En effet, il serait ennuyeux qu'un visiteur envoie un message vide ou qu'il ne donne pas son pseudo. Si c'est le cas, alors on va enregistrer les données (en n'oubliant pas d'utiliser mysql_real_escape_string et htmlspecialchars pour les raisons de sécurité expliquées plus tôt).
  3. Ensuite, que l'on ait dû enregistrer quelque chose ou pas, on écrit le code HTML du formulaire. C'est tout bête, on a déjà vu ça dans le chapitre sur les variables et même dans le TP de la protection par mot de passe.
  4. Enfin, on affiche les 10 derniers messages à l'aide de la requête SQL suivante :
    SELECT * FROM minichat ORDER BY ID DESC LIMIT 0,10
    Ce qui signifie : "Sélectionne tous les champs dans minichat (SELECT * FROM minichat), ordonne les entrées dans l'ordre décroissant (ORDER BY ID DESC), et n'en prends que 10 (LIMIT 0,10)"
La première fois qu'on affiche la page, $_POST['pseudo'] et $_POST['message'] n'existent pas, donc PHP n'exécutera pas ce qui se trouve dans la condition du isset.
Si on s'amuse à poster un message, il sera d'abord enregistré dans la base de données. Ensuite, on affiche les messages. Comme le nôtre a été enregistré juste avant, c'est normal qu'il apparaisse de suite !
Etape 5 : améliorer ce script !
Simplement pour donner des idées car il n'y a pas de correction pour chacune des idées.
Donc, quelques idées pour améliorer le script :
  • Retenir le pseudo. Le pseudo qu'a tapé le visiteur se trouve dans la variable $_POST['pseudo'].Et il est possible en HTML de pré-remplir un champ avec l'attribut "value". Par exemple :
    Code HTML
    <input type="text" name=""pseudo" value="alain33" />
    Remplacer alain33 par un echo de $_POST['pseudo'], et le pseudo sera automatiquement inscrit !
  • Empêcher les messages en double. En effet, si on actualise la page (touche F5) pour voir s'il y a de nouveaux messages, notre navigateur va nous demander s'il doit renvoyer les informations… Si on dites "oui", alors le message qu'il vient d'envoyer sera réenvoyé, ce qui fait qu'il apparaîtra en double !Pour éviter cela, il y a bien une solution : avant d'enregistrer un message, on vérifie que le dernier message posté n'est pas identique. Si c'est le même, on n'enregistre pas le message (sinon on aurait eu un double !).
  • Supprimer automatiquement les vieux messages. A chaque fois qu'un nouveau message va être posté, on compte le nombre total de messages dans la table. S'il y en a par exemple plus de 1000, on supprime le plus vieux, histoire de faire de la place pour pas trop encombrer notre base de données (à moins de vouloir garder un historique complet)

Autres conseils pour finir.
- Amélioration du graphisme
- Amélioration du code PHP comme, par exemple, ajouter un champ qui enregistre l'heure du message.