Ces mécanismes ont en commun l’attribution d’un identifiant de session à un utilisateur, et la mise en œuvre d’un système permettant de transmettre systématique-ment l’identifiant de ses
Trang 1/ / T é l é c h a r g e m e n t d ’ u n e p h o t o i d e n t i f i é e p a r $_GET [ ’ i d ’ ]
/ / On commence p a r i n c r é m e n t e r l e c o m p t e u r
$ c o n n e x i o n = Connexion (NOM, PASSE , BASE , SERVEUR) ;
$ r e q u e t e = "UPDATE Album SET c o m p t e u r = c o m p t e u r +1 "
"WHERE i d = ’ { $_GET [ ’ i d ’ ] } ’ " ;
$ r e s u l t a t = E x e c R e q u e t e ( $ r e q u e t e , $ c o n n e x i o n ) ;
/ / On e n v o i e un en −t ê t e f o r ç a n t l e t r a n s f e r t ( d o w n l o a d )
$ f i c h i e r = $_GET [ ’ i d ’ ] " j p g " ;
$chemin = "PHOTOS/ " ;
h e a d e r ( " Content−t y p e : a p p l i c a t i o n / f o r c e −download " ) ;
h e a d e r ( " Content−d i s p o s i t i o n : f i l e n a m e = $ f i c h i e r " ) ;
/ / A p r è s l ’ en−t ê t e on t r a n s m e t l e c o n t e n u du f i c h i e r l u i −même
r e a d F i l e ( $chemin $ f i c h i e r ) ;
? >
L’incrémentation du compteur est totalement transparente pour l’utilisateur L’in-formation Content-type de l’en-tête demande au navigateur de traiter le contenu
du message HTTP comme un fichier à stocker, tandis que Content-disposition permet de proposer un nom par défaut, dans la fenêtre de téléchargement, pour ce fichier Enfin, la fonction readfile() ouvre un fichier et transfère directement son contenu au navigateur
L’intérêt de ce genre de script est de permettre d’exécuter un traitement quel-conque en PHP, sans aucun affichage, puis de renvoyer à une autre URL sans que l’utilisateur ait à intervenir On pourrait ici, en plus de l’incrémentation du compteur, regarder qui vient chercher une image (en inspectant son adresse IP, disponible dans la variable serveur REMOTE_ADDR, ou toute autre information contenue dans les variables CGI, voir page 16)
L’en-tête Location: autreURL par exemple permet de renvoyer à l’URL autreURL, qui peut être un script PHP ou un fichier HTML produisant réellement l’affichage
2.5 SESSIONS
Comme nous l’avons déjà évoqué dans le chapitre 1, le protocole HTTP ne conserve pas d’informations sur la communication entre un programme client et un
pro-gramme serveur Le terme de session web désigne les mécanismes qui permettent
d’établir une certaine continuité dans les échanges entre un client et un serveur
donnés Ces mécanismes ont en commun l’attribution d’un identifiant de session à un
utilisateur, et la mise en œuvre d’un système permettant de transmettre systématique-ment l’identifiant de session à chaque accès du navigateur vers le serveur Le serveur sait alors à qui il a affaire, et peut accumuler de l’information sur cet interlocuteur
Trang 22.5.1 Comment gérer une session web ?
Il existe essentiellement deux systèmes possibles Le premier consiste à insérer
l’iden-tifiant de session dans toutes les URL des pages transmises au client, ainsi que dans
tous ses formulaires Cette solution, conforme au standard HTTP, est très lourde à
mettre en œuvre De plus elle s’avère très fragile puisqu’il suffit que l’internaute
accède à ne serait-ce qu’une seule page d’un autre site pour que l’identifiant de session
soit perdu
La deuxième solution est de créer un ou plusieurs cookies pour stocker l’identifiant
de session, (et peut-être d’autres informations) du côté du programme client
Rappe-lons (voir la fin du chapitre 1, page 16) qu’un cookie est essentiellement une donnée
transmise par le programme serveur au programme client, ce dernier étant chargé de
la conserver pour une durée déterminée Cette durée peut d’ailleurs excéder la durée d’exécution du programme client lui-même, ce qui implique que les cookies soient stockés dans un fichier texte sur la machine cliente
On peut créer des cookies à partir d’une application PHP avec la fonction
SetCookie(), placée dans l’en-tête du message HTTP Dès que le navigateur a reçu
(et accepté) un cookie venant d’un serveur, il renvoie ce cookie avec tous les accès
à ce même serveur, et ce durant toute la durée de vie du cookie Ce processus est relativement sécurisé puisque seul le programme serveur qui a créé un cookie
peut y accéder, ce qui garantit qu’un autre serveur ne peut pas s’emparer de ces informations En revanche, toute personne pouvant lire des fichiers sur la machine
cliente peut alors trouver les cookies en clair dans le fichier cookies.
Les cookies ne font pas partie du protocole HTTP, mais ont justement été inventés
pour pallier les insuffisances de ce dernier Ils sont reconnus par tous les navigateurs,
même si certains proposent à leurs utilisateurs de refuser d’enregistrer les cookies sur
la machine
Voici un script PHP qui montre comment gérer un compteur d’accès au site avec
un cookie.
Exemple 2.25 exemples/SetCookie.php:Un compteur d’accès réalisé avec un cookie
<? php
/ / E s t −c e que l e c o o k i e e x i s t e ?
i f ( i s S e t ( $_COOKIE [ ’ c o m p t e u r ’ ] ) ) {
$ m e s s a g e = " Vous ê t e s d é j à venu { $_COOKIE [ ’ c o m p t e u r ’ ] } f o i s " " me r e n d r e v i s i t e < b r / >\n " ;
/ / On i n c r é m e n t e l e c o m p t e u r
$ v a l e u r = $_COOKIE [ ’ c o m p t e u r ’ ] + 1 ;
}
e l s e {
/ / I l f a u t c r é e r l e c o o k i e a v e c l a v a l e u r 1
$ m e s s a g e = " B o n j o u r , j e v o u s e n v o i e un c o o k i e < b r / >\n " ;
$ v a l e u r = 1 ;
}
Trang 3/ / E n v o i du c o o k i e
S e t C o o k i e ( " c o m p t e u r " , $ v a l e u r ) ;
? >
<? xml v e r s i o n = " 1 0 " e n c o d i n g = " i s o−8959−1 " ? >
<!DOCTYPE html PUBLIC "−//W3C/ / DTD XHTML 1 0 S t r i c t / / EN"
" h t t p : / / www w3 o r g / TR / xhtml1 /DTD/ xhtml1−s t r i c t dtd ">
<html xmlns= " h t t p : / / www w3 o r g / 1 9 9 9 / xhtml " xml : l a n g = " f r " >
<head >
< t i t l e > L e s c o o k i e s < / t i t l e >
< l i n k r e l = ’ s t y l e s h e e t ’ h r e f = " f i l m s c s s " t y p e = " t e x t / c s s " / >
</ head >
<body >
<h1>Un c o m p t e u r d ’ a c c è s au s i t e a v e c c o o k i e < / h1>
<? php echo $ m e s s a g e ; ? >
</ body >
</ html >
L’affichage se limite à un message qui varie selon que c’est la première fois ou non qu’un utilisateur se connecte au site À chaque passage (essayez de recharger
plusieurs fois la page) le compteur stocké dans le cookie est récupéré et incrémenté.
Ces instructions sont placées avant toute sortie HTML puisque la définition d’un
cookie fait partie de l’en-tête HTTP Si l’on commet l’erreur de transmettre ne
serait-ce qu’un caractère blanc avant le cookie, on obtient le message suivant:
Warning: Cannot modify header information
-headers already sent by (output started
at /Applications/MAMP/htdocs/exemples/SetCookie.php:2)
in /Applications/MAMP/htdocs/exemples/SetCookie.php on line 18
Dans ce cas regardez votre code à l’emplacement indiqué par le message, et cherchez les caractères transmis avant toute instruction plaçant quelque chose dans l’en-tête
REMARQUE –Dans les fichiers contenant des déclarations de fonctions ou de classes, une bonne habitude à prendre est de ne pas placer la balise fermante PHP Cela ne gène pas l’interpréteur, tout en évitant d’introduire des caractères parasites après la balise fermante.
L’appel à SetCookie() crée le cookie la première fois, et modifie sa valeur les fois suivantes Par défaut, la durée de vie de ce cookie est celle du processus client
(le navigateur) mais il est possible de donner une date pour le garder plusieurs jours, mois ou années (voir page 16)
Trang 42.5.2 Gestion de session avec cookies
Voyons maintenant comment utiliser les cookies pour gérer des sessions et enregistrer
des informations sur un internaute dans une base de données Les étapes à mettre en œuvre sont les suivantes :
1 quand un internaute arrive pour la première fois sur le site, on lui attribue un
identifiant unique, et on lui transmet cet identifiant dans un cookie ;
2 à chaque accès ultérieur on est capable de reconnaître l’internaute par son identifiant, et on peut mémoriser les informations le concernant dans une ou plusieurs tables ;
3 quand la session est terminée, on peut valider définitivement l’ensemble des actions effectuées par l’internaute, éventuellement en lui demandant confir-mation
L’exemple donné ci-dessous consiste à proposer un menu en plusieurs phases : les entrées, les plats, puis les desserts, en conservant à chaque fois l’information sur les choix précédents
REMARQUE –PHP propose un mécanisme pour gérer les sessions Cependant, pour clarifier les choses, nous décrivons dans un premier temps une technique indépendante avant de montrer l’équivalent avec les fonctions PHP Le chapitre 7 montre comment combiner sessions web et authentification d’accès à un site.
Voici la table Carte contenant les choix possibles, avec leur type.
Exemple 2.26 exemples/Carte.sql:La carte du restaurant
# C r é a t i o n d ’ une t a b l e p o u r l a c a r t e d ’ un r e s t a u r a n t
CREATE TABLE C a r t e
t y p e ENUM ( " E n t r é e " , " P l a t " , " D e s s e r t " ) ,
PRIMARY KEY ( i d _ c h o i x )
) ;
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" C r u d i t é s " , " E n t r é e ") ; INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" C h a r c u t e r i e " , " E n t r é e ") ; INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" Hareng " , " E n t r é e ") ;
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" S t e a k " , " P l a t ") ;
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" T u r b o t " , " P l a t ") ;
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" C h o u c r o u t e " , " P l a t ") ;
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" P a r i s−B r e s t " , " D e s s e r t ");
INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" Crème c a r a m e l " , " D e s s e r t ") ; INSERT INTO C a r t e ( l i b e l l e , t y p e) VALUES(" T a r t e c i t r o n " , " D e s s e r t ") ;
Trang 5Il nous faut une autre table pour conserver les choix d’un internaute Cette table associe l’internaute représenté par son identifiant de session, et un choix de la carte représenté par son identifiant id_choix
Exemple 2.27 exemples/Commande.sql:Les commandes de l’internaute
# C r é a t i o n d ’ une t a b l e p o u r l e s commandes au r e s t a u r a n t
CREATE TABLE Commande
( i d _ s e s s i o n VARCHAR ( 4 0 ) NOT NULL,
i d _ c h o i x INTEGER NOT NULL,
PRIMARY KEY ( i d _ s e s s i o n , i d _ c h o i x )
) ;
Passons maintenant à la réalisation du système de commandes Il faut d’abord prévoir une fonction pour afficher les choix de la carte en fonction du type (entrée, plat ou dessert) Ces choix sont proposés avec un bouton de type radio
Exemple 2.28 exemples/FormCommande.php:Le formulaire d’affichage d’un choix à la carte
<? php
/ / F o r m u l a i r e d e s a i s i e d ’ un c h o i x à l a c a r t e
f u n c t i o n FormCommande ( $ t y p e _ c h o i x , $ s c r i p t , $ c o n n e x i o n )
{
/ / Un m e s s a g e p o u r i n d i q u e r à q u e l s t a d e on e n e s t
i f ( $ t y p e _ c h o i x == " E n t r é e " )
echo " P o u r commencer n o u s v o u s p r o p o s o n s l e s e n t r é e s < b r / > " ;
e l s e
i f ( $ t y p e _ c h o i x == " P l a t " )
echo " M a i n t e n a n t c h o i s i s s e z un p l a t < b r / > " ;
e l s e
echo " E n f i n c h o i s i s s e z un d e s s e r t < b r / > " ;
/ / M a i n t e n a n t on c r é e l e f o r m u l a i r e
echo " < f o r m a c t i o n = ’ $ s c r i p t ’ method = ’ p o s t ’ >\n " ;
/ / Champ c a c h é a v e c l e t y p e d e c h o i x
echo " < i n p u t t y p e = ’ h i d d e n ’ name = ’ t y p e _ c h o i x ’ v a l u e = ’
$ t y p e _ c h o i x ’ / > " ;
/ / R e c h e r c h e d e s c h o i x s e l o n l e t y p e ( e n t r é e , p l a t ou d e s s e r t )
$ r e q u e t e = " SELECT ∗ FROM Carte WHERE t y p e = ’ $ t y p e _ c h o i x ’ " ;
$ r e s u l t a t = E x e c R e q u e t e ( $ r e q u e t e , $ c o n n e x i o n ) ;
/ / A f f i c h a g e d e s c h o i x
w h i l e ( $ c h o i x = O b j e t S u i v a n t ( $ r e s u l t a t ) )
echo " $ c h o i x−> l i b e l l e : "
" < i n p u t t y p e = ’ r a d i o ’ name = ’ i d _ c h o i x ’ v a l u e = ’ $ c h o i x−>
i d _ c h o i x ’/ > < b r / > " ;