phpInfo.netLes ArchivesLes éléPHPants

  
  Accueil
  Trucs & Astuces
  Scripts
  Regex
  Annuaire
  Articles

.
      
 Articles   La gestion des sessions avec PHP 4  Par Guillaume SMET   Avril 2001    »  A quoi servent les sessions ?
 »  Comment fonctionnent les sessions ?
 »  A quoi ne servent pas les sessions ?
 »  Quelques erreurs communes
 »  Conclusion


A quoi servent les sessions ?

Lorsque qu’une personne se connecte sur votre site, elle ouvre une session. Il est parfois intéressant de conserver les valeurs de certaines variables tout au long de cette session.

Exemple : La personne entre un login et un mot de passe pour accéder au site et on souhaite vérifier au début de chaque page du site que cette personne est bien autorisée.

Solutions possibles :
  • On peut éventuellement transmettre la valeur de ces variables dans l’URL mais il s’agit parfois de données sensibles, de tableaux, d’objets… Ce n’est pas une solution élégante et elle n’est pas toujours réalisable. Cette solution est totalement irrecevable quand il s’agit de sécurité. De plus, une URL est limitée à 255 caractères.

  • On peut également enregistrer ces données en utilisant un cookie sur la machine du client. Ceci pose plusieurs problèmes : si le client n’accepte pas les cookies, ce qui est relativement courant, on ne peut stocker les données. De plus, c’est une solution client-side assez peu fiable au niveau sécurité par nature.
Aucune de ces solutions n’est réellement satisfaisante pour ce que nous souhaitons faire. De nombreux moyens de gérer les sessions ont été développés reposant en général sur des bases de données. PHP4 introduit des fonctions permettant de gérer les sessions relativement simplement. C’est l’objet du présent article.

Comment fonctionnent les sessions ?

1. Du côté du serveur

Lors de l’ouverture d’une session, une id de session est attribuée au client. Celle-ci permet de l’identifier et d’accéder à ses variables de session.

Les variables de session sont enregistrées sur le serveur dans le répertoire session.save_path défini dans la configuration de PHP sous la forme d’un fichier texte par session.

A l'aide de l'id de session de l'utilisateur, PHP peut retrouver la valeur des variables de session dans le fichier texte correspondant.

Simplifions : Une personne se connecte avec son login et son mot de passe. On lui donne l’id de session 1. On enregistre son login et son mot de passe comme variables de session. Sur le serveur, un fichier texte session_1 est créé. Il contient login="login rentré"; password="mot de passe rentré". C'est une simplification assez grossière mais n'hésitez pas à aller voir à quoi ressemble un tel fichier dans le répertoire session.save_path (configuration de PHP).

On comprend assez vite la nécessité de transmettre l'id de session de l'utilisateur de page en page. Cette question sera abordée au paragraphe 3.

2. Les fonctions utilisées

PHP4 dispose d'un certain nombre de fonctions permettant de manipuler les sessions. Voici les plus utiles :
  • session_start : cette fonction est à mettre en tête de toutes les pages où vous souhaitez avoir accès à vos variables de session. Il ne doit y avoir aucun code affichable avant l'utilisation de cette fonction sous peine d'erreur (headers already sent).
    Cette fonction ouvre une session s'il n'existe pas de session déjà ouverte. Si une session a déjà été ouverte et que l'id de session a été correctement transmise à la page, elle reprend la session existante et permet l'accès aux variables de session correspond à cette session.
  • session_id([id]) : définit l'id de session à utiliser ou renvoie l'id de session utilisée. Lors d'un session_start, une id de session est automatiquement générée par PHP. Il n'est donc en général pas nécessaire de la définir.
  • session_name([nom]) : définit le nom de la session en cours ou renvoie le nom utilisé par la session en cours. Le nom par défaut est défini par le session.name défini dans la configuration de PHP.
  • session_register("variable") : permet d'enregistrer la variable de session passée en paramètre. Il est à noter que pour enregistrer $login, il faut utiliser session_register("login").
  • session_is_registered("variable") : vérifie si la variable spécifiée en paramètre est enregistrée dans la session active.
  • session_unregister("variable") : détruit une variable de session préalablement enregistrée.
  • session_destroy() : détruit la session active.
