I. Les cookies▲
I-A. Introduction▲
Le protocole HTTPprotocole HTTP est dit « stateless », ou autrement dit sans état. Pour un serveur, chaque requête qu'il reçoit est indépendante de la précédente, ainsi que de la suivante. Un serveur web est « bête » en quelque sorte, il écoute son port, à chaque fois qu'une requête se présente, il la traite, puis passe à la suivante. Ce processus est néanmoins gênant pour une application, car celle-ci a souvent besoin de « se souvenir » d'un (des) paramètre(s) d'un utilisateur.
Un cookie est un petit fichier texte (inoffensif donc), créé par le serveur. En rajoutant l'en-tête Set-cookie, dans sa réponse, le serveur indique au client qu'il souhaite y stocker un cookie. Le client peut décider, ou non de s'exécuter et de créer le cookie demandé.
S'il l'accepte, le navigateur client va ensuite joindre le cookie à l'en-tête de toutes ses requêtes vers le même domaine (on verra ça plus précisément). Aux requêtes suivantes, le client rajoute donc l'en-tête HTTP Cookie et le serveur recevant cet en-tête va le transmettre à PHP.
Ainsi sur une seule requête HTTP, on ne peut savoir si le client accepte les cookies, ou non. Il va être obligé de réadresser une requête au même serveur qui va cette fois-ci regarder s'il a reçu en retour le cookie, ou non. C'est ainsi que si l'utilisateur décide de changer de navigateur entre deux requêtes, ce ne seront pas les mêmes cookies qui seront envoyés.
Un cookie est cependant limité en taille, 4 Ko maximum ; et en nombre de cookies ; mais ce chiffre est généralement très grand. On comprendra que pour stocker une quantité importante d'informations, le cookie n'est pas la solution. Il sert dans une grande majorité des cas à identifier un utilisateur, on va voir cela.
I-B. Utilisations▲
PHP est lié au serveur web, il récupère les cookies à partir que celui-ci lui fournit, il les a lui-même reçus, par HTTP, du client. Lorsque PHP récupère les cookies en début de traitement, il les place dans un tableau superglobal accessible via $_COOKIE.
PHP peut aussi décider d'envoyer un cookie (si on le lui demande), par la fonction setCookie(name, value, expire). Il manque des paramètres, ça sera vu dans la section suivante.
Ainsi lors de l'appel à setCookie(), le moteur de PHP va générer les en-têtes HTTP appropriés pour nous, en interne. C'est pour cela qu'on dit que setCookie() doit être appelé avant toute sortie, car un appel à echo, par exemple, demande à PHP d'afficher quelque chose, et l'oblige donc à générer les en-têtes HTTP relatifs à cet affichage.
Or après qu'il a écrit les en-têtes et envoyé le contenu du « echo », on ne peut plus faire machine arrière, un appel à setCookie() génèrera donc un warning vous informant que les en-têtes de la réponse HTTP ont déjà été envoyés : le fameux « "Headers already sent" » très connu des débutants…
Revenons à setCookie() : tout d'abord il faut nommer le cookie, pour pouvoir le reconnaitre. Ensuite il faut lui attribuer une valeur, et enfin optionnellement, une date d'expiration.
Si on ne spécifie pas de date d'expiration, le cookie sera stocké dans la mémoire vive du client (en général), et détruit dès la fermeture du navigateur (et non de l'onglet). Ce cas est pratique pour retenir du client un paramètre temporaire, comme son nom, que l'on souhaite afficher sur nos pages.
Si une date est précisée, ça sera un timestamp. Arrivé à la date, le navigateur client efface le cookie :
<?php
setCookie('developpez'
,
'tutoriel sur les cookies / sessions'
,
time()+
24
*
3600
);
?>
<?php
if
(isset($_COOKIE
[
'developpez'
]
)){
echo htmlentities($_COOKIE
[
'developpez'
],
ENT_QUOTES,
);
?>
I-C. Sécurité▲
Comme un cookie peut être vu et modifié par le client, à la main (c'est un fichier texte), on échappera sa sortie si on l'affiche, et on vérifiera correctement sa valeur. On peut le chiffrer ou lui rajouter une somme de contrôle (md5) pour empêcher sa modification. Le 4e paramètre de setCookie() est « path ». Il définit le chemin pour lequel le cookie est valable sur ce domaine, et sera donc envoyé par le client. Par défaut, il vaut « / », ce qui veut dire que le cookie sera fourni à tous les chemins du domaine actuel.
Ainsi le client enverra son cookie s'il accède à http://monsite.com, mais aussi à (par exemple) http://monsite.com/sql/
Pour limiter le cookie à un dossier en particulier, on lui passe le nom de dossier en 4e paramètre :
<?php
setCookie('developpez_admin'
,
'Bienvenue administrateur'
,
time()+
24
*
3600
,
'/admin/'
);
Le cinquième paramètre de setCookie() fait la même chose, mais pour le domaine et les sous-domaines :
<?php
setCookie('DBA_developpez'
,
'Bienvenue DBA'
,
time()+
24
*
3600
,
'/admin/'
,
'sql.monsite.com'
);
Ce cookie sera envoyé par le navigateur à http://sql.monsite.com/admin/, http://sql.monsite.com/admin/un-repertoire/ , mais pas à http://sql.monsite.com/ ni à http://www.monsite.com/admin/ ni à http://www.monsite.com/
Si je donne la valeur de « .monsite.com », au 5e paramètre (remarquez le point avant le domaine), alors le cookie sera reçu de tous les sous-domaines de monsite.com.
Le 6e paramètre, « secured », est un booléen, qui vaut false par défaut. Mis à true, il spécifiera au navigateur de n'envoyer ce cookie QUE si la connexion est sécurisée par exemple via SSL.
Enfin le 7e et dernier paramètre est apparu en PHP 5.2, il s'appelle HttpOnly, il est à false par défaut. Mis à true, il envoie un cookie noté « HttpOnly », si le navigateur implémente cette règle, alors il rendra inaccessible le cookie à javascript ou tout autre interpréteur pouvant y accéder.
Le cookie ne sera envoyé que par HTTP, et stocké dans une zone mémoire sûre sur le navigateur. Cet attribut est d'une importance capitale pour contrer les attaques de vol de sessionVol de cookie de session
Par contre il n'est pas mis à true par défaut, car si le navigateur ne connait pas ce type de cookie (vieux navigateurs), il risque tout simplement de l'ignorer.