Introduction
Les sessions sont utilisées pour conserver des informations à propos d'un utilisateur du côté serveur entre chaque requête. Généralement un COOKIE de session est créé afin de permettre l'identification de l'utilisateur. Il est aussi possible d'envoyer un paramètre GET dans l'URL si on ne veut pas créer un COOKIE. Par défaut en PHP, le tous ce passe dans un COOKIE et les données de la session sont enregistré dans un fichier du côté du serveur.
Introduction aux sessions
La configuration des sessions se retrouve dans le fichier php.ini. Par exemple ici on vois que les sessions sont enregistrées sur le disques et transmis via COOKIE.
session.save_handler = files
session.save_path = "/var/lib/php/session"
session.use_cookies = 1
Exemple d'utilisation de session
L'utilisation d'une session en PHP permet de stocké des données sur un utilisateur et est souvent utiliser pour authentifier un utilisateur.
Voici un exemple de code qui initie une session et incrémente un compteur PHP. Si vous appelez l'URL, et que vous rechargez la page, vous devriez voir le compteur qui s'incrémente.
<?php
// Fichier : compteur.php
// Démarre la session
session_start();
// Créer une variable session pour le compteur et initialise le compteur
if(!isset($_SESSION['compteur'])) {
$_SESSION['compteur'] = 0;
}
// Incrémente le compteur
$_SESSION['compteur']++;
// Affiche le compteur
echo $_SESSION['compteur'];
Problème possible
Un des problèmes communs qui empêche les sessions de fonctionner correctement est lorsque le session_start()
est appelé après que des entêtes (headers) aille été envoyé.
Vous avez déjà surement vu ce message d'erreur :
Warning: session_start(): Cannot start session when headers already sent...
Voici un exemple pour répliquer le problème :
<?php
// Fichier : probleme-commun.php
// Init some script
// include('config.php');
// Remarquer l'espace
?>
<?php
// L'erreur aura lieu seulement si le output_buffering n'est pas utiliser.
// Ici on émule cet effet
ob_end_flush();
include('compteur.php');
?>
Un entête sera alors envoyé et le COOKIE ne sera pas transmis. Exemple semble simple, mais lorsqu'on programme, généralement ça arrive lorsque nous avons des fichiers qui sont inclus. Par exemple, un fichier index.php qui inclut un fichier session.php. L'espace peut alors se retrouver un peu n'importe où.
Solution
Afin d'éviter le problème, il est possible d'utiliser le output_buffering
en PHP.
; http://php.net/output-buffering
output_buffering = 4096
Vous pouvez utiliser la fonction ob_start()
en PHP au début de votre code pour retarder l'envoie des entêtes.
Les codes sont disponibles à l'adresse suivante : https://github.com/webo3/docs-session-php
Utiliser des sessions avec plusieurs serveurs
Votre site web a du succès et vous devez maintenant passer à un environnement avec plusieurs serveurs?
Avec un environnement comportant plusieurs serveurs, ce n'est plus si simple d'utiliser une session PHP puisqu'elle est enregistrée par défaut sur le disque via la configuration php.ini.
Il y a plusieurs solutions pour stocker la session:
- Utilisation d'un répartiteur de charge qui renvoie l'utilisateur toujours sur le même serveur.
sticky session
- Utilisation d'un COOKIE crypté
- Utilisation d'un serveur de base de données
- Utilisation d'un serveur de fichier partagé
- Utilisation de serveurs Memcached ou Redis
Voyons un peu chacune des solutions.
Utilisation des sticky session
Un répartiteur de charge peut théoriquement renvoyer toujours l'utilisateur sur le même serveur. Avec cette méthode, il n'est pas nécessaire de faire des modifications. Par contre, qu'arrive-t-il lorsqu'un des serveurs tombe? L'utilisateur est redirigé sur un autre serveur et perd alors le contenu de sa session, cela peut signifié de seulement avoir à ce reloger.
Utilisation d'un COOKIE crypté
L'idée est d'utiliser un COOKIE crypté pour stocker l'information de l'utilisateur. Le cryptage et décryptage doit êtes faites du côté serveur. De cette manière, les serveurs n'ont pas besoin de partager d'informations. Par contre, l'utilisation de cette technique nous limite dans la grosseur du contenu de la session puisque la grosseur maximum d'un COOKIE est de 4096 octets.
Cette technique permet de gérer une petite quantité d'information dans la session. Par contre si on a plusieurs requêtes concurrentes il peut y avoir des problèmes de racing condition
qui surviennent.
Pour ce faire on créer une classe de session en PHP et on change applique le session_set_save_handler.
Si cette solution vous intéresse, voir le code d'exemple
Utilisation d'un serveur de base de données
Cette technique est similaire à celle utilisée au COOKIE crypté, sauf que les données sont sauvegardées dans la base de données au lieu d'être retournées sous forme de COOKIE crypté. L'avantage est que la quantité d'information que l'on peut enregistrer dans la session est supérieure. Par contre, cette solution ajoute un poids sur une base de données qui est généralement déjà chargé et donc est non recommandée.
Si cette solution vous intéresse, il existe plusieurs libraires déjà faites : https://packagist.org/?query=mysql-session-handler
Utilisation d'un serveur de fichier partagé
Cette solution est assez simple à mettre en place, on utilise un serveur de partages de fichiers de type NFS, Samba ou autre et on pointe le session.save_path="/path"
Par contre, l'augmentation des IOPS et la nécessité de faire des "lock" sur les fichiers situés sur le réseau peuvent réduire la performance.
Utilisation de serveurs Memcached ou Redis
Memcached ou Redis sont des solutions rapides à mettre en place. Il suffit d'installer une extension memcached ou redis et de changer la configuration PHP session.save_handler
et session.save_path
.
Pour Memcached avec l'extension PHP memcached
session.save_path="memcached"
session.save_handler="IP:11211"
Pour Memcached avec l'extension PHP memcache
session.save_path="memcache"
session.save_handler="tcp://IP:11211"
Pour Redis avec l'extension PHP Redis
session.save_path="redis"
session.save_handler="tcp://IP:6379?auth=mot-de-passe"
Ce sont deux solutions intéressantes et très efficaces.
Si vous voulez savoir comment installer Memcached sur un serveur, nous avons créé un tutoriel disponible à l'adresse suivante : Installation Memcached