2013-03-26 1 views
4

J'utilise session_set_save_handler() pour enregistrer des sessions dans une base de données.

Après le passage de php v.5.3 à v.5.4, la fonction write() n'est pas appelée du tout; ni lors de l'appel de la fonction session_write_close(), ni lorsque le script est terminé (il fonctionnait correctement avant et aucune modification n'a été apportée au code). Les fonctions read(), open() et close() sont toujours appelées comme d'habitude.

Je sais qu'il y a plusieurs changements dans php 5.4 liés au mécanisme session_set_save_handler(). Est-ce que quelqu'un a un problème similaire ou sait ce qui a été changé?session_set_save_handler et écrire sur php 5.4.12

class session { 

    private $table_name; 

    function __construct() { 
     $this->table_name = SESS_TABLE; 

     session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc')); 
     register_shutdown_function('session_write_close'); 

    } 

    function start_session($session_name, $secure) { 
     global $session; 

     // Make sure the session cookie is not accessable via javascript. 
     $httponly = true; 

     // Hash algorithm to use for the sessionid. (use hash_algos() to get a list of available hashes.) 
     $session_hash = 'sha512'; 

     // Check if hash is available 
     if (in_array($session_hash, hash_algos())) { 
      // Set the has function. 
      ini_set('session.hash_function', $session_hash); 
     } 
     // How many bits per character of the hash. 
     // The possible values are '4' (0-9, a-f), '5' (0-9, a-v), and '6' (0-9, a-z, A-Z, "-", ","). 
     ini_set('session.hash_bits_per_character', 5); 

     // Force the session to only use cookies, not URL variables. 
     ini_set('session.use_only_cookies', 1); 

     // Get session cookie parameters 
     $cookieParams = session_get_cookie_params(); 
     // Set the parameters 
     session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly); 
     // Change the session name 
     session_name($session_name); 
     // Now we cat start the session 
     session_start(); 
     // This line regenerates the session and delete the old one. 
     // It also generates a new encryption key in the database. 
     if(USE_REGENERATE){ 
      $this->regenerate_id(); 
     } 
     //session_regenerate_id(true);  
    } 

    function regenerate_id() { 

     $old_sess_id = session_id(); 
     session_regenerate_id(true); 
     $new_sess_id = session_id(); 
     Logger::write($old_sess_id .'-'.$new_sess_id , 'session.log'); 

     $time = time(); 
     if(!isset($this->u_stmt)) { 
      $this->u_stmt = $this->db->prepare(" UPDATE ".$this->table_name." set id = ? where id=?"); 
     } 

     $this->u_stmt->bind_param('ss', $new_sess_id,$old_sess_id); 
     $this->u_stmt->execute(); 
     return true; 
    } 

    function open() { 
     $host = 'localhost'; 
     $user = SESS_USER; 
     $pass = SESS_PASSWORD; 
     $name = SESS_DBNAME; 
     $mysqli = new mysqli($host, $user, $pass, $name); 
     $this->db = $mysqli; 
     return true; 
    } 

    function close() { 
     $this->db->close(); 
     return true; 
    } 

    function read($id) { 
     global $s_read_start, $s_read_end; 
     $s_read_start = microtime(true); 
     if(!isset($this->read_stmt)) { 
      $this->read_stmt = $this->db->prepare("SELECT data FROM ".$this->table_name." WHERE id = ? LIMIT 1"); 
     } 
     $this->read_stmt->bind_param('s', $id); 
     $this->read_stmt->execute(); 
     $this->read_stmt->store_result(); 
     $this->read_stmt->bind_result($data); 
     $this->read_stmt->fetch(); 
     $key = $this->getkey($id); 
     $data = $this->decrypt($data, $key); 
     $s_read_end = microtime(true); 
     if($s_read_end-$s_read_start > MORE_THEN) 
      error_log (date("Y-m-d H:i:s").' '.'READ: '. ($s_read_end-$s_read_start).PHP_EOL,3,BASE_DIR.'/logs/cookies.log'); 
     return $data; 
    } 

    function write($id, $data) { 
     error_log (date("Y-m-d H:i:s").' '.'WRITE: '.PHP_EOL,3,BASE_DIR.'/logs/cookies.log'); 
     global $s_write_start, $s_write_end; 
     $s_write_start = microtime(true); 
     // Get unique key 
     $key = $this->getkey($id); 
     // Encrypt the data 
     $data = $this->encrypt($data, $key); 

     $time = time(); 
     if(!isset($this->w_stmt)) { 
      $this->w_stmt = $this->db->prepare("REPLACE INTO ".$this->table_name." (id, set_time, data, session_key) VALUES (?, ?, ?, ?)"); 
     } 

     $this->w_stmt->bind_param('siss', $id, $time, $data, $key); 
     $this->w_stmt->execute(); 
     $s_write_end = microtime(true); 
     if($s_write_end-$s_write_start > MORE_THEN) 
      error_log (date("Y-m-d H:i:s").' '.'WRITE: '. ($s_write_end-$s_write_start).PHP_EOL,3,BASE_DIR.'/logs/cookies.log'); 
     return true; 
    } 

    function destroy($id) { 
     global $s_destroy_start, $s_destroy_end; 
     $s_destroy_start = microtime(true); 

     if(!isset($this->delete_stmt)) { 
      $this->delete_stmt = $this->db->prepare("DELETE FROM ".$this->table_name." WHERE id = ?"); 
     } 
     $this->delete_stmt->bind_param('s', $id); 
     $this->delete_stmt->execute(); 
     $s_destroy_end = microtime(true); 
     if($s_destroy_end-$s_destroy_start > MORE_THEN) 
      error_log (date("Y-m-d H:i:s").' '.'DESTROY: '. ($s_destroy_end-$s_destroy_start).PHP_EOL,3,BASE_DIR.'/logs/cookies.log'); 
     return true; 
    } 

    function gc($max) { 
     global $s_gc_start, $s_gc_end; 
     $s_gc_start = microtime(true); 

     if(!isset($this->gc_stmt)) { 
      $this->gc_stmt = $this->db->prepare("DELETE FROM ".$this->table_name." WHERE set_time < ?"); 
     } 
     $old = time() - $max; 
     $this->gc_stmt->bind_param('s', $old); 
     $this->gc_stmt->execute(); 
     $s_gc_end = microtime(true); 
     if($s_gc_end-$s_gc_start > MORE_THEN) 
      error_log (date("Y-m-d H:i:s").' '.'GC: '. ($s_gc_end-$s_gc_start).PHP_EOL,3,BASE_DIR.'/logs/cookies.log'); 
     return true; 
    } 

    private function getkey($id) { 
     if(!isset($this->key_stmt)) { 
      $this->key_stmt = $this->db->prepare("SELECT session_key FROM ".$this->table_name." WHERE id = ? LIMIT 1"); 
     } 
     $this->key_stmt->bind_param('s', $id); 
     $this->key_stmt->execute(); 
     $this->key_stmt->store_result(); 
     if($this->key_stmt->num_rows == 1) { 
      $this->key_stmt->bind_result($key); 
      $this->key_stmt->fetch(); 
      return $key; 
     } else { 
      $random_key = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true)); 
      return $random_key; 
     } 
    } 

    private function encrypt($data, $key) { 
     $salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*[email protected]@pH'; 
     $key = substr(hash('sha256', $salt.$key.$salt), 0, 32); 
     $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); 
     $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
     $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, $iv)); 
     return $encrypted; 
    } 

    private function decrypt($data, $key) { 
     $salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*[email protected]@pH'; 
     $key = substr(hash('sha256', $salt.$key.$salt), 0, 32); 
     $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); 
     $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
     $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_ECB, $iv); 
     return $decrypted; 
    } 
} 

Utilisation:

$session = new session(); 
$session->start_session('name', false); 

Désolé pour certains débogage dans le code.

+1

Pouvez-vous montrer le code? (si c'est trop, alors postez-le à pastebin et partagez le lien peut être aussi bien) – hek2mgl

+0

Le code est ajouté. –

+0

semble que session_register_shutdown (void) est utilisé d'une manière non destinée à> = 5.4? Utilisez à la place 'register_shutdown_function ('shutdown');'? De plus, n'y a-t-il pas une interface que vous pouvez utiliser maintenant? – ficuscr

Répondre

0

Il semble que votre objet de session ait été détruit par le garbage collector interne de PHP avant l'appel de la fonction shutdown. Dans ce cas, vous devez déplacer la fonction session_write_close() en destructor:

function __destruct() { 
    session_write_close(); 
} 

je vous recommande de réécrire votre code selon le nouveau mécanisme de gestion de session. Implémentez SessionHandlerInterface pour éviter un tel comportement à l'avenir.

Questions connexes