Master AI 1ère année - module INF04 : Langages et structures du Web

TP AJAX : conception d'une application de messagerie instanée

Attention, ce sujet reprend celui d'une autre matière. Vous n'avez que la seconde partie à réaliser à partir des sources fournies.

Description de l'application

L'objectif de ce TP est de concevoir une application de messagerie instantanée, ou chat, à l'aide des techniques présentées en cours. Cette application permettra à un utilisateur de créer un compte ou de se loguer à l'aide d'un compte existant, puis de discuter avec les autres utilisateurs connectés.

Objectifs du devoir

Ce devoir comporte deux parties aux objectifs distincts :

Environnement de développement

Comme pour le devoir précédent, vous développerez sous WampServer (voir lien d'installation sur la page d'accueil du module). Cet outil ne fonctionne que sous Windows. Si vous utilisez un Mac ou un autre système d'exploitation, merci d'utiliser les mêmes outils, et sous des versions compatibles avec celles ci-dessus. Les instructions de la section suivante sont spécifiques à WampServer. Si vous utilisez d'autres outils, reportez-vous à leurs manuels d'instruction pour arriver aux même résultats. Vous pouvez me contacter en cas de problème.

Partie 1 : conception de l'application

Création de la structure de données

Modélisation

La première des choses à faire est de définir la structure de données que vous allez utiliser. Pour cela, vous devrez tenir compte des éléments suivants :

Création

Dans PHPMyAdmin, vous allez créer :

Attention : cet "utilisateur générique", n'est qu'un outil technique pour accéder facilement à la base depuis l'application. Il ne doit pas être confondu avec les utilisateurs "réels", tels qu'ils sont décrits dans le reste de cet énoncé, et dont les caractéristiques seront enregistrées dynamiquement dans la base.

Vous indiquerez dans votre rapport les requêtes SQL de création des tables.

Vous indiquerez dans votre rapport les droits dont dispose l'utilisateur générique sur chaque table.

Structuration générale de l'application

Vous réaliserez un ou plusieurs schéma(s) globa(l/ux) de votre application, afin d'articuler les différentes pages, en fonction des liens existant entre elles. Vous distinguerez sur ce(s) schéma(s) les liens hypermédias que l'utilisateur pourra parcourir, les redirections automatiques réalisées par le système, et les inclusions de pages côté serveur, dont l'utilisateur n'a pas connaissance.

Vous incluerez ce(s) schéma(s)dans votre rapport.

Fonctionnalités à réaliser

Vous trouverez ci-dessous une liste des principales tâches à réaliser.

Vous noterez dans votre rapport les principaux choix techniques effectués pour ces tâches.

Connexion à l'application

À partir de la page d'accueil de votre application, un utilisateur pourra soit se connecter, en utilisant un formulaire web disponible sur cette page, soit suivre un lien qui lui permettra de créer un compte.

S'il choisit de se connecter à un compte existant et si son login ou son mot de passe sont faux ou ne correspondent pas l'un à l'autre, l'application le renvoie sur la même page, en y incluant un message d'erreur approprié.

Lorsque l'utilisateur a été authentifié en fonction de ses caractéristiques dans la base, il est reconnu par le système qui le redirige alors vers l'interface de discussion.

Création d'un compte utilisateur

Dans le cas où il utilise directement le formulaire de connexion, il renseigne deux champs (pseudo et mot de passe) et valide sa requête à l'aide d'un bouton approprié. Le mot de passe est entré deux fois, afin de vérifier qu'il n'y a pas eu d'erreur de frappe.

Si le pseudo existe déjà, ou si les deux mots de passe entrés ne sont pas identiques, l'application le renvoie sur la même page, en y incluant un message d'erreur approprié.

Dans le cas contraire, il est enregistré dans la base et considéré comme authentifié par le système, qui le redirige alors vers l'interface de discussion.

Interface de discussion

Il s'agit ici de réaliser la fonctionnalité de chat proprement dite, qui permet d'assurer le fonctionnement "normal" de l'application. L'interface est celle que voit un utilisateur connecté à un groupe de discussion. Elle propose les fonctionnalités suivantes :
Indications :
L'image ci-dessous présente un exemple d'interface basique. Ici, les deux parties de l'interface sont réalisées dans des cadres séparés, mais vous êtes libre de choisir une autre solution technique.
 
