我按照http://www.php.net/manual/en/class.sessionhandlerinterface.php
制作了以下代码AND
http://www.wikihow.com/Create-a-Secure-Session-Managment-System-in-PHP-and-MySQL
这里我使用MySQL数据库来存储和检索会话变量。这段代码工作正常。但是,如果您能够指出错误并分享您对此代码的意见,那将会很棒。
class MySessionHandler implements SessionHandlerInterface
{
public function open($savePath, $sessionName)
{
$host = 'localhost';
$user = '******';
$pass = '******';
$name = '*******';
$mysqli = new mysqli($host, $user, $pass, $name);
$this->db = $mysqli;
return true;
}
public function close()
{
return true;
}
public function read($id)
{
if(!isset($this->read_stmt)) {
$this->read_stmt = $this->db->prepare("SELECT data FROM sessions 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);
return $data;
}
public function write($id, $data)
{
// 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 sessions (id, set_time, data, session_key) VALUES (?, ?, ?, ?)");
}
$this->w_stmt->bind_param('siss', $id, $time, $data, $key);
$this->w_stmt->execute();
return true;
}
public function destroy($id)
{
if(!isset($this->delete_stmt)) {
$this->delete_stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?");
}
$this->delete_stmt->bind_param('s', $id);
$this->delete_stmt->execute();
return true;
}
public function gc($maxlifetime)
{
if(!isset($this->gc_stmt)) {
$this->gc_stmt = $this->db->prepare("DELETE FROM sessions WHERE set_time < ?");
}
$old = time() - $max;
$this->gc_stmt->bind_param('s', $old);
$this->gc_stmt->execute();
return true;
}
private function getkey($id) {
if(!isset($this->key_stmt)) {
$this->key_stmt = $this->db->prepare("SELECT session_key FROM sessions 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;
}
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();
感谢您的时间
干杯
答案 0 :(得分:3)
您没有锁定会话。这是最大的错误。
每当PHP中的请求启动会话并从文件中读取数据时,PHP就会获取该文件的锁定,并且任何并行请求都将停止并等待session_start()
函数,直到锁定释放为止。
如果您没有锁定,将发生以下情况:第一个请求从数据库中读取所有数据。第二个请求也读取相同的数据。第一个请求将值更改为A.第二个请求将另一个值更改为B.第一个请求结束并将其A写回数据库。然后第二个请求用它的B回写更改,但是没有A.数据丢失了!
我注意到的另一件事:为什么用base64编码加密数据?这不是必需的,数据库可以接受二进制数据。唯一的好处是你的主机可以卖给你更大的机器。