I use session_set_save_handler() to save the sessions in the database.
After switching from php v.5.3 to v.5.4, the write() function is not called at all; neither when the session_write_close() function was called, nor when the script ended (it worked correctly before and no changes were made to the code). The read() , open() and close() functions are still called normal.
I know that in php 5.4 there are several changes related to the session_set_save_handler() mechanism. Does anyone have a similar problem or know what has been changed?
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, af), '5' (0-9, av), and '6' (0-9, az, AZ, "-", ","). 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("Ymd 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("Ymd 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("Ymd 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("Ymd 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("Ymd 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* ewr4n39=E@rAsp7c-Ph @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* ewr4n39=E@rAsp7c-Ph @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; } }
Using:
$session = new session(); $session->start_session('name', false);
Sorry for debugging the code.