Exemple très simple d'interface de discussion

Recommandations de forme

Bien entendu, n'oubliez pas de faire en sorte que vos documents soient en XHTML strict (sauf pour ceux qui définissent des frames) et que des feuilles de style CSS leur soient associés.

Une fois cette première partie du travail réalisée, et rédigez le rapport demandé à la fin de ce document. Sauvegardez votre travail et enregistrez le tout dans un fichier ZIP.

Partie 2 : amélioration de l'application

L'état actuel de votre application est le suivant : toutes les 5 secondes, chaque client interroge le serveur web, lequel va à son tour interroger le serveur de bases de données, puis dynamiquement générer une nouvelle page contenant la totalité des messages enregistrés, et la renvoyer à chaque client via le réseau.

Si le nombre d'utilisateurs est grand et/ou s'il y a de nombreux messages enregistrés dans la base, ce fonctionnement peut vite représenter une charge de travail importante pour les deux serveurs, ainsi qu'une consommation inutile de bande passante réseau.

L'objectif de cette partie est donc d'affiner le processus de récupération et d'affichage des messages échangés par les différents utilisateurs.

Préambule

Deux possibilités sont à votre disposition pour alléger les traitements et les transferts de données. Toutes les deux nécessitent que votre application connaisse le numéro du dernier message enregistré dans la base, ainsi que celui du dernier message récupéré par chaque utilisateur.

Modifiez votre application pour rendre ces données disponibles dans la page qui affiche les messages.

Indication : pour le dernier message enregistré dans la base, les variables globales de niveau application n'existent pas en PHP. Il est donc impossible de mémoriser le nombre de messages total et de rendre cette valeur disponible à la fois pour toutes les pages de l'application et pour tous les utilisateurs. J'ai obtenu également assez peu de résultat en utilisant des variables statiques (http://www.lephpfacile.com/cours/21-la-portee-des-variables, exemple 7). Deux autres possibilités :

Utilisation des en-têtes HTTP

Si le numéro du dernier message enregistré dans la base est égal à celui du dernier message envoyé à un client, cela signifie qu'aucun message n'est arrivé depuis la dernière requête du client. Il est donc inutile de recalculer toute la page.

Plutôt que de renvoyer une réponse HTTP contenant une page complète, il suffit de renvoyer juste un en-tête HTTP, avec le code de statut indiquant au client que la page n'a pas été modifiée. Voir ici pour le code de statut, et pour la façon de l'utiliser en PHP.

Modifiez votre application pour que la page ne soit plus renvoyée si aucun nouveau message ne doit être affiché.

Chargement asynchrone des derniers messages

L'étape suivante consiste à ne télécharger que les messages non encore récupérés par chaque client, et de les ajouter dynamiquement à la page d'affichage des messages. Pour cela, vous allez expérimenter la technologie AJAX, qui va vous permettre de récupérer les nouveaux messages de façon asynchrone (c'est-à-dire sans effacement de la page affichée ni interruption de la tâche de l'utilisateur), et d'extraire les messages pour les rajouter à la suite des messages déjà affichés.

Techniquement, il s'agit d'utiliser :

Génération des documents XML contenant les nouveaux messages

Voir le cours XML pour plus de précisions sur le langage de structuration de données XML. La structure de ce document XML sera la suivante :
Exemple :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<Messages>
  <Message>
    <Auteur>toto</Auteur>
    <Texte>Message1</Texte>
  </Message>
  <Message>
    <Auteur>titi</Auteur>
    <Texte>Message2</Texte>
  </Message>
  <Message>
    <Auteur>tata</Auteur>
    <Texte>Message3</Texte>
  </Message>
