IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Sessions et cookies en PHP


précédentsommairesuivant

IV. Aller plus loin

IV-A. Utiliser plusieurs sessions dans la même page

Il est impossible d'ouvrir simultanément plusieurs sessions. Cependant, on peut tout à fait ouvrir plusieurs sessions l'une après l'autre. Dans ce cas, il faut fermer la première session sans la détruire, grâce à session_write_close(), puis assigner les nouveaux session_name et session_id, et enfin ouvrir la nouvelle session avec session_start().

 
Sélectionnez
<?php
session_name('utilisateur');
session_start(); // Création de la première session
[...] // Utilisation de la première session
session_write_close(); // Fermeture de la première session, ses données sont sauvegardées.
session_name('admin'); // Indication du nom de la seconde session
session_start(); // Ouverture de la seconde session
[...] // Utilisation de la seconde session.
?>

On peut refaire la manipulation autant de fois que l'on veut.

Une fois la session fermée, il est toujours possible d'accéder en lecture (les modifications ne seront pas prises en compte) aux variables de l'ancienne session. $_SESSION ne sera vidé et prérempli qu'au prochain appel à session_start().

IV-B. Configuration liée aux sessions

La transmission de l'identifiant de session

Comme vu au début, un identifiant unique identifie chaque session. PHP se charge lui-même de transmettre cet identifiant d'une page à l'autre, mais on peut indiquer explicitement comment le faire à l'aide de quatre directives de configurations :

  • session.use_cookies : cette option fait stocker l'identifiant (et seulement l'identifiant) dans un cookie si elle est égale à 1. Sa valeur par défaut est 1. Si l'option est à 0, et qu'un cookie de session est présent dans le navigateur, il sera simplement ignoré ;
  • session.use_only_cookies : si cette option est égale à 1, alors PHP ignorera les identifiants transmis via l'URL pour n'utiliser que ceux contenus dans les cookies. Sa valeur par défaut est 0 ;
  • session.use_trans_sid : si cette option est égale à 1, alors PHP insèrera automatiquement l'identifiant dans tous les liens non absolus (ne commençant pas par http:// ou ftp:// ou mailto: ou d'autres liens absolus, les liens commençant par un / (relatifs à la racine du site) seront eux pourvus de l'identifiant.) Sa valeur par défaut est 0 ;
  • session.url_rewriter_tags : indique où et dans quelles balises HTML insérer l'identifiant de session dans le cas où session.use_trans_sid est à 1. Sa valeur par défaut est : a=href,area=href,frame=src,input=src,form=fakeentry,fieldset= Le format est balise1=attribut1,balise2=attribut2,… Le cas des balises form et fieldset est particulier, car cela se traduit en fait par l'apparition d'un champ input (de type hidden) supplémentaire.

Extrait du phpinfo :

Directive

Local Value

Master Value

session.use_cookies

On

On

session.use_only_cookies

Off

Off

session.use_trans_id

On

On

session.url_rewriter_tags

a=href, area=href, frame=src, input=src, form=fakeentry, fieldset=

a=href, area=href, frame=src, input=src, form=fakeentry, fieldset=

Voici deux exemples de configuration pour ces options :

  1. Le premier est celui qui présente le plus de chances de faire transiter l'identifiant :

  2. Le second est celui qui est totalement invisible à l'œil d'un visiteur classique mais, si les cookies sont désactivés, il ne fonctionnera pas.

Il faut savoir que faire passer l'identifiant dans l'URL (session.use_trans_sid à 1) peut présenter des risques. En effet, quelqu'un copiant un lien pour un ami lui donnerait par là-même son identifiant de session et sa session serait ouverte quand on cliquerait sur le lien.

La sécurité des sessions