Important : cette liste n'est pas exhaustive et ne dispense en aucun cas de la lecture du manuel présent sur php.net, rubrique Sessions.

Reprenons l'exemple vu précédemment.

Exemple 1 :

<?php

session_start
(); // Démarre la session. Spécifie une id de session.

$login="nom"; // On définit la variable classique $login

$password="mot de passe"; // On définit la variable classique $password

session_register("login"); // On enregistre $login dans la session

session_register("password"); // On enregistre $password dans la session

header("Location: exemple2.php?".session_name()."=".session_id());

exit();
// Redirection. On en reparle dans le II.3.

?>

Exemple 2 :

<?php

// Ici $login et $password ne sont pas définis

session_start();

// Ils sont définis à partir d'ici.

echo $login;

echo
$password;

if(
$login!="nom") session_destroy(); // destruction de la session

?>

Cet exemple simple devrait vous permettre de comprendre comment sont manipulées les variables de session.

Si l'on souhaite modifier la valeur d'une variable de session, il faut procéder comme suit :

<?php

session_start
();

echo
$login; // il a la valeur de la variable de session correspondante.

// la variable $login présente dans notre page prend une valeur différente de
// celle présente dans la session. La variable de session $login n'a pas été
// modifiée ; elle a toujours la même valeur !

$login="nouveau_login";

echo
$login; // Affiche "nouveau_login"

// Met à jour la variable de session $login avec la nouvelle valeur à savoir
// "nouveau_login"

session_register("login");

?>

3. Transmettre l'id de session

Comme nous l'avons vu précédemment, l'id de session permet d'identifier un utilisateur de manière unique et lui donne accès à ses variables de session. Il est donc nécessaire de transmettre cette id de session de page en page. Cette transmission doit être parfaite car si pour une page l'id de session n'est pas correctement transmise, le session_start crée une nouvelle session et les variables de session de la session précédente sont perdues.

Nous nous placerons ici dans un cadre général et ne rentrerons pas dans les cas particuliers de certains hébergeurs qui utilisent des versions spécifiques de PHP.

Voici les diverses solutions que l'on peut retenir. Il est à noter que l'utilisation de telle ou telle solution dépend à la fois de la configuration du serveur et de celle du client.

  • La solution la plus simple : si PHP a été compilé avec l'option –-enable-trans-sid et qu'on a configuré session.use_trans_sid à 1, il n'est pas nécessaire de se préoccuper de transmettre l'id de session, PHP la transmet automatiquement dans l'URL de manière transparente (on ne voit pas l'id de session dans l'URL). C'est sans doute la solution la plus élégante et la moins casse-tête.
    MAIS, cette solution ne peut pas être retenue dans la majorité des cas ! En effet, PHP ne gère plus cette fonctionnalité sitôt qu'on effectue une redirection avec un header ! De plus, si on utilise des URL absolues, ce qui peut arriver dans certains développements, PHP ne transmet pas l'id de session car il suppose qu'on se dirige vers un site extérieur.

  • On peut comme souvent se reposer sur un système de cookies. PHP le gère d'ailleurs automatiquement dans sa configuration avec session.use_cookies. S'il est à 1, l'id de session est automatiquement enregistré en tant que cookie sur l'ordinateur du client. Cette solution ne peut pas non plus être retenue telle quelle car si le client refuse les cookies, l'id de session n'est pas enregistrée.

  • On peut décider de passer à chaque fois l'id de session dans l'URL. C'est une solution qui fonctionne à tous les coups même si elle est lourde et peu élégante.
    Les URL seront alors de la forme : "index.php?".session_name()."=".session_id() ou index.php?<? echo session_name();?>=<? echo session_id(); ?> ou autres variantes du même genre.
Ce sont les trois solutions que l'on peut retenir a priori. Il n'y a donc pas réellement de solutions miracles.

J'utilise personnellement une solution "batarde" qui fonctionne dans tous les cas et qui est, à mon sens, relativement légère.

