Créer un minichat pour votre site web qui se rafraîchit automatiquement en PHP/AJAX

Introduction :

Bonjour, aujourd'hui je vais vous apprendre à réaliser un minichat que vous pourrez mettre en place sur votre site web.
J'ai tout d'abord choisi le PHP/MySQL donc il faut quelques notions en PHP et bases de données ainsi qu'en HTML. Le PHP va nous permettre l'interaction entre notre page web (notre minichat) et la base de données (MySQL). En d'autres termes, vous avez un formulaire avec un champ pseudo et un champ message et quand vous cliquez sur un bouton, votre message est envoyé au serveur et stocké dans la base de données.
Ensuite, toujours grâce au PHP, nous irons lire la base de données, récupérer tous les champs et afficher tous les pseudo et leurs messages associés.

Vous allez me dire "Eh bien c'est tout ce qui nous faut pour faire un chat!" et je vais dire oui! mais...
Le PHP ne permet pas d'actualiser la page (à part en la rechargeant) pour voir si de nouveaux messages ont été écrit, il faut pour cela recharger la page via la touche F5.
D'où le fait que je vais utiliser l'AJAX, du javascript qui permet d'envoyer des requêtes au serveur, on peut demander un fichier PHP, HTML ou XML par exemple. AJAX permet donc de récupérer le contenu stocké ou généré par le serveur de façon totalement transparente pour l'utilisateur. Lorsqu'il a fini, il affiche le résultat (du texte) grâce à javascript, permettant ainsi le non-rechargement de la page web.

Sommaire :


Création de la base de données dans PHPMYADMIN :

Tout d'abord, accédez à votre page d'administration de votre base de données, dans la plupart des cas PHPMYADMIN.

Créer base PHPMYADMIN

Créez une base par exemple appelez-là : minichat. Cette fenêtre devrai apparaître:
Ensuite il faut créer notre table : appelez-là de nouveau minichat et spécifiez qu'il faut 3 champs.

Créer table PHPMYADMIN

Les trois champs de notre table sont :

  • id : nous permet de numéroter chaque message
  • pseudo : enregistre le pseudo du message
  • message : qui contient le contenu du message
  • timestamp : qui contient l'heure en secondes à laquelle le message a été posté (OPTIONNEL)

id sera de type INT et de longueur 255, se sera unique donc on le définit en tant que clé primaire et en auto incrémente (comme ça il change tout seul).
pseudo sera de type VARCHAR et de longueur 32
message sera aussi de type VARCHAR et de longueur 255

Créer structure 1
Créer structure 2


Vous pouvez si vous le souhaitez ajouter le champ timestamp, de type INT et de longueur 255.
Il ne vous reste plus qu'à appuyer sur le bouton SAUVEGARDER. La création de la base de données ce termine ici! Passons au HTML.

Voici le script de création de table au cas où vous n'aurez pas PhpMyAdmin :

CREATE TABLE IF NOT EXISTS `minichat` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `pseudo` varchar(32) NOT NULL,
  `message` varchar(255) NOT NULL,
  `timestamp` int(255) NOT NULL,
  PRIMARY KEY (`id`)
)

Création de la page de notre chat (minichat.html) :

Nous allons maintenant passer à l'affichage de notre minichat, Puis j'utiliserai AJAX pour effectuer mes requetes automatiquement.
Particularité : je ne mets pas de formulaire dans le HTML (pas de <form method="post"> ...) tout sera géré en Javascript.
Je n'ai donc besoin que des champs input.
Je vous mets donc à disposition le code HTML du minichat (sans aucune mise en forme via CSS):

<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="Content-Language" content="fr" />
<meta name="Copyright" content="Prozero" />
<meta name="Author" content="Aure77" />
<title>Mini-Chat</title>
<script type="text/javascript">
// <![CDATA[
// Notre javascript/AJAX ici
// ]]>
</script>
</head>
<body onload="fonction_javascript_rafraichir();">
<h1>Mini-Chat</h1>
<!-- Affichage du minichat ici -->
<div id="minichat"></div>
<!-- Fin Affichage du minichat -->
<p>
Pseudo : <br/><input type="text" name="pseudo" id="pseudo" /><br />
Message : <br/><textarea name="message" rows="5" cols="30" id="message"></textarea><br />
<input type="button" value="Envoyer" onclick="fonction_javascript_envoi();"/>
</p>
</body>
</html>

Comme vous pouvez le constater, vous avez une zone de texte pour mettre votre pseudo, une textarea pour le message et un bouton pour l'envoi.
Pour le moment c'est bien beau, mais ça ne fais rien! Passons donc au traitement en PHP!


Création de la page de traitement des messages en PHP (minichat.php) :