Il existe plusieurs directives de configuration permettant de jouer sur la sécurité des sessions, en voici quelques-unes.

  • Vérifier la provenance du visiteur
    session.referer_check permet de spécifier une chaîne de caractères qui doit être présente dans le « referer » (adresse de la page de provenance) si celui-ci est indiqué par le navigateur. Une bonne idée est d'indiquer le nom de domaine de votre site (par exemple). Par contre, gardez à l'idée que cela ne permet pas d'être sûr que le visiteur provient d'une des pages de votre site. En effet, le referrer provient du protocole HTTP, lequel est très facile à manipuler !
  • Augmenter la complexité de l'identifiant de session
    session.hash_function permet de choisir entre deux algorithmes de création des identifiants de sessions : MD5 (mettre la valeur 0) ou SHA-1 (mettre la valeur 1), le second permet de générer des identifiants de sessions plus longs.
    session.hash_bits_per_caracter permet de définir les plages de caractères utilisées pour l'identifiant de session 4 pour les caractères '0' à '9' et 'a' à 'f', 5 pour '0'-'9' et 'a'-'v' et 6 pour '0'-'9', 'a'-z', 'A'-'Z', '-' et ','. Il s'agit uniquement d'une représentation de l'identifiant, en aucun cas ça ne modifie sa complexité intrinsèque. Ces directives de configuration ne sont disponibles que depuis PHP 5.
  • Modifier la façon dont sont formatées les données de sessions
    session.serialize_handler permet de modifier la façon dont sont formatées les données de sessions avant d'être sauvegardées. Par défaut, (valeur php) c'est une sérialization proche de la fonction serialize qui est utilisée. Si votre installation de PHP le supporte, vous pouvez utiliser WDDX (valeur WDDX), qui permet de récupérer un format XML.
  • Modifier la façon dont sont sauvegardées les données de sessions
    session.save_handler permet de modifier la façon dont sont sauvegardées les données de sessions. La configuration actuelle ne permet pas de choisir d'autres « handler » que celui par défaut (dans un fichier non crypté, valeur files). Cependant, il existe une fonction PHP qui permet de définir un nouveau handler, voir un peu plus loin.
  • Modifier les données utilisées pour créer les identifiants de sessions
    session.entropy_file permet de spécifier un fichier dont seront extraites des données permettant de rendre aléatoire l'identifiant de session généré. En général, c'est un « fichier » spécial qui est utilisé, dont le contenu est différent et aléatoire à chaque fois qu'on tente de le lire (/dev/random ou /dev/urandom sous unix par exemple).
    session.entropy_length permet de spécifier le nombre de caractères qui seront lus dans ce fichier.
  • Modifier la configuration du cookie stockant les identifiants de sessions
    session.cookie_lifetime, session.cookie_path et session.cookie_domain permet de modifier la durée de vie, le chemin et le domaine attribués à un cookie.
    session.cookie_secure restreint l'utilisation du cookie aux connexions HTTPS (connexions cryptées).
    session.cookie_httponly restreint l'accès au cookie via le protocole HTTP. Autrement dit, les langages de script côté client (Javascript par exemple) n'auront pas accès au cookie. Ce n'est pas supporté par tous les navigateurs, et disponibles uniquement depuis PHP5.
  • Modifier la mise en cache des pages par le navigateur et les proxys
    session.cache_limiter permet d'autoriser ou non la mise en cache des pages Web par le navigateur et les proxies. nocache (valeur par défaut) interdit la mise en page, private l'autorise uniquement pour les navigateurs et public pour tout le monde. Certains navigateurs peuvent rencontrer quelques problèmes avec l'expiration du cache : dans ce cas, il vaut mieux spécifier private_no_expire.
    session.cache_expire permet de spécifier la durée de vie des pages web mises en cache.

Bien qu'il soit possible de crypter les sessions, elles sont stockées en tant que fichiers sur le serveur Web. À ce titre, elles n'ont pas de système d'identification (login + password spécifiques) comme le shell et la base de données. Nous étudierons plus loin une solution permettant de modifier la manière dont sont enregistrées les sessions (et ainsi d'utiliser la base de données).

La durée de vie des sessions

Pour modifier la durée de vie des sessions, en plus de jouer sur la durée de vie du cookie et du cache, on peut également jouer sur le temps au-delà duquel PHP considèrera les données stockées comme obsolètes.

Pour cela, il existe trois directives de configuration :

  • session.gc_maxlifetime : il s'agit effectivement de la durée au-delà de laquelle des données de session seront considérées comme périmées ;
  • session.gc_probability : la vérification du temps de vie des données n'est pas systématique, c'est lancé aléatoirement selon une fréquence prédéfinie. Il s'agit de la probabilité de déclenchement de l'opération ;
  • session.gc_divisor : pour obtenir la fréquence de lancement de la procédure de vérification des données, il faut diviser la probabilité par ce paramètre. Par exemple, si gc_probability vaut 1 et que gc_divisor vaut 100, alors ce sera lancé 1 fois toutes les 100 ouvertures de session.

Modifier localement la configuration des sessions