</Messages>

  1. Écrivez une nouvelle page PHP qui génère un tel document à partir des enregistrements contenus dans la base. Pour cela, procédez comme pour une page XHTML, en tapant les balises XML dans le corps de la page, et en insérant le code nécessaire dans des scripts PHP.

    Remarques :
    • avant d'envoyer des données en XML, attention à bien positionner l'en-tête indiquant que le contenu de la réponse est de type "text/xml", pour qu'elle puisse être traitée correctement en AJAX par les fonctions de la bibliothèque,
    • les premiers et derniers caractères d'une déclaration XML sont "confusionnants" pour un script PHP ; ils ne peuvent pas être tapés directement dans le corps de la page, mais peuvent être insérés dans une chaîne de caractères, laquelle sera rajoutée au corps de la page XML à l'aide par exemple d'une instruction print,
  2. Modifiez ensuite cette page PHP pour qu'elle renvoie uniquement les messages dont le numéro est supérieur à celui du dernier message déjà téléchargé par l'utilisateur. Reprenez ce que vous avez fait à la question précédente, pour ne pas renvoyer des documents vides si aucun nouveau message n'a besoin d'être récupéré.
  3. Rajoutez éventuellement dans cette page un traitement pour les requêtes POST, qui rajoute un message dans la base avant d'actualiser l'affichage (voir plus haut, quatrième remarque de la partie "interface de discussion).

Corps du document XHTML et fonctions JavaScript d'inclusion dans ce document

Une bibliothèque de fonctions JavaScript qui réalisent l'envoi de la requête et le traitement de la réponse en asynchrone est disponible ici. J'ai commenté les différentes fonctions pour que vous compreniez ce qu'elles font.
  1. La première étape est de récupérer le code de cette bibliothèque de fonctions, et de le faire fonctionner. Pour cela, réalisez une page XHTML simple, qui possède les caractéristiques suivantes :
    • l'élément head contient deux éléments script dont l'un pointe vers la bibliothèque de fonctions JavaScript : <script type="text/javascript" src="ajax.js"></script>, et le second contient une fonction JavaScript qui appelle l'une des fonctions principales de la bibliothèque (voir ci-dessous), et se relance périodiquement pour permettre l'actualisation des messages (voir document annexe),
    • l'élément body possède un attribut onload qui appelle cette dernière fonction JavaScript au chargement de la page : <body onload="javascript:mafonction(...);">,
    • l'élément dans lequel vous voulez que les messages s'affichent possède un attribut id.
    La fonction principale de la bibliothèque AJAX s'appelle loadXMLAsynchroneously et prend les paramètres suivants :
    • le nom de la méthode HTTP utilisée ('GET' ou 'POST'),
    • l'URL relative de la page PHP qui génère le document XML,
    • les paramètres éventuels de cette requête ('toto=12&titi=nimportequoi', ou null sinon),
    • la valeur de l'attribut id de l'élément de la page qui doit recevoir les données.
  2. La deuxième étape est d'inclure ce code dans votre application. Pour cela :
    • remplacez la page d'affichage en PHP par cette nouvelle page XHTML, et vérifiez-en le fonctionnement,
    • modifiez le formulaire d'envoi des données pour qu'il envoie par POST chaque nouveau message en asynchrone au serveur (voir document annexe) ; pour cela, vous pouvez soit :
      • traiter ces requêtes dans une page PHP à part, en utilisant l'autre fonction principale de la bibliothèque, sendRequestAsynchroneously, qui n'effectue aucun traitement pour la réponse,
      • la traiter dans la même page PHP que la précédente, en utilisant une différenciation en fonction des méthodes HTTP utilisées (cf. partie 3 de la question précédente) ; cela permet l'actualisation immédiate de l'affichage des message.
  3. La troisième étape consiste à modifier la fonction traiteXML() de la bibliothèque ajax.js, qui extrait les contenus du document XML récupéré, et crée une structure XHTML simple (un div et des span) pour les rajouter dans la page XHTML. Il s'agit de modifier le code de cette fonction pour que les auteurs et les textes des messages soient alignés verticalement, en les plaçant dans les cellules d'une table par exemple, et en en améliorant le formattage. À vous de jouer...
Comme pour la partie précédente, sauvegardez votre travail dans un fichier ZIP, en y rajoutant éventuellement un fichier texte additionnel (voir plus bas).

Modalités de rendu du devoir


Vous rendrez deux fichiers au format ZIP séparés, pour chacune des deux parties du devoir :
Vous enverrez ces deux fichiers par courriel à Lionel Médini (lionel.medini _at_ univ-lyon1.fr). J'accuserai réception de vos messages pour vous signifier que je les aurai bien reçus et que les pièces jointes sont ouvrables. Le fait d'avoir reçu un accusé de réception à votre envoi ne signifie pas que le devoir a été corrigé, ou qu'aucun des fichiers de votre application ne manque.

L'objet du message devra impérativement contenir les mots "e-Miage", "C216", "rendu" et "devoir 3", ainsi que vos nom et prénom.