Un Chat élémentaire en Php/jQuery
Posé ici le mardi 16 juin 2009 à 07:30 par
Lors d'une de mes dernières incursions sur mon compte Facebook, j'ai vu qu'ils avaient ajouté une sorte de messagerie instantanée. L'option doit bien exister depuis un quart de siècle, mais je l'avais loupé jusque là.
Je trouve l'idée sympathique et me suis dit qu'une telle messagerie pouvait avoir sa place dans une section d'administration de site pour permettre aux administrateurs/modérateurs de discuter entre eux.
J'ai donc griffonné un petit chat en quelques lignes, le but étant de rester le plus élémentaire possible. Pas envie de me tracasser avec des écritures/lectures en base de données. Un simple fichier plat et un peu d'Ajax peuvent faire l'affaire. Zoooop.
Ce que je veux
Je veux quelque chose de simplissime, rapide à mettre en œuvre. Je ne veux pas m'embêter avec une base de données. L'idée est de rester Straight to the point pour des besoins légers.
Mise en place
Tout commence par un simple formulaire permettant d'entrer son message et d'une fenêtre retranscrivant la discussion. Pour garder l'article le plus simple possible, je ne gère pas l'identification. Le pseudo est ici entré par l'utilisateur lui-même. Dans un vrai site communautaire ou une partie administrateur, l'identifiant de l'utilisateur est déjà connu. C'est celui-ci qu'on pourrait utiliser.
Html du Chat
<div id="chat">
<!-- Chat Room -->
<div id="room"><dl></dl></div>
<!-- Formulaire -->
<form action="#" method="post">
<input type="text" name="user" value="Anonyme" size="7"/>
<input type="text" name="message" size="30" AUTOCOMPLETE="off" />
<input type="submit" value="ok" />
</form>
</div>
Lorsqu'un message est entré, il est posté en Ajax à un second script PHP qui fait le travail. La fenêtre de dialogue est rafraichie toutes les 5 secondes.
Fichier chat.js
/**
* Un mini-Chat en jQuery/Php
* par Jay Salvat - http://blog.jaysalvat.com/
*/
$(function() {
// Lorsqu'un message est posté
$('#chat form').submit(function() {
// On récupère les valeurs de champs
var user = $('#chat input[name=user]').val();
var message = $('#chat input[name=message]').val();
// On les poste en Ajax
$.post('chat.php', { 'user':user, 'message':message }, function() {
refreshChat();
});
$('#chat input[name=message]').val('');
return false;
});
// Rafraichissement du contenu du Chat
function refreshChat() {
$.ajax({
url: "chat.html",
ifModified:true,
success: function(content){
$('#room').html(content);
}
});
setTimeout(refreshChat, 5000);
}
refreshChat();
});
Le script PHP, ici chat.php reçoit le message et le pseudo, et se contente de les écrire dans un fichier avec quelques tags Html. Ce fichier s'appelle ici chat.html. Quelques manœuvres sont effectuées pour ne garder que les dix dernières lignes.
Fichier chat.php
<?php
/**
* Un mini-Chat en jQuery/Php
* par Jay Salvat - http://blog.jaysalvat.com/
*/
$file = 'chat.html'; // fichier de stockage
$max_lines = 20; // nombre de lignes maximum stockées
if (isset($_POST['message'])) {
$user = $_POST['user'];
$message = $_POST['message'];
$date = date('d/m/y H:i:s');
$line = "<dt><b>{$user}</b> {$date}</dt><dd>{$message}</dd>\n";
// Le fichier plat est rouvert
$content = file($file);
// ... traité
$content = array_slice($content, 0, $max_lines);
array_unshift($content, $line);
// ... et réécrit
file_put_contents($file, $content);
}
?>
Le reste n'est que cosmétique. Un peu de CSS met le tout en forme. Je ne m'attarde pas sur la feuille de style qui n'a ici aucun intérêt.