Je me repose sur le session.use_cookies=1. Cependant, je prévois une solution de secours au cas où les cookies sont refusés par le client. J'utilise la constante SID définie par PHP. SID est une chaîne vide si l'id de session a bien été enregistrée dans un cookie et vaut session_name()."=".session_id() si l'id de session n'a pas pu être enregistrée comme cookie.
Mes URL sont donc du type "index.php?".SID ou index.php?<? echo SID; ?> et autres variantes.

On peut d'ailleurs facilement écrire une fonction url($chaîne) qui ajoute SID ou non à la fin de l'URL passée en paramètre si SID est nul ou non. Ceci permet d'éviter les ? et les & inutiles en fin d'URL.

NB : cette solution est une solution personnelle. Elle n'est pas parfaite et il existe d'autres méthodes qui fonctionnent tout aussi bien. A vous de trouver celle qui vous va le mieux.

Sessions et programmation orientée objet

Les variables de session peuvent être de tout type : chaînes, entiers, tableaux, objets… Cependant, quand on utilise des objets, il est nécessaire de prendre quelques précautions : la définition de la classe doit être incluse avant le session_start afin que PHP puisse manipuler l'objet enregistré dans la session.

Exemple :

Supposons l'existence d'une classe Utilisateur définie dans le fichier class_utilisateur.inc.php. Supposons l'existence d'une variable de session $user qui est une instance d'Utilisateur. On écrira le début de notre fichier comme suit :

<?php

// Inclusion de la définition de Utilisateur

include("class_utilisateur.inc.php");

// PHP connaît la définition de Utilisateur, il peut donc manipuler l'objet
// $user et récupérer les données stockées dans le fichier texte correspondant
// à la session.

session_start();

?>


A quoi ne servent pas les sessions ?

Les sessions ne sont pas à utiliser dans tous les cas. Il est parfois plus simple et plus élégant d'utiliser d'autres solutions. Les sessions ne s’appliquent pas de toute façon à toutes les situations.

Les sessions ne permettent pas de conserver des informations d’une visite à une autre. Pour cela, il faut soit recourir aux cookies pour enregistrer des données sur l’ordinateur du client (avec toujours les mêmes problèmes que précédemment), soit utiliser un système d’identification reposant sur une base de données.

Pour transmettre des informations vers une seule page, les sessions peuvent être lourdes à mettre en place. On peut alors soit recourir à un passage dans l’URL pour des informations courtes et peu sensibles, soit utiliser les champs cachés d’un formulaire du type <input type="hidden" name="variable" value="valeur">.

En conclusion, l'utilisation des sessions PHP4 peut être très intéressante mais elles ne sont pas à utiliser à tort et à travers. Leur utilisation est notamment très différente de l'utilisation des cookies.

Quelques erreurs communes

Ce paragraphe reprend quelques messages d'erreurs fréquents ainsi que les erreurs les plus souvent commises lors de l'utilisation des sessions. Cette liste est loin d'être exhaustive. N'hésitez pas à faire part de vos erreurs et du diagnostic correspondant dans les commentaires.

Erreur 1 :

Warning: Cannot send session cookie - headers already sent by (output started at c:\easyphp\www\test5.php:2) in c:\easyphp\www\test5.php on line 4

Warning: Cannot send session cache limiter - headers already sent (output started at c:\easyphp\www\test5.php:2) in c:\easyphp\www\test5.php on line 4

C'est l'erreur la plus classique. Un caractère affichable est présent avant le session_start. Ceci peut être un simple espace ou passage à la ligne avant le <? Ou un echo qui ne doit pas être avant le session_start.

Erreur 2 :

Fatal error: The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition utilisateur of the object you are trying to operate on was loaded _before_ the session was started in c:/easyphp/www/extranetpei/include/securite/fonction_check_auth_user.php on line 26

La classe d'une instance utilisée comme variable de session n'a pas été déclarée avant le session_start. PHP n'arrive pas à gérer cette variable de session car il ne connaît pas la structure de l'objet.

Conclusion

Cet article n'a pas pour but d'être exhaustif ou de remplacer la documentation de PHP. Il s'agit juste de mettre en lumière ce que l'on peut faire et ne pas faire avec les sessions PHP4 ainsi que les problèmes que l'on peut rencontrer.

Il est loin d'être parfait ou complet et ne demande qu'à être amélioré.
Synseo