Libérer la session PHP pour éviter le freeze

26 11 2011

Aujourd’hui les enfants, on va parler du fonctionnement des sessions en PHP, dans le détail.

Quand un client (navigateur) fait une requête HTTP vers une page de votre site qui utilise les sessions (permettant à vos visiteurs de se connecter avec un compte perso/premium par exemple), il va inclure dans cette requête HTTP, au niveau des headers, un cookie contenant ce qu’on appelle l’identifiant de session.

Exemple :

PHPSESSID=19a04504ad488ef391698e8caf906605

Le nom du cookie (ici PHPSESSID) est d’ailleurs configurable dans le fichier de configuration de votre serveur PHP : php.ini :

; Name of the session (used as cookie name).
session.name = PHPSESSID

Bref, quand le serveur va recevoir cette requête, cet identifiant de session va être utilisé par la fonction session_start() qui va aller charger en mémoire la session (contenant tout un tas de variables que vous avez défini dans les pages précédentes) depuis un fichier. Et ce fichier peut justement être identifié en utilisant l’identifiant de session, tous les fichiers de session se trouvent dans un même répertoire (défini dans php.ini > session.save_path), et sont nommés de la sorte : sess_<identifiant de session>, dans mon exemple, le fichier va s’appeler : sess_19a04504ad488ef391698e8caf906605.

Qu’y a t-il dans le fichier de session ?

Pour comprendre, vous allez créer un petit script PHP tout simple qui démarre la session et va y enregistrer 2 variables :

<?php
session_start();
$_SESSION['nom']  = 'MrSchnaps';
$_SESSION['date'] = date('d/m/Y H:i:s');
?>

Après avoir appelé ce fichier avec un navigateur, allez voir dans le répertoire ou votre serveur PHP enregistre les sessions, et ouvrez le fichier (prenez le fichier le plus récent s’il y en a plusieurs), voici ce qu’on va y trouver :

nom|s:9:"MrSchnaps";date|s:19:"26/11/2011 13:13:42";

Tiens, justement les 2 variables qu’on vient de défini, avec des caractères bizarre autour… étrange non ?

En fait, cette chaîne de caractère correspond tout simplement à la variable $_SESSION qui a été sérialisée avec la fonction serialize(). La sérialisation (ou Marshalling) est tout simplement un procédé permettant de convertir une variable (donc quelque chose qui est dans la mémoire d’un ordinateur, qu’on ne peut pas stocker par définition), en une chaîne de caractère, qui pourra ensuite être enregistrée dans un fichier, dans une base de données ou même envoyé à un autre serveur par le réseau…

Et ce fichier de session est chargé (unserialize) depuis le fichier de session à chaque appel de session_start(), c’est pour ça que vous retrouvez vos variables d’une page à une autre.

Problèmes liés aux sessions

Venons en au principal intérêt de cet article, ce mécanisme peut générer des problèmes lorsqu’une même session est utilisée par 2 scripts PHP en concurrence.

C’est rarement le cas, mais l’exemple typique est celui d’un script permettant de contrôler les téléchargements. Ce genre de script très simple se content en général de définir une série de headers spécifiques au téléchargement (Content-Type, Content-Length, Content-disposition, application/force-download…), de contrôler les autorisations, conditions particulières… puis enfin d’envoyer le fichier au client en utilisant la fonction php readfile().

Le souci c’est que ce script PHP va s’exécuter pendant toute la durée du téléchargement, et dans ce cas on observe qu’il est impossible de charger n’importe quelle page du site tant que l’exécution du script n’est pas terminée, le site est comme figé, il freeze (mais pas tout tout le monde, juste pour les clients qui utilise l’ID de session incriminé).

La cause de ce problème est facile à comprendre : le second script cherche à démarrer la session, et donc à charger le fichier de session, mais il ne peut pas puisque celui-ci est est verrouillé par le script de téléchargement, donc le second script se met en attente d’une libération de ce fichier.

Or c’est absurde, puisque quand on appelle readfile() dans le premier fichier, tout le traitement PHP, les vérifications… sont déjà faites.

Heureusement, il existe un moyen de libérer le fichier de session, exactement comme on ferme une connexion à une base de données avec mysql_close, et cette solution c’est la fonction session_write_close(), qu’il suffit d’appeler dès que vous avez terminé de modifier $_SESSION.


Partager :

Ces icônes sont des liens vers des sites de partage de signet sociaux où les lecteurs peuvent partager et découvrir de nouveaux liens.
  • Digg
  • del.icio.us
  • Facebook
  • Digg -fr
  • Live
  • MisterWong Fr
  • Scoopeo
  • StumbleUpon
  • Technorati
  • Wikio FR

Actions

Informations

Et maintenant je fais quoi ?

Laisser un commentaire

Vous pouvez utiliser ces balises html : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>