- session_regenerate_id().
- stockage et vérification de l'ip du visiteur en variable de session.
- stockage et vérification d'un hash composé de l'identifiant du navigateur, de l'adresse ip, d'un sel aléatoire, et de l'identifiant de session.
Je n'ai pas repris le code, et il y a des défauts qui sautent aux yeux (par exemple que la vérification de l'ip est incluse dans la vérification du hash, et donc inutile).
C'est livré comme toujours "as-is", et je vous documente ça là vite fait (*)
Instanciation
Session implémente le Singleton. On n'appelle donc pas son constructeur, mais on rappelle l'instance statique :Utilisation$session = Session::Instance();
Les variables de session sont les variables membres de la classe. Evitez d'utiliser les variables de session "_random" et "_instance" je crois que ça provoquerait une erreur.Méthodes// enregistrer une variable de session $session->maVariable = "ma valeur"; // vérifier qu'une variable existe if (isset($session->maVariable)) { echo "OK, elle est en session"; } // détruire une variable unset($session->maVariable);
static Session Instance()
Rappelle l'instance unique de l'objet Session (singleton).
array all()
Renvoie la liste des noms de variables définies en session.
void unsetAll()
Détruit toutes les variables de session.
Exemple d'utilisation, le compteur$session = Session::Instance(); if (!isset($session->counter)) { $session->counter = 0; } $session->counter += 1; echo "COUNTER={$session->counter}";
<?php
class Session
{
private static $_instance;
private $_random;
private function __construct()
{
$this->_random = new Random();
if (headers_sent($filename,$lineno)) {
throw new Exception('Headers already sent by '.$filename.' (line '.$lineno.') : cannot start session');
}
session_start();
$this->__unset('sec_corrupted');
$this->checkIp();
$this->checkHash();
session_regenerate_id();
$this->setIp();
$this->setHash();
}
public static function Instance()
{
if (!self::$_instance) {
self::$_instance =& new self();
}
return self::$_instance;
}
private function __get($name)
{
return $_SESSION[$name];
}
private function __set($name, $value)
{
return $_SESSION[$name] = $value;
}
private function __unset($name)
{
unset($_SESSION[$name]);
session_unregister($name);
}
private function __isset($name)
{
return isset($_SESSION[$name]);
}
public function all()
{
return array_keys($_SESSION);
}
private function checkIp()
{
$ip = $_SERVER['REMOTE_ADDR'];
if ($this->__isset('sec_ip')) {
if ($this->__get('sec_ip') != $ip) {
// corrupted !
$this->unsetAll();
$this->__set('sec_corrupted', 'ip');
}
}
}
private function setIp()
{
$ip = $_SERVER['REMOTE_ADDR'];
$this->__set('sec_ip', $ip);
}
private function generateSalt()
{
if (!$this->__isset('sec_salt')) {
$this->__set('sec_salt', $this->_random->generateAlnum(8));
}
}
private function getHash()
{
$this->generateSalt();
$hash = md5(
$this->__get('sec_salt') . ':' .
$_SERVER['HTTP_USER_AGENT'] . ':' .
$_SERVER['REMOTE_ADDR'] . ':' .
session_id());
return $hash;
}
private function checkHash()
{
$hash = $this->getHash();
if ($this->__isset('sec_hash')) {
if ($this->__get('sec_hash') != $hash) {
// corrupted !
$this->unsetAll();
$this->__set('sec_corrupted', 'hash');
}
}
}
private function setHash()
{
$hash = $this->getHash();
$this->__set('sec_hash', $hash);
}
public function unsetAll()
{
$vars = $this->all();
foreach ($vars as $var) {
$this->__unset($var);
}
}
}
?>
Cette classe utilise la class "Random" ci-dessous :<?php
class Random
{
public function __construct()
{
$this->seed(microtime(true));
}
public function seed($seed)
{
mt_srand($seed);
}
public function get($min = null, $max = null)
{
if ($max === null && $min !== null) {
return false;
}
if ($min === null) {
return mt_rand();
}
else {
return mt_rand($min, $max);
}
}
public function generateAlpha($len, $case_sensitive = false)
{
$chars = 'abcdefghijklmnopqrstuvwxyz';
if (!$case_sensitive) {
$chars .= strtoupper($chars);
}
return $this->generateString($chars);
}
public function generateAlnum($len, $case_sensitive = false)
{
$chars = 'abcdefghijklmnopqrstuvwxyz';
if (!$case_sensitive) {
$chars .= strtoupper($chars);
}
$head = $this->generateString($chars, 1);
$chars .= '0123456789';
$tail = $this->generateString($chars, $len-1);
return $head . $tail;
}
public function generateString($chars, $len)
{
$string = '';
$nb_chars = strlen($chars);
for ($i=0; $i<$len; ++$i) {
$string .= $chars{$this->get(0, $nb_chars)};
}
return $string;
}
}
?>
(*) C'est du vieux code, je l'ai relu et retesté il est OK, mais - honte sur moi - n'est pas commenté ni documenté. L'objet c'est bien on comprend vite de quoi on parle, mais si on me le demande j'ajouterai des commentaires.