Analyse
Je reviens plus en détail sur certains points.
Javascript : chat.js
$('#chat form').submit(function() {
var user = $('#chat input[name=user]').val();
var message = $('#chat input[name=message]').val();
// ...
return false;
});
Lorsque l'événement submit est déclenché, je récupère les valeurs des deux champs (user et message). Le return false annule l'effet par défaut du submit. Le formulaire ne sera donc pas posté avec un rechargement de page.
$.post('chat.php', { 'user':user, 'message':message }, function() {
refreshChat();
});
Une fois les valeurs de champs récupérées, je les passe en Ajax par méthode POST à mon script chat.php. Puis je lance la fonction refreshChat() qui rafraichi la discussion.
function refreshChat() {
$.ajax({
url: "chat.html",
ifModified:true,
success: function(content){
$('#room').html(content);
}
});
setTimeout(refreshChat, 5000);
}
Avec cette fonction on rafraichi la discussion. Une requête Ajax prend le contenu du fichier plat chat.html et l'affiche dans notre Chat (#room). Le point important ici est la ligne ifModified:true qui permet de ne charger le contenu que si le fichier a été modifié. Attention, cet attribut peut poser problème sur certains serveurs ne renvoyant pas certaines informations dans les headers http. C'est le cas sur mon hébergement OVH.
Enfin, un setTimeout relance la fonction toutes les 5 secondes (5000). Voilà pour la partie client.
Php : chat.php
Le script client échange des données avec un fichier le fichier chat.php. Voyons de quoi celui-ci est constitué.
if (isset($_POST['message'])) {
$user = $_POST['user'];
$message = $_POST['message'];
$date = date('d/m/y H:i:s');
// ...
}
Lorsque des données sont postées en Ajax, j'ajoute la date et je les range dans de simples variables pour y voir plus clair par la suite.
$line = "<dt><b>{$user}</b> {$date}</dt><dd>{$message}</dd>\n";
Je créé la nouvelle ligne qui sera ajouté à la discussion un peu plus tard.
$content = file($file);
$content = array_slice($content, 0, $max_lines);
J'ouvre le fichier de stockage chat.html dans un tableau (file) et je n'en garde qu'un certain nombre de lignes (ici défini par $max_lines) pour que le fichier garde une taille raisonnable.
array_unshift($content, $line);
La ligne nouvellement créée est ajoutée au début de la discussion avec array_unshift.
file_put_contents($file, $content);
Puis le contenu total est réécrit dans le fichier chat.html.
Conclusion
Voilà tout est là. On est loin du tout option mais là n'était pas l'idée. Comme d'habitude je n'ébauche qu'une idée, à chacun de se l'approprier et de l'intégrer et de la modifier selon ses besoins.
Ce contenu est mis à disposition selon les termes de la licence Creative Commons 2.0 France : Paternité, Pas d'Utilisation Commerciale, Partage des Conditions Initiales à l'Identique.
Context
Thématiques :
Trackbacks
0 trackback