Ceci est notre page de traitement, nous allons utiliser la méthode POST pour récupérer les valeurs des champs pseudo et message.
Eh là vous allez me dire : "Une méthode post, alors qu'on n'a pas mis de formulaire, y a un blem là?". Eh bien non c'est normal! On verra ça plus tard, mais c'est notre AJAX qui fera tout ça...

<?php
header("Content-Type: text/html; charset=iso-8859-1"); // On crée un header qui formate la page en texte
mysql_connect("localhost", "root", ""); // On ouvre une connexion à la base de données avec nos identifiants
mysql_select_db("minichat"); // On selectionne la base qui contient notre table pour le chat
if (isset($_POST['pseudo']) && isset($_POST['message']))  // Si on reçoit des données via une méthode POST
{
    if(!empty($_POST['pseudo']) && !empty($_POST['message'])) // Et si leur valeur n'est ni NULL, ni vide
    {
	// Alors les requetes pour écrire le pseudo et le message dans la base de données ici
    }
}
 
// On affiche les messages de notre chat ici
 
mysql_close(); // On ferme la connexion de notre base de données
?>

Comme vous pouvez le voir dans ce code PHP, il y a 2 phases :

  • Si des données sont transmisent à minichat.php par méthode POST, alors on insère les valeurs dans la base de données
  • Dans tout les cas on lit la base de données et on affiche son contenu

Nous allons commencer par la requete qui permet d'afficher les messages:
Tout d'abord, il va falloir faire une requete SQL SELECT sur l'ensemble de la table minichat.
SELECT * FROM minichat ORDER BY id DESC LIMIT 0,10
Traduction : On selectionne toutes les lignes de la table minichat qu'on trie par id décroissant dans une limite de 10 messages
ça c'est du SQL, maintenant comment executer cette requête dans notre PHP ? Réponse:

// On selectionne toute la table minichat triée par id avec une limite de 10 messages
$reponse = mysql_query("SELECT * FROM minichat ORDER BY id DESC LIMIT 0,10");
// on récupère le résultat dans $reponse
 

mysql_query permet d'effectuer une requete sur la base de données en PHP et $reponse est donc le résultat de la requête.
Ensuite il nous faut parcourir chaque ligne de cette requete et afficher les valeurs dans une boucle (ici while).
Pour parcourir $reponse on utilise mysql_fetch_array, qui transforme le résultat en un tableau associatif.

<?php
// On selectionne toute la table minichat triée par id avec une limite de 10 messages
$reponse = mysql_query("SELECT * FROM minichat ORDER BY id DESC LIMIT 0,10");
// On crée un tableau associatif et on le parcours jusqu'à ce qu'il n'y ai plus de valeurs
while($val = mysql_fetch_array($reponse))
{
// On affiche les messages de la forme (en exemple) : <p><strong>Aure77<strong> à 12:01:45 : Ceci est mon message</p>
	echo "<p><strong>".$val['pseudo']."</strong> 
	à ".date('H\:i\:s', $val['timestamp'])." : ".$val['message'];."</p>"
}
?>

