3

我按照http://www.php.net/manual/en/class.sessionhandlerinterface.php制作了以下代码

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();

谢谢你的时间

干杯

4

1 回答 1

4

您没有锁定会话。这是最大的错误。

每当 PHP 中的请求启动会话并从文件中读取数据时,PHP 会获取该文件上的锁,并且任何并行请求将停止并等待该session_start()函数,直到锁被释放。

如果不加锁,会发生以下情况: 第一个请求从数据库中读取所有数据。第二个请求也读取相同的数据。第一个请求将值更改为 A。第二个请求将另一个值更改为 B。第一个请求结束并将其 A 写回数据库。然后第二个请求用 B 写回更改,但没有 A。数据丢失!

我注意到的另一件事:为什么要使用 base64 对加密数据进行编码?这不是必需的,数据库可以接受二进制数据。唯一的好处是你的主机可以卖给你一台更大的机器。

于 2013-08-25T09:01:46.240 回答