我使用这个article构建了这个会话类。我确信我已经遵循了所有规则和所有给出的信息,但我的代码不起作用。
会话课程:session.php
class Session {
function __construct() {
// set our custom session functions
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
// This line prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');
}
function start_session($session_name, $secure) {
// Make sure the session cookie is not accessable via javascript
$httponly = true;
// Hash algorith to use for the session_id
$session_hash = 'sha512';
// Check if hash is available
if (in_array($session_hash, hash_algos())) {
// Set the hash function
ini_set('session.hash_function', $session_hash);
}
// How many bits per character of the hash
ini_set('session.hash_bits_per_character', 5);
// Force the session to only use cookies, nut 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 sesion name
session_name($session_name);
// Now we can 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
session_regenerate_id(true);
}
function open() {
// Define Connection variables
$host = '';
$user = '';
$pass = '';
$dbnm = '';
// Connection string based on connection variables
$PDO = new PDO("mysql:host=$host;dbname=$dbnm", $user, $pass);
// Connect to DB based on connection string
$this->db = $PDO;
return true;
}
function close() {
// Close DB connection
$this->db->close();
return true;
}
function read($id) {
// If not the read statement is defined
if(!isset($this->read_stmt)) {
// Prepared statement for getting data from DB
$this->read_stmt = $this->db->prepare("SELECT data FROM sessions WHERE id = ? LIMIT 1");
}
$this->read_stmt->bind_param('s', $id); // Replace ? with $id
$this->read_stmt->execute(); // Execute the prepared statement
$this->read_stmt->store_result(); // We store the data returned
$this->read_stmt->bind_result($data); // We bind the result to a $data variable
$this->read_stmt->fetch(); // And fetch returned data
// This function is defined later
// but returns the session key based on the $id
$key = $this->getkey($id);
// Both the variabels are decrypted and assigned to $data
$data = $this->decrypt($data, $key);
// We return the results
return $data;
}
function write($id, $data) {
// Get unique session key
$key = $this->getkey($id);
//Encrypt the data
$data = $this->encrypt($data);
// Assign current time to $time variable
$time = time();
// If not the write statement is defined
if(!isset($this->write_stmt)) {
// Prepared statement for replacing data in DB
$this->write_stmt = $this->db->prepare("REPLACE INTO sessions (id, set_time, data, session_key) VALUES (?, ?, ?, ?)");
}
$this->write_stmt->bind_param('siss', $id, $time, $data, $key); // Replace ?, ?, ?, ? with $id, $time, $data, $key
$this->write_stmt->execute(); // Execute the prepared statement
// Return confirmation
return true;
}
function destroy($id) {
// If not the delete statement is defined
if(!isset($this->delete_stmt)) {
// Prepared statement for deleting session data from DB
$this->delete_stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?");
}
$this->delete_stmt->bind_param('s', $id); // Replace ? with $id
$this->delete_stmt->execute(); // Execute the prepared statement
// Return confirmation
return true;
}
function gc($max) {
// This function 'Garbage Collector' is emptying the DB for old sessions
// this way, the DB takes care of itself.
// If not the GC statement is defined
if(!isset($this->gc_stmt)) {
// Prepared statement for deleting session data from DB
$this->gc_stmt = $this->db->prepare("DELETE FROM sessions WHERE set_time < ?");
}
// Define $old to be an old statement
$old = time() - $max;
$this->gc_stmt->bind_param('s', $old); // Replace ? with $old
$this->gc_stmt->execute(); // Execute the prepared statement
// Return confirmation
return true;
}
private function getkey($id) {
// This function is used to get the unique key for encryption from the sessions table.
// If there is no session it just returns a new random key for encryption.
// If not the select statement is defined
if(!isset($this->key_stmt)) {
// Prepared statement for selecting session key from DB
$this->key_stmt = $this->db->prepare("SELECT session_key FROM sessions WHERE id = ? LIMIT 1");
}
$this->key_stmt->bind_param('s', $id); // Replace ? with $old
$this->key_stmt->execute(); // Execute the prepared statement
$this->key_stmt->store_result(); // We store the data returned
// If the select statement returns a row
if($this->key_stmt->num_rows == 1) {
$this->key_stmt->bind_result($key); // We bind the result to a $data variable
$this->read_stmt->fetch(); // And fetch returned data
// Then we return the result
return $key;
} else {
// We generate a random key
$random_key = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
// Then we return the result
return $random_key;
}
}
private function encrypt($data, $key) {
// A complete random key for encryption
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
// We assign a hash encoded version of the random key and session key to the $key
$key = substr(hash('sha256', $salt.$key.$salt), 0, 32);
// Open module, and create IV
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
// Do the encryption and assign it to $encrypted
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, $iv));
// And return the encrypted data
return $encrypted;
}
private function decrypt($data, $key) {
// The same key for encryption is used for decrytion (obviously)
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
// We assign a hash encoded version of the random key and session key to the $key
$key = substr(hash('sha256', $salt.$key.$salt), 0, 32);
// Open module, and create IV
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
// Do the decryption and assign it to $decrypted
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_ECB, $iv);
// And return the decrypted data
return $decrypted;
}
}
然后我有两页用于测试。我也相信这些页面写得正确,所以必须有一些东西阻止类工作..我有一个更大的脚本,我使用相同的类,我能够定义新的类$session = new Session();
但是当我开始会话$session->start_session('test', false);
脚本死了。
测试页面PHP:tester.php
<?
require_once('session.php');
$session = new Session();
$session->start_session('test', false);
$_SESSION['dims'] = 'This is a session variable';
?>
<a href="tester2.php">click here</a>
测试页2 PHP:tester2.php
<?
require_once('session.php');
$session = new Session();
$session->start_session('test', false);
echo $_SESSION['dims'];
?>
我发现出现了500错误的内部服务器错误。
答案 0 :(得分:1)
您的类已通过PDO建立了连接,但您正在使用的教程使用MySQLi预处理语句。这两个API彼此不兼容。 PDO中的等效代码如下所示:
// If not the read statement is defined
if(!isset($this->read_stmt)) {
// Prepared statement for getting data from DB
// Prepare using the named parameter :id instead of ? (though ? can be used in PDO too)
$this->read_stmt = $this->db->prepare("SELECT data FROM sessions WHERE id = :id LIMIT 1");
}
// If the statement was successfully prepared...
if ($this->read_stmt) {
// One of 2 param binding methods in PDO...
$this->read_stmt->bindParam(':id', $id, PDO::PARAM_STR);
$this->read_stmt->execute();
// No correlate for store_result() in PDO...
// Fetch the first row and get the data key from it
// You don't need to do a bind result in PDO. Instead just fetch() or fetchAll()
// more like the old mysql_fetch_*() functions.
$row = $this->read_stmt->fetch(PDO::FETCH_ASSOC);
$data = $row['data']
// Do the rest of your stuff with data.
}
我不会在上面翻译你的整个代码块,但这应该让你开始。 PDO docs on bindParam()
有足够的示例,您应该能够找出其他查询。
最后,我推荐PDO Tutorial for MySQL Developers,它有很好的例子,虽然它没有直接解决将MySQLi预处理语句翻译成PDO语句的问题。