Avec while($val = mysql_fetch_array($reponse)), on crée un tableau associatif pour chaque ligne de notre requête et donc pour accéder à nos champs, on utilise notre tableau ainsi : $val['nom_du_champs_dans_la_base_de_donnee'];
Ici nous pouvons accéder à 3 (4 avec l'optionnel) valeurs qui sont :

  • $val['id'] -> contient l'id du message
  • $val['pseudo'] -> contient le pseudo
  • $val['message'] -> contient le message
  • $val['timestamp'] -> contient le temps en secondes (OPTIONNEL)

Maintenant on va s'occuper de l'enregistrement dans la base de données :
Premièrement on doit récupérer les valeurs qui sont passées en paramètres (via la méthode POST) dans des variables. On accède à ces valeurs de cette façon : $_POST['nom_du_parametre']nom_du_parametre correspond au tag name="nom_du_parametre" de notre champ input.
Exemple :

<input type="text" name="pseudo" />

On récupère la valeur avec $_POST['pseudo']
Maintenant qu'on sait récupérer les paramètres, on va devoir progéter ces variables pour eviter les problèmes de caractères spéciaux et injection SQL
Pour cela il existe déjà une fonction en PHP : mysql_real_escape_string($ma_variable)
Avec cette fonction, on peut donc inserer sans soucis nos données dans notre table...

On sait récupérer nos variables, les protéger pour la base de données, eh bien.. Il reste plus qu'à les insérer dans notre table!
La requête SQL : INSERT INTO minichat(pseudo,message,timestamp) VALUES('$pseudo','$message',$time)
On ajoute tout ça, et on obtient notre PHP final (minichat.php) :

<?php
header("Content-Type: text/html; charset=iso-8859-1");
mysql_connect("localhost","root","");
mysql_select_db("minichat");
if (isset($_POST['pseudo']) && isset($_POST['message'])) 
{
    if (!empty($_POST['pseudo']) && !empty($_POST['message'])) 
    {
        $message = mysql_real_escape_string(utf8_decode($_POST['message']));
        $pseudo = mysql_real_escape_string(utf8_decode($_POST['pseudo']));
        mysql_query("INSERT INTO minichat(pseudo,message,timestamp) VALUES('$pseudo', '$message', '".time()."')");
    }
}
$reponse = mysql_query("SELECT * FROM minichat");
while($val = mysql_fetch_array($reponse))
{
	echo '<p><strong>'.htmlentities(stripslashes($val['pseudo'])).'</strong> 
	à '.date('H\:i\:s',$val['timestamp']).' : '. htmlentities(stripslashes($val['message'])) .'</p>';
}
?>

Petit oublie de ma part, je ne sais pas si vous avez remarqué, mais j'ai ajouté lors de l'enregistrement des variables dans la BDD, la fonction utf8_decode. Cette fonction nous permet de décoder les caractères encodés en utf8 en iso-8859-1!
En gros ce que vous ne savez peut-être pas, c'est que le code AJAX que nous allons faire après, encode les variables passées en paramètres (POST) en utf8.
Or c'est une norme anglo-saxonne qui ne prend pas en charge les jolies accents de notre langue et affiche 'é' à la place de 'é' ^^.
Pour que les accents soient pris en compte on utilise donc la norme iso-8859-1(pour éviter d'écrire &eacute; à la place de é). Voilà tout!


Création de notre script de traitement en AJAX (minichat.js):

Bien nous arrivons à la partie la plus importante de notre minichat, le script en AJAX!
En effet il va nous permettre 2 choses:

  • Rafraichir la liste des messages selon un timer prédéfini sans recharger la page
  • Envoyer un nouveau message à notre script PHP

Pourquoi avoir choisi l'AJAX ? Car il nous permet d'envoyer des requetes à un fichier PHP (on peut aussi le faire en XML).
Est-ce plus dur que le javascript ? Pas beaucoup plus, mais c'est assez lourd (niveau code) à mettre en place.

Allez on commence! comme je vous l'ai dit, notre script AJAX doit envoyer une requête HTTP vers notre page PHP en lui envoyant des paramètes.
Donc dans un premier temps on va créer un objet (voir sur google la programmation objet) permettant d'ouvrir des requêtes HTTP :

function getXMLHttpRequest() 
{
	var xhr = null; // On déclare une variable xhr à null
 
	// Teste si le navigateur prend en charge les XMLHttpRequest
	if (window.XMLHttpRequest || window.ActiveXObject)
	{
		if (window.ActiveXObject) // Si Internet Explorer alors on utilise les ActiveX
		{
			try // On teste IE7 ou supérieur
			{
				xhr = new ActiveXObject("Msxml2.XMLHTTP");
			} 
			catch(e) // Si une erreur est levée, alors c'est IE 6 ou inférieur
			{
				xhr = new ActiveXObject("Microsoft.XMLHTTP");
			}
		} 
		else // Navigateurs récents (Firefox, Opéra, Chrome, Safari, ...)
		{
			xhr = new XMLHttpRequest(); 
		}
	}
	else // Assez explicite...
	{
		alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest...");
		return null;
	}
 
	return xhr; // On retourne l'objet xhr
}
 
// On appelle notre fonction ainsi:
var xhr = getXMLHttpRequest();
 

Maintenant qu'on a déclaré notre objet XMLHttpRequest, on peut l'utiliser pour effectuer une requête sur une autre page.
Il nous faut créer 2 fonctions, une pour rafraichir le chat (la plus simple) et une seconde pour envoyer nos données (un tout petit peu plus dur).
Voici nos 2 fonctions:

// Cette fonction s'exécutera périodiquement pour récupérer les messages
function refreshChat() 
{
	var xhr = getXMLHttpRequest(); // On récupère notre objet
	xhr.onreadystatechange = function() {
		// Si xhr reçoit des données (xhr.readyState == 4) et que son status est OK
		// alors on récupère les données (xhr.responseText) qu'on injecte entre les balises div du minichat
		if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
			// Remplissage des données textuelles récupérées
			document.getElementById('minichat').innerHTML = xhr.responseText;
		}
	};
 
	xhr.open("GET", "minichat.php", true); // On ouvre une connexion en méthode GET vers minichat.php 
	xhr.send(null); // On envoie
}
 
 
// Cette fonction permet l'envoi des données vers minichat.php
function submitChat()
{
	var xhr = getXMLHttpRequest();
	// on récupère la valeur de nos champs input via leurs id et on les encode (encodeURIComponent)
	var pseudo = encodeURIComponent(document.getElementById('pseudo').value);
	var message = encodeURIComponent(document.getElementById('message').value);
	document.getElementById('message').value = ""; // On efface le message dans la textarea
 
	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
			// Remplissage des données textuelles récupérées
			document.getElementById('minichat').innerHTML = xhr.responseText;
		}
	};
 
	xhr.open("POST", "minichat.php", true); // On ouvre une connexion en méthode POST vers minichat.php
	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // permet l'encodage des POST
	xhr.send("pseudo="+pseudo+"&message="+message); // On définit nos variables et leurs valeurs
	// par exemple pseudo=Aure77&message=Coucou
}
 
