Session PHP

Tutoriel d'utilisation des sessions PHP.

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

Besoin d'aide ?

Vous ne trouvez pas ce que vous cherchez ?

Parler avec un de nos spécialistes aujourd'hui.

Par courriel

Autres suggestions

Injection SQL en PHP

PHP

Découvrez tout ce que vous devez savoir sur l'injection SQL en PHP, une technique d'attaque courante qui peut permettre à des pirates de voler ou de modifier des données dans votre base de données. Dans cet article, vous apprendrez comment détecter et prévenir les attaques d'injection SQL en PHP en utilisant des pratiques de codage sécurisées.

Traduction Laravel

PHP

Utilisation d'un script créer par webO3 pour travailler avec les traductions sous Laravel.

Validation de l'existence d'un courriel en PHP

PHP

Utilisation d'un script créer par webO3 pour valider l'existence d'une adresse de courriel sur le serveur SMTP.