已解决:答案在第二篇文章中
我尝试使用 PDO 将会话存储在数据库中,但它不会产生我预期的错误,请阅读我的代码。
这是我的会话处理程序类的代码:
class MySessionHandler implements SessionHandlerInterface
{
protected $conn = NULL;
public function open($savePath, $sessionName)
{
if(is_null($this->conn))
{
$dsn = 'mysql:host=localhost;dbname=php_advanced';
$username = 'root';
$password = 'password';
try
{
$this->conn = new PDO($dsn, $username, $password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
$this->conn = NULL;
die('error in open function ' . $e->getMessage());
}
}
return TRUE;
}
public function close()
{
echo '<p>close</p>';
$this->conn = NULL;
return TRUE;
}
public function read($id)
{
echo '<p>read</p>';
$query = 'SELECT data FROM session_table WHERE session_id = :id';
try
{
$pdo = $this->conn->prepare($query);
$pdo->bindValue(':id', $id);
$pdo->execute();
// Kalo query berhasil nemuin id..
if($pdo->rowCount() == 1)
{
list($sessionData) = $pdo->fetch();
return $sessionData;
}
return FALSE;
}
catch(PDOException $e)
{
$this->conn = NULL;
die('error in read function => ' . $e->getMessage());
}
}
public function write($id, $data)
{
echo '<p>write</p>';
$query = 'REPLACE INTO session_table(session_id, data) VALUES(:id, :data)';
try
{
$pdo = $this->conn->prepare($query);
$pdo->bindValue(':id', $id);
$pdo->bindValue(':data', $data);
$pdo->execute();
// return the value whether its success or not
return (bool)$pdo->rowCount();
}
catch(PDOException $e)
{
$this->conn = NULL;
die('error in write function => ' . $e->getMessage());
}
}
public function destroy($id)
{
echo '<p>destroy</p>';
$query = 'DELETE FROM session_table WHERE session_id = :id LIMIT 1';
try
{
$pdo = $this->conn->prepare($query);
$pdo->bindValue(':id', $id);
$pdo->execute();
$_SESSION = array();
return (bool)$pdo->rowCount();
}
catch(PDOException $e)
{
$this->conn = NULL;
die('error in destroy function => ' . $e->getMessage());
}
}
public function gc($maxLifeTime)
{
echo '<p>garbage collection</p>';
$query = 'DELETE FROM session_table WHERE DATE_ADD(last_accessed INTERVAL :time SECOND) < NOW()';
try
{
$pdo = $this->conn->prepare($query);
$pdo->bindValue(':time', $maxLifeTime);
$pdo->execute();
return TRUE;
}
catch(PDOException $e)
{
$this->conn = NULL;
die('error in gc function => ' . $e->getMessage());
}
}
}
$SessionHandler = new MySessionHandler();
session_set_save_handler($SessionHandler);
session_name('my_session');
session_start();
我故意删除了 session_write_close。这可能听起来很愚蠢,但我想获得会话错误以了解更多信息..
这是会话脚本(使用本书的代码):
require('session_class.php');
?><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>DB Session Test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<?php
// Store some dummy data in the session, if no data is present:
if (empty($_SESSION)) {
$_SESSION['blah'] = 'umlaut';
$_SESSION['this'] = 3615684.45;
$_SESSION['that'] = 'blue';
// Print a message indicating what's going on:
echo '<p>Session data stored.</p>';
} else { // Print the already-stored data:
echo '<p>Session Data Exists:<pre>' . print_r($_SESSION, 1) . '</pre></p>';
}
// Log the user out, if applicable:
if (isset($_GET['logout'])) {
session_destroy();
echo '<p>Session destroyed.</p>';
} else { // Otherwise, print the "Log Out" link:
echo '<a href="session_link.php?logout=true">Log Out</a>';
}
// Reprint the session data:
echo '<p>Session Data:<pre>' . print_r($_SESSION, 1) . '</pre></p>';
// Complete the page:
echo '</body>
</html>';
// Write and close the session:
// session_write_close() <<<<<--- I REMOVE THIS ON PURPOSE TO GET ERROR
?>
但我没有收到任何错误,然后我尝试使用 book 的 mysqli 脚本连接数据库,它产生了我预期的错误,因为我删除了session_write_close()
..
谁能解释为什么如果我使用 PDO 它不会产生错误?我什至不使用
register_shutdown_function('session_write_close');
在我的会话类析构函数中(故意)
注意:我是故意这样做的,因为我想了解更多。
我期望的错误就像我使用 mysqli 连接时一样(连接在脚本末尾由 php 关闭,然后会话尝试写入并关闭但没有可用的连接):
Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 66
Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 66
Warning: mysqli_query() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 67
Warning: mysqli_close() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 33
更新 1
我最近发现 mysqli 每次使用时都需要数据库连接mysqli_real_escape_string()
,mysqli_query
并且因为但我认为我的 pdo 在脚本结束时也需要数据库连接-> db 连接关闭->MySessionHandler
将尝试写入并关闭,但没有 db连接,因为 pdo 已被 php 关闭,但没有产生错误..
更新 2
我只是试图传递session_set_save_handler
函数回调,它会产生错误
<?php
$conn = NULL;
function open_session()
{
echo '<p>open session</p>';
global $conn;
$_dsn = 'mysql:host=localhost;dbname=php_advanced';
$_username = 'root';
$_password = 'password';
$conn = new PDO($_dsn, $_username, $_password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return TRUE;
}
function close_session()
{
echo '<p>close session</p>';
global $conn;
$conn = NULL;
return TRUE;
}
function read_session($sid)
{
echo '<p>read session</p>';
global $conn;
$query = 'SELECT data FROM session_table WHERE session_id = :sid';
$pdo = $conn->prepare($query);
$pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
$pdo->execute();
if($pdo->rowCount() == 1)
{
list($session_data) = $pdo->fetch();
echo '<pre>';
print_r($session_data);
echo '</pre>';
return $session_data;
}
else
{
return '';
}
}
function write_session($sid, $data)
{
echo '<p>write session</p>';
global $conn;
$query = 'REPLACE INTO session_table(session_id, data) VALUES(:sid, :data)';
$pdo = $conn->prepare($query);
$pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
$pdo->bindValue(':data', $data, PDO::PARAM_STR);
$pdo->execute();
return $pdo->rowCount();
}
function destroy_session($sid)
{
echo '<p>destroy session </p>';
global $conn;
$query = 'DELETE FROM session_table WHERE session_id = :sid';
$pdo = $conn->prepare($query);
$pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
$pdo->execute();
// clean the session array;
$_SESSION = array();
return (bool)$pdo->rowCount();
}
function clean_session($expire)
{
echo '<p>clean session</p>';
global $conn;
$query = 'DELETE FROM session_table WHERE DATE_ADD(last_accessed, INTERVAL :expire SECOND) < NOW()';
$pdo = $conn->prepare($query);
$pdo->bindValue(':expire', $expire, PDO::PARAM_INT);
$pdo->execute();
return $pdo->rowCount();
}
session_set_save_handler('open_session', 'close_session', 'read_session', 'write_session', 'destroy_session', 'clean_session');
session_name('my_session');
session_start();
但是当我通过MySessionHandler
课程时,它不会因为没有连接而产生错误。