var timer=setInterval("refreshChat()", 5000); // Rafraichit le minichat toute les 5s
 

Je vous explique rapidement, xhr.onreadystatechange lance une fonction à chaque changement d'état (par exemple envoi,réception de données,...).
Nous attendons une réception de données d'où le if(xhr.readyState == 4) où 4 étant la valeur lorsque le serveur a reçu toutes les données.
xhr.status indique si la requête n'a pas rencontré d'erreur (200 ou 0 = tout s'est bien passé)
xhr.open(method,fichier_destination,booléen) permet d'ouvrir une requête vers un fichier (ici notre minichat.php) par méthode POST ou GET et le dernier paramètre est un booléen permettant de choisir le mode de transmission.
Pour plus d'informations, vous pouvez consulter le tutoriel AJAX du site du zéro

Comme vous pouvez le remarquer, j'ai créé une fonction en méthode GET pour le refresh et la méthode POST pour l'envoi des données du formulaire.
Le refreshChat() est simple à comprendre. Dans la fonction du onreadystatechange, j'ai introduit cette ligne:

document.getElementById('minichat').innerHTML = xhr.responseText;

document.getElementById('minichat').innerHTML veut dire que je modifie le contenu de la balise HTML qui a l'id 'minichat' et je lui mets comme valeur xhr.responseText, le retour de la requête de notre fichier php.
Comme notre fichier PHP n'a pas reçu de méthode POST car notre fonction RefreshChat() est en méthode GET, il effectue directement le SELECT sur la base de données et ensuite affiche les résultats de la requête SQL avec echo.
Donc responseText contient uniquement les echo formatés en texte de notre fichier php.
Donc dynamiquement, notre balise HTML <div id="minichat">Va se remplir ici avec le contenu du PHP</div>. C'est pas génial ça!

submitchat() est très proche de refreshChat(), à la différence qu'elle utilise la méthode POST pour la requete HTTP et qu'elle transmet 2 variables (le pseudo et le message) via cette dernière méthode.
Pour récupérer les 2 variables on va utiliser leurs id via javascript grâce à document.getElementById('pseudo').value pour le pseudo par exemple.
J'ai rajouté encodeURIComponent afin d'encoder les caractères saisies dans la zone de texte (pour éviter quelques problèmes lors du passage des variables au PHP).
Ce qui change c'est :

xhr.open("POST", "minichat.php", true); // On ouvre une connexion en méthode POST vers minichat.php
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // permet l'encodage des POST
xhr.send("pseudo="+pseudo+"&message="+message); // On définit nos variables et leurs valeurs

Donc la méthode open de notre objet AJAX est configurée en méthode POST cette fois-ci. On rajoute ensuite ce header : setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); afin d'autoriser le passage de variables encodées préalablement.
Et enfin notre méthode send nous permet de définir les noms de nos futures variables $_POST avec leurs valeurs associées.
Ici on attribue le pseudo et le message qui proviennent des champs du formulaire.

Pensez à ajouter setInterval dans votre javascript si vous voulez que votre chat se rafraichisse automatiquement.
En premier paramètre, c'est le nom de la fonction javascript qui s'exécutera périodiquement (dans notre cas refreshChat()).
En second paramètre, c'est la fréquence d'exécution de la fonction en millisecondes.
J'ai mis 5000 ms, donc le chat se rafraîchira toutes les 5s.

setInterval("refreshChat()", 5000);

Voilà on viens de finir notre partie AJAX! Vous pouvez souffler c'est fini.

Le résultat :

Je dois l'avouer il n'est pas très joli xD, mais en tout cas il fonctionne...

minichat resultat

Les sources du minichat zippées (ajout du script php avec PDO) : minichat.zip
Mais après c'est que du CSS pour le rendre joli... Je vous laisse le faire ^^

J'espère que mon petit tuto en PHP vous a plu et si vous avez une question ou une remarque, il y a le forum ou les commentaires à disposition.

Rédigé par Aure77 le 2 juin 2009
Creative Commons License

Laisser un commentaire