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 :
- La première partie consiste à
concevoir une application de chat complète et fonctionnelle
: créer la
structure de données, les comptes utilisateurs et
l'interface web
permettant l'échange de données avec la base (y
compris l'envoi et la réception des
messages). Cette partie est techniquement "classique", et vous pouvez
la réaliser en vous appuyant sur vos travaux des devoirs
précédents et
votre expérience d'utilisateur d'outils de
messagerie instantanée existants. Vous serez donc moins
guidés que dans les devoirs
précédents, et aurez plus de lattitude pour
organiser les pages et les scripts PHP comme vous l'entendez.
À la fin de cette partie, il vous est demandé de
fournir le code source de
vos différents composants, ainsi qu'un rapport succinct,
dont le contenu est indiqué à la fin de cet
énoncé.
- La seconde partie se focalise sur un point particulier de
l'application : le processus de
téléchargement des messages à
afficher pour un utilisateur donné. Cette partie a
pour but de vous faire utiliser plus finement le fonctionnement du
protocole HTTP, et vous permettra d'expérimenter les
échanges de
données asynchrones en XML entre le serveur et le client,
à l'aide des
technologies AJAX. Pour la réaliser, vous pourrez utiliser
vos notes prises au dernier regroupement, ainsi que quelques
références et fonctions
JavaScript données dans ce document annexe. Vous
fournirez le code de cette deuxième partie du devoir
séparément de celui de la première.
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 :
- chaque utilisateur possède un identifiant unique
("pseudo"), et se logue à l'aide d'un mot de passe,
- chaque message est identifié par son
numéro
d'ordre, ne contient que du texte simple, et devra
être affichés avec le pseudo de son
auteur,
- une fois la base créée, l'application
pourra créer des comptes, rajouter des messages, mais aucune
suppression ne doit être possible.
Création
Dans PHPMyAdmin, vous allez créer :
- une base nommée
"c216_devoir3",
- les tables
permettant de réaliser la modélisation ci-dessus.
- un utilisateur générique (login = mdp
= "chat"), que
vous
utiliserez
dans toute votre application pour accéder
à cette
base de
données.
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 :
- affichage des messages : la totalité des
messages
échangés sont affichés, avec leurs
auteurs ; pour permettre le chargement des nouveaux messages sans
renvoi de données de la part de l'utilisateur, cet affichage
est
actualisé
toutes les 5 secondes,
- saisie
et envoi de nouveaux messages : les messages sont envoyés
depuis un formulaire basique qui
provoque l'enregistrement d'un nouveau message et l'actualisation de
l'affichage de ceux-ci ,
- déconnexion :
l'utilisateur quitte l'application ; il est redirigé vers
une
page statique le remerciant de s'être connecté.
Indications :
- pour l'actualisation automatique de la page, vous pouvez
par exemple utiliser
l'en-tête HTTP "Refresh" (voir : http://cyberzoide.developpez.com/html/meta.php3),
- pour l'envoi des messages, prévoyez que le
serveur aura
besoin de savoir de quel utilisateur chaque message provient,
- si vous
utilisez des cadres, l'envoi d'un formulaire vers un autre cadre de la
page se fait en utilisant l'attribut target,
- il est
conseillé d'utiliser des méthodes HTTP
différentes
pour l'envoi d'un nouveau message et pour l'actualisation
périodique de l'affichage des messages. Cela permet de faire
différents traitements dans la même page
dynamique, en
fonction du type de méthode utilisé,
après avoir
testé celle-ci (voir : http://www.vulgarisation-informatique.com/variables-predefinies.php).
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.
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 :
- créer une fonction qui retrouve ce
numéro par une requête dans la table contenant les
messages,
- à chaque ajout d'un nouvel enregistrement,
stocker le
numéro du dernier message (par exemple, à l'aide
de LAST_INSERT_ID()),
et l'enregistrer dans un fichier ou une nouvelle table de la base de
façon à pouvoir le
récupérer facilement.
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
là
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 :
- une structure de données XML pour
l'échange de
données entre le client et le serveur.
- une page XHTML dynamique qui fait appel aux fonctions
JavaScript ci-dessous,
- des fonctions JavaScript pour le
téléchargement des messages et leur ajout
dynamique au
document XHTML ci-dessus.
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 :
- une déclaration XML,
- un élément racine (de nom
"Messages"), qui contiendra :
- un ou plusieurs élément(s)
nommé(s) "Message", contenant chacun :
- un élément "Auteur", contenant le
pseudo de l'auteur,
- un élément "Texte", contenant le
texte du message.
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>
- É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,
- 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é.
- 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.
- 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.
- 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.
- 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 :
- Première partie : vous incluerez dans le premier
fichier le
code (correctement commenté) de la dernière
version, un fichier texte contenant les
différentes requêtes SQL de création
des tables, ainsi qu'un rapport au format
PDF de
quelques pages
(pas plus d'une dizaine), comprenant :
- une
description succincte et un schéma
général de votre application,
- l'ensemble des requêtes de
création
des tables
- les réponses aux
autres questions
posées en bleu dans cet énoncé,
- les points forts et/ou
faibles et les problèmes rencontrés pour cette
application.
- Deuxième partie : vous incluerez dans le second
fichier le
code (correctement commenté) de la dernière
version, et éventuellement un fichier texte contenant les
requêtes SQL de création
des tables (si vous avez eu besoin d'en créer dans cette
partie) ou d'autres remarques que vous estimez nécessaires à la compréhension de votre travail.
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.