Comme pour toutes les directives de configuration de PHP, il est possible de modifier la configuration des sessions sur certains serveurs. On utilise pour cela le fichier .htaccess. Pour modifier la valeur d'une directive de configuration, il suffit d'indiquer php_value ou php_flag (dans le cas d'une directive de type on/off), suivi du nom de la directive de configuration et de sa nouvelle valeur (en séparant le tout par des espaces).
Cependant, gardez à l'esprit que cela dépend entièrement de la configuration du serveur, il est même possible que seule une partie des directives soit modifiable, voire aucune…

IV-C. Modifier la façon dont sont stockées les données de sessions

Comme indiqué plus haut, PHP ne fournit pas de gestionnaire de données de sessions autres que des fichiers non cryptés. Il est cependant possible de définir vous-même les opérations à faire pour ouvrir, fermer, lire, écrire et vérifier la durée de vie d'une session.
Cette fonctionnalité vous permettra par exemple de crypter et de stocker très facilement vos sessions dans une base de données (par exemple) en écrivant les fonctions de requêtage adéquates. Une fois ceci fait, vous n'aurez alors plus besoin de définir les opérations d'accès à la base de données pour les sessions !
Vous trouverez un peu plus bas un exemple de fonctions vous permettant de stocker les sessions dans une base de données.

Dans ce cas, il vous faut alors définir ces opérations au début de chaque script (avant le session_start) !

La fonction permettant de faire ceci se nomme session_set_save_handler() et prend en argument les noms des fonctions permettant les opérations citées ci-dessus (dans le même ordre). L'exemple ci-dessous ne fait que redéfinir les opérations par défaut de PHP, pas très utile, certes, mais ça vous permet de voir comment ça fonctionne…

 
Sélectionnez
<?php
function ouvrir_session($chemin_de_stockage, $nom_de_session)
{
  $_ENV['chemin_de_stockage_des_sessions'] = $chemin_de_stockage;
  return true;
}

function fermer_session()
{
  return true; // Rien à faire
}

function lire_session($identifiant_de_session)
{
  return strval(file_get_contents($_ENV['chemin_de_stockage_des_sessions'].'/sess_'.$identifiant_de_session));
}

function ecrire_session($identifiant_de_session, $donnees_de_session)
{
  if ($fp = fopen($_ENV['chemin_de_stockage_des_sessions'].'/sess_'.$identifiant_de_session, "w")) {
   $return = fwrite($fp, $donnees_de_session);
   fclose($fp);
   return $return;
  } else {
   return false;
  }
}

function detruire_session($identifiant_de_session)
{
  return unlink($_ENV['chemin_de_stockage_des_sessions'].'/sess_'.$identifiant_de_session);
}

function verifier_validite_session($temps_de_validite)
{
  $files = glob($_ENV['chemin_de_stockage_des_sessions'].'/sess_*');

  if(!empty($files))
  {
    foreach($files as $file)
    {
      // Il peut s'agir d'un répertoire ou d'un fichier, mais seuls les fichiers nous intéressent
      if(is_file($file) and filemtime($file) + $sessionTime < time())
      {
        unlink($file);
      }
    }
  }

  /*foreach ($_ENV['chemin_de_stockage_des_sessions'].'/sess_*') as $fichier_de_session) {
   if (filemtime($fichier_de_session) + $temps_de_validite < time()) {
     unlink($fichier_de_session);
   }
  }*/

  return true;
}

session_set_save_handler(
  'ouvrir_session',
  'fermer_session',
  'lire_session',
  'ecrire_session',
  'detruire_session',
  'verifier_validite_session'
);

session_start();

// Maintenant on peut se servir des sessions sans modifications par rapport à avant...
// C'est complètement transparent pour l'utilisateur.
?>

Nous allons maintenant voir un exemple de fonctions permettant de stocker vos sessions dans une base de données. Nous utiliserons MySQL comme SGBD et MySQLi comme extension PHP pour communiquer avec MySQL. Des commentaires indiquent comment remplacer MySQLi par MySQL.

Bien sûr, il ne s'agit ici que d'un exemple ! Ces fonctions ne sont pas parfaitement sécurisées ni optimisées !

Il ne faut surtout pas, par exemple, les utiliser ainsi dans un environnement de production.

Création de la table pour stocker les données
Sélectionnez
USE my_database;

CREATE TABLE `sessions` (
    `identifiant` VARCHAR( 64 ) NOT NULL ,
    `nom` VARCHAR( 64 ) NOT NULL ,
    `dernier_acces` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    `donnees` TINYTEXT NOT NULL ,
    PRIMARY KEY ( `identifiant` , `nom` )
) ENGINE = MYISAM ;
Les fonctions d'accès en elles-mêmes
Sélectionnez
<?php
/**
 * SGBD est une constante contenant l'adresse du serveur MySQL. [typiquement 'localhost']
 * LOGIN_SGBD est une constante contenant votre login pour la connexion au serveur MySQL.
 * MOT_DE_PASSE_SGBD est une constante contenant votre mot de passe pour la connexion au serveur MySQL.
 * SESSIONS_BDD est une constante contenant le nom de la base de données où sont stockées les données. [ici, 'my_database']
 * SESSION_TABLE est une constante contenant le nom de la table où sont stockées les données. [ici, 'sessions']
*/

function ouvrir_session($chemin_de_stockage, $nom_de_session)
{
  $_ENV['nom_de_session'] = $nom_de_session;
  return true;
}

function fermer_session()
{
  return true; // Rien à faire
}

function lire_session($identifiant_de_session)
{
  $mysql = new mysqli(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD, SESSIONS_BDD);
  //$mysql = mysql_connect(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD); mysql_select_db(SESSIONS_BDD, $mysql);
  if(!$mysql)
  {
    return '';
  }
  $resultat =  $mysql->query('SELECT donnees FROM '.SESSIONS_TABLE
      .' WHERE identifiant = \''.$identifiant_de_session.'\' AND nom =\''.$_ENV['nom_de_session'].'\'');
  //$resultat = mysql_query('SELECT donnees FROM '.SESSIONS_TABLE
  //    .' WHERE identifiant = \''.$identifiant_de_session.'\' AND nom =\''.$_ENV['nom_de_session'].'\'', $mysql);
  $donnes = '';
  if($resultat->num_rows == 1) //if(mysql_num_rows($resultat) == 1)
    $donnees = $result->fetch_array(); //$donnees = mysql_fetch_array($resultat);
  $resultat->free(); //mysql_free_result($resultat);
  $mysql->close(); //mysql_close($mysql);
  return strval($donnes['donnees']);
}

function ecrire_session($identifiant_de_session, $donnees_de_session)
{
  $mysql = new mysqli(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD, SESSIONS_BDD);
  //$mysql = mysql_connect(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD); mysql_select_db(SESSIONS_BDD, $mysql);
  if(!$mysql)
  {
      return false;
  }
  $result = true;
  $mysql->query('UPDATE '.SESSIONS_TABLE.' SET donnees = \''.$donnees_de_session.'\''
          .' WHERE identifiant = \''.$identifiant_de_session.'\' AND nom =\''.$_ENV['nom_de_session'].'\'') or $result = false;
  //mysql_query('UPDATE '.SESSIONS_TABLE.' SET donnees = \''.$donnees_de_session.'\''
  //    .' WHERE identifiant = \''.$identifiant_de_session.'\' AND nom =\''.$_ENV['nom_de_session'].'\'', $mysql) or $result = false;
  $mysql->close(); //mysql_close($mysql);
  return $result;
}

function detruire_session($identifiant_de_session)
{
  $mysql = new mysqli(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD, SESSIONS_BDD);
  //$mysql = mysql_connect(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD); mysql_select_db(SESSIONS_BDD, $mysql);
  if(!$mysql)
  {
      return false;
  }
  $result = true;
  $mysql->query('DELETE FROM '.SESSIONS_TABLE.' WHERE identifiant = \''.$identifiant_de_session.'\''
      .' AND nom =\''.$_ENV['nom_de_session'].'\'') or $result = false;
  //mysql_query('DELETE FROM '.SESSIONS_TABLE.' WHERE identifiant = \''.$identifiant_de_session.'\''
  //    .' AND nom =\''.$_ENV['nom_de_session'].'\'', $mysql) or $result = false;
  $mysql->close(); //mysql_close($mysql);
  return $result;
}

function verifier_validite_session($temps_de_validite)
{
  $mysql = new mysqli(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD, SESSIONS_BDD);
  //$mysql = mysql_connect(SGBD, LOGIN_SGBD, MOT_DE_PASSE_SGBD); mysql_select_db(SESSIONS_BDD, $mysql);
  if(!$mysql)
  {
      return false;
  }
  $result = true;
  $mysql->query('DELETE FROM '.SESSIONS_TABLE.' WHERE ADDDATE(dernier_acces, INTERVAL '.$temps_de_validite.' SECOND) < NOW()')
    or $result = false;
  //mysql_query('DELETE FROM '.SESSIONS_TABLE.' WHERE ADDDATE(dernier_acces, INTERVAL '.$temps_de_validite.' SECOND) < NOW()', $mysql)
    or $result = false;
  $mysql->close(); //mysql_close($mysql);
  return $result;
}

session_set_save_handler(
  'ouvrir_session',
  'fermer_session',
  'lire_session',
  'ecrire_session',
  'detruire_session',
  'verifier_validite_session'
);

session_start();

// Maintenant on peut se servir des sessions sans modifications par rapport à avant...
// C'est complètement transparent pour l'utilisateur.
?>

IV-D. À savoir

  • L'hébergeur Free est une exception puisque, pour pouvoir utiliser les sessions, il vous faudra créer à la racine de votre FTP un répertoire nommé sessions.
  • La fonction session_id() utilisée sans paramètre renvoie l'identificateur actuel de la session et la fonction session_name() utilisée sans paramètre renvoie le nom courant de la session. Ainsi, pour passer dans un lien l'identificateur de session, ce qui permet de récupérer la session de l'utilisateur même s'il change de répertoire, il suffit de procéder ainsi :
 
Sélectionnez
<?php
echo 'http://adresse_de_votre_site?' . session_name() . '=' . session_id();
?>

précédentsommairesuivant

Copyright © 2006 Developpez.com Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.