使用 PDO 将会话存储在数据库中的 PHP 不会产生我预期的错误
Posted
技术标签:
【中文标题】使用 PDO 将会话存储在数据库中的 PHP 不会产生我预期的错误【英文标题】:PHP using PDO to store session in DB doesnt produce the errors i expected 【发布时间】:2013-03-01 11:59:24 【问题描述】:已解决: 答案在第二个帖子中
我尝试使用 PDO 将会话存储在 DB 中,但它不会产生我预期的错误,请阅读我的代码。
这是我的会话处理程序类的代码:
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 连接 -> db 连接关闭 -> @987654328 @将尝试写入并关闭,但由于pdo已被php关闭,因此没有db连接,但没有产生错误..
更新 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
类时,它不会因为没有连接而产生错误。
【问题讨论】:
不要使用 try..catch 和 die!这是无用的、错误的和不安全的 好吧,谢谢您的提示。顺便说一句,在 catch 块中做的好的/做法是什么 仅当您要以某种方式处理错误时才使用 catch 块。否则就放手吧。 PHP 将通知您并自动退出脚本 - 因此,无需编写 100 次捕获。 哦,好吧,这真的帮助我变得更好。谢谢!无论如何,你知道为什么我上面的 pdo 脚本不会产生错误吗? 有些问题一目了然无法回答,只能经过一些调试。如果您认为这种行为是错误的,为什么不想稍微调试一下您的代码? 【参考方案1】:解决方案
对不起,伙计们,我的错误实际上是一个非常简单的答案,为什么 MySessionHandler
类不会在脚本末尾出现 session_write_close()
错误,
session_set_save_handler()
默认注册session_write_close()
到register_shutdown_function()
因此,如果您想为会话创建自己的关闭功能,请使用:
session_set_save_handler($SessionClass, FALSE)
,如果你这样做,那么你必须在你的类析构函数中提供session_write_close()
来源:http://php.net/manual/en/function.session-set-save-handler.php
感谢您的提示和关注
【讨论】:
接受你的回答,那么很明显它已经回答了。并不是说有人通过文字墙工作然后最终意识到它是徒劳的。以上是关于使用 PDO 将会话存储在数据库中的 PHP 不会产生我预期的错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 PDO 和 PHP 将表单中的数据插入 MySQL 数据库