Commentaires
21 commentaires
Bonjour,
Sympa. L'idée date, en effet, je me souviens que j'avais fait un petit chat avec des frames HTML et du PHP sans utiliser Javascript grâce à la balise (maintenant décriée) meta refresh et un formulaire de type POST avec un target qui va bien.
C'est bcp plus sexy comme ça ;), c'est sûr. Et ça m'a permis de voir un peu comment fonctionne JQuery car apparemment, ce serait mieux que Prototype.
@+
1. Par Nicolas Froidure le mardi 16 juin 2009 à 14:33
Implémentation basique oui mais sympa.
Facebook utilise une technique moins connue : des requêtes ajax sont lancées en permanence et restes actives pendant en gros une minute à la recherche de nouveaux messages, dès qu'un nouveau message est reçu le script s'arrête, envoit les messages à l'utilisateur et une nouvelle requête repart ...
C'est du "long polling"
2. Par Vincent Voyer le mardi 16 juin 2009 à 22:33
Merci pour cette astuce ;)
3. Par CpNForTehWin le dimanche 21 juin 2009 à 12:32
Même pas une petite démo sans historique ? :(
4. Par Mr Xhark le mardi 30 juin 2009 à 21:10
@Mr Xhark
Démo en place.
5. Par Jay Salvat le mercredi 01 juillet 2009 à 11:00
C'est étrange car sous IE les écrits ne s'affichent pas mais ça propage bien les informations sur un autre navigateur ouvert à côté (Firefox pour ne pas le nommer).
@Jay : De plus la démo est concernée par le mail que je t'ai envoyé il y a quelques temps ;)
6. Par Stan le jeudi 02 juillet 2009 à 15:59
Merci pour ce tuto.
Comment modifier ce script pour qu'il enregistre la conversation dans une base de données et non dans un fichier. En plus il semble que le script ne marche pas bien sous IE6(les écrits ne s'affichent pas).
7. Par Demorex le jeudi 02 juillet 2009 à 17:09
Merci à tous pour vos feedbacks.
Comme précisé dans la 1ère version de l'article, la démo n'était pas prévue d'être en ligne pour diverses raisons de configuration serveur.
Je pense que maintenant tout est bon.
8. Par Jay Salvat le jeudi 02 juillet 2009 à 17:28
@ Demorex ,
Simplement en remplacant l'écriture dans le fichier par une écriture en base de données et le fichier plat chat.html, par un script PHP qui lit cette même base.
A toi de jouer :)
9. Par Jay Salvat le jeudi 02 juillet 2009 à 17:48
@ Jay Salvat
j'ai remplacé le fichier chat.html par chat2.php, j'y ai inclus les parametres de connexions à ma base de données:
- dans chat.js :
function refreshChat() {
$.ajax({
url: "chat/chat2.php",
success: function(content){
$('#room').html(content);
}
});
- dans chat.php (on fait l'insertion dans la base de données
-dans chat2.php
$requete = "SELECT * from demo_chat order by id desc"; //(pseudo,texte,date)
$exe=mysql_query($requete);
$msg_texte="";
while ($tab=mysql_fetch_array($exe)) {
$msg_texte .= "<dt><b>{$tab[pseudo]}</b> {$tab[date]}</dt><dd>{$tab[texte]}</dd>\n";
}
echo $msg_texte;
mysql_close($connect);
Tout cela fonctionne vien sous Firefox, mais sous IE6 l'actualisation des données enregistrées ne marche pas.
Comment resoudre ce probleme?
10. Par Demorex le jeudi 02 juillet 2009 à 19:16
Salut.
Ce lien m'a permis de résoudre mon problème Remiprevost.com…t-contenu-texte
Merci.
11. Par Demorex le vendredi 03 juillet 2009 à 10:55
@Demorex
Merci beaucoup pour ce complément d'information.
12. Par Jay Salvat le vendredi 03 juillet 2009 à 11:04
Excellent !!
Je viens de découvrir Jquery et Ajax et ce petit tuto me donne envie de poursuivre !
Moi aussi j'avais tenté de faire un petit chat avec des frames et du php il y a quelques temps, mais c'était l'usine à gaz et vraiment pas élégant du tout.
Là c'est propre, c'est net... j'adore !!
Comme le site du boulot est en asp, j'ai juste réécrit chat.php en chat.asp, pour ceux que ça pourrait intéresser, ça donne un truc de ce genre :
<%
user = session("user")
message = request.form("message")
new_line = "<dl><dt><b>"&user&"</b> "&now()&"</dt><dd>"&message&"</dd></dl>"
Set FSO = _
Server.CreateObject("Scripting.FileSystemObject")
dir = Server.MapPath(".")
Fnm = dir & "\chat.html"
if FSO.FileExists(Fnm) then
set inF = FSO.OpenTextFile(Fnm,1,false)
new_line = new_line & inF.readAll
inF.close
end if
set inF = FSO.OpenTextFile(Fnm,2,false)
inF.write(new_line)
inF.close
%>
En rentrant chez moi j'ai repris la version php mais ils semblerait que mon hébergeur ne m'autorise pas à modifier le fichier 'chat.html'... Alors j'ai utilisé la méthode de Demorex, en passant par ma base MySql.
Ca marche nickel sauf pour Google Chrome qui n'affiche pas la discussion dans le DIV du haut ! En enlevant le ifmodified ça marche pour tout le monde, même Chrome...
En même temps, je trouve illogique qu'avec le ifmodified la version de Demorex puisse fonctionner sous IE et FireFox, étant donné que le fichier .php n'est pas réellement modifié, contrairement au fichier chat.html qui est lui "physiquement" mis à jour ! Quelqu'un saurait m'expliquer cela ?
En tout cas, bravo et merci pour ce tuto bien sympa et didactique ;o)
13. Par CoreDump le lundi 05 octobre 2009 à 14:50
Bonsoir CoreDump,
Merci pour ta contribution ASP.
En effet, je ne le précise pas dans l'article mais il faut ouvrir les droits d'écriture sur le fichier HTML. La fonction adéquate est chmod.
Tu as aussi raison sur le ifModified de la version avec PHP. Par défaut il sera toujours "modified" à moins de jouer avec les headers.
Le ifModified est un confort mais n'empêche pas le script de fonctionner. Sur la démo le ifModified ne fonctionne pas, mon hébergeur ne le permet pas. C'est juste plus lent et lourd.
14. Par Jay Salvat le lundi 05 octobre 2009 à 21:28
Je suis en train de développer une appli similaire à la votre, mais basé sur une base de données pour récupérer diverses informations (il s'agit d'un tchat sur un espace communautaire).
Je voulais savoir si quelqu'un avait une idée sur les impacts en requetes sur une bdd : un refresh chaque 5 sec. est acceptable, est il risqué de pousser le refresh à 1 sec ? Que ce soit pour la charge du serveur mysql ou un éventuel plantage du navigateur client ?
Merci de vos éventuelles réponses.
15. Par Zeflex le mardi 20 octobre 2009 à 00:24
Bonjour
J'expérimente la technique mais avec Silverlight comme client et php comme serveur.
Vous pouvez avoir un aperçu ici : (projet en developpement)
Furukoo.fr/furu…2/TestPage.html (Silverlight obligatoire) UserName : guest / Password : guest
On peut observer le traffic HTTP sous FF avec Firebug ou sous IE avec la debugbar.
Le "pool" est de 10 secondes seulement car je teste un "active user" toute les 10 secondes.
Qu'en pensez vous ?
Yvan
16. Par Yvan Nébotieff le mardi 10 novembre 2009 à 18:10
La fonction setTimeout() ne prendait-elle pas une chaine de caractère ? Du genre : setTimeout("refreshChat()", 5000); ?
17. Par Bill le mercredi 11 novembre 2009 à 13:51
Bonsoir Bill,
SetTimeout prend une fonction pas forcement une chaine de caractère.
18. Par Jay Salvat le mercredi 11 novembre 2009 à 21:41
Bonjour Yvan,
Je ne réponds que maintenant car j'ai eu du mal à installer Silverlight sur mon mac.
Je pense que 10 secondes est un peu long pour espérer une conversation fluide.
19. Par Jay Salvat le jeudi 12 novembre 2009 à 09:56
Merci Jay Salvat pour ce tutorial.
Cependant je suis hebergé sur OVH comme vous ce qui rend caduque la fonction refreshChat().
Avez-vous une astuce pour y remédier ?
20. Par Kraddle le mercredi 06 janvier 2010 à 13:08
A ben c'est trouvé !
Merci pour cette démonstration et bonne route à vous
21. Par Kraddle le mercredi 06 janvier 2010 à 13:16