我正在尝试使用PHP的session_set_save_handler
,我想使用PDO连接来存储会话数据。
我将此函数作为写操作的回调函数:
function _write($id, $data) {
logger('_WRITE ' . $id . ' ' . $data);
try {
$access = time();
$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$stmt->bindParam(':access', $access, PDO::PARAM_INT);
$stmt->bindParam(':data', $data, PDO::PARAM_STR);
$stmt->execute();
$stmt->closeCursor();
return true;
} catch (PDOException $e) {
logger('This is never executed.');
logger($e->getTraceAsString());
}
}
前两条日志消息总是显示出来,但是$stmt = $GLOBALS['db']->prepare($sql)
之后的第三条消息永远不会显示在日志文件中,也没有异常的痕迹。
会话 db表保持为空。
来自_close
回调的日志消息始终存在。
以下是我连接数据库的方式:
$db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
我有PHP 5.2.10。
我尝试使用“手动准备的”$GLOBALS['db']->exec($sql)
内容运行$sql
,但它仍然无声地失败。查询本身没问题,我可以通过数据库控制台执行它。
在VolkerK发现问题之后我发现this article解释了这种奇怪现象背后的原因。也许它也可以为其他人提供信息。
最不痛苦,神奇的解决方案是我必须将以下函数调用添加到我的前端控制器(主index.php)文件的最后:
session_write_close();
答案 0 :(得分:4)
我的注意事项是:$ GLOBALS ['db']未设置或不是pdo的实例(不再?),因此发生PHP Fatal error: Call to a member function prepare() on a non-object
并且php退出。
$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
if ( !isset($GLOBALS['db']) ) {
logger('there is no globals[db]');
return;
}
else if ( !is_object($GLOBALS['db']) ) {
logger('globals[db] is not an object');
return;
}
else if ( !($GLOBALS['db'] instanceof PDO) ) {
logger('globals[db] is not a PDO object');
return;
}
else {
logger('globals[db] seems ok');
}
$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');
答案 1 :(得分:1)
也许PDO无法识别REPLACE INTO语法。如果底层数据库访问库不直接支持预准备语句,则PDO会模拟它们,并且可能在其可能的语句类型列表中没有REPLACE INTO。
在准备通话后立即尝试检查$stmt->errorCode()
?
如果这是mysql,您可以尝试重写预准备语句,如下所示:
INSERT INTO sessions (id, access, data)
VALUES(:id, :access, :data)
ON DUPLICATE KEY UDPATE
access=VALUES(access), data=VALUES(data);
看看是否能让你更远。
答案 2 :(得分:0)
我觉得无法通过$GLOBALS[]
访问资源数据类型。关于引用的方式或其他方面的东西。如果你有心情幽默我的预感,试试这个函数声明:
function _write($id, $data) {
global $db;
logger('_WRITE ' . $id . ' ' . $data);
try {
而不是这个:
$stmt = $GLOBALS['db']->prepare($sql);
试
$stmt = $db->prepare($sql);
你也可以尝试捕捉普通的旧Exception
而不是PDOException
s;它可能会陷入其中。
希望这有帮助!