我创建自己的自定义SessionHandler,将会话信息存储在 postgresql 9.3 数据库中,并且我遇到了会话数据传递给{{1}的问题方法没有被写入数据库,但会话名称是??
write()
时处理会话 - 使用各种方法的回显输出进行测试,并且/ tmp中没有创建会话文件session_start()
中的$session_data
arg包含正确的序列化字符串,如回显write()
方法中的内容所示。write()
正好被写入数据库,因此是一个BLANK序列化字符串$session_name
。a:0:{}
为空还是没有返回值?read()
session.save_handler = user
session.use_strict_mode = 1
session.use_cookies = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.name = _g
session.auto_start = 0
session.serialize_handler = php_serialize
class SessionManagement implements SessionHandlerInterface {
private $_id = '';
private $_link = null;
public function __construct() {
session_set_save_handler(
[$this, 'open'],
[$this, 'close'],
[$this, 'read'],
[$this, 'write'],
[$this, 'destroy'],
[$this, 'gc']
);
}
public function open($save_path, $session_id) {
echo 'open called<br/>';
$this->_id = $session_id;
$this->_link = new PDO('pgsql:host=' . $_SERVER['DB_HOST'] . ';dbname=' . $_SERVER['DB_DB'],
$_SERVER['DB_USER'],
$_SERVER['DB_PASS']);
}
public function close() {
echo 'close called<br/>';
}
public function destroy($session_id) {
echo 'destroying '.$session_id, '<br/>';
}
public function gc($maxlifetime) {
echo 'GC called<br/>';
}
public function read($session_name) {
$name = $this->_id.'_'.$session_name;
$sql = 'SELECT session_data FROM sessions WHERE session_name = :name';
if ($rel = $this->_link->prepare($sql)) {
if ($rel->execute([':name' => $name])) {
return $rel->fetch(PDO::FETCH_ASSOC)['session_data'];
} else {
return false;
}
} else {
return false;
}
return '';
}
public function write($session_name, $session_data) {
echo 'Session data: '.$session_data.'<br/>';
$name = $this->_id . '_' . $session_name;
$data = $session_data;
$sql = "SELECT 1 FROM sessions WHERE session_name = :name";
if ($rel = $this->_link->prepare($sql)) {
if ($rel->execute([':name' => $name])) {
if ($rel->rowCount()) {
echo 'Updating...<br/>';
$sql = 'UPDATE sessions SET session_data = :data WHERE session_name = :name';
if ($rel = $this->_link->prepare($sql)) {
if ($rel->execute([':name' => $name, ':data' => $data])) {
echo 'Update success...<br/>';
} else {
echo 'Update failed...<br/>';
var_dump($rel->errorInfo());
}
}
} else {
echo 'Inserting...<br/>';
$sql = 'INSERT INTO sessions (session_name, session_data) ';
$sql .= 'VALUES(:name, :data)';
if ($rel = $this->_link->prepare($sql)) {
if ($rel->execute([':name' => $name, ':data' => $data])) {
echo 'Insert success...<br/>';
} else {
echo 'Insert failed...<br/>';
var_dump($rel->errorInfo());
}
}
}
}
}
}
}
new SessionManagement();
session_start();
$_SESSION['test_var1'] = 'some test data';
session_write_close(); // Making sure writing is finished
echo $_SESSION['test_var1'];
open called
Session data: a:1:{s:9:"test_var1";s:14:"some test data";}
Inserting...
Insert success...
close called
some test data
_g_h8m64bsb7a72dpj56vgojn6f4k3ncdf97leihcqfupg2qtvpbo20
我不确定这是数据库问题还是PHP问题。我现在已经搞砸了几天,并决定是时候问社区了。希望有人能够了解问题所在。
答案 0 :(得分:1)
我认为你必须在Open函数处理程序和类本身之外初始化PDO对象
尝试使用全局值或静态变量访问您的PDO对象。
这是我为我的项目使用MYSQL的实现:
class Core_DB_SessionHandler implements SessionHandlerInterface
{
protected $options = array(); // Options de la session
protected static $db = NULL; // Acceder a la BDD
public function __construct($options, $pdo) {
$this->options = $options;
self::$db = $pdo;
}
public function open($savePath, $sessionName) {
$now = time();
$req = self::$db->prepare("DELETE FROM tbl_sessions WHERE expire < '{1}' ");
$req->execute(array($now));
return TRUE;
}
public function close() {
$this->gc(ini_get('session.gc_maxlifetime'));
}
public function read($id) {
$now = time();
$stmt = self::$db->query("SELECT data FROM tbl_sessions WHERE sid = '$id AND expire < '$now'");
$result = $stmt->fetchColumn();
return $result;
}
public function write($id, $data) {
if (array_key_exists('TIMEOUT', $_SESSION)) {
$newExp = $_SESSION['TIMEOUT'];
}
else {
$newExp = time() + $this->options['time_limiter'];
}
try {
$req = self::$db->prepare('INSERT INTO tbl_sessions (sid, data, expire) VALUES (:sid, :data, :expire)
ON DUPLICATE KEY UPDATE data = :data, expire = :expire');
$vals = array('sid' => $id, 'data' => $data, 'expire' => $newExp);
$req->execute($vals);
return TRUE;
}
catch (PDOException $e) {
throw new Core_Exception(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
}
}
public function destroy($id) {
$stmt = self::$db->prepare("DELETE FROM tbl_sessions WHERE sid = '{1}'");
$stmt->execute(array($id));
//return ($stmt->rowCount() === 1) ? true : false;
return TRUE;
}
public function gc($maxlifetime) {
$now = time();
$req = self::$db->prepare("DELETE FROM tbl_sessions WHERE expire < '{1}' ");
$req->execute(array($now));
return TRUE;
}
}
我按照这样初始化处理程序:
$handler = new Core_DB_SessionHandler($MyOptions, $MyPDO);
if (PHP5) {
if (!session_set_save_handler($handler, TRUE)) {
throw new Core_Exception('Erreur lors de l\'init des sessions !');
}
}
nb:在你的表结构中,不要使用自动增量ID
答案 1 :(得分:0)
好吧,我已经解决了我的问题,但是很难说这个问题是否真的是问题所在。
在read方法中,我更改了以下内容:
return $rel->fetch(PDO::FETCH_ASSOC)['session_data'];
到
$data $rel->fetch(PDO::FETCH_ASSOC)['session_data'];
return $data;
在此之后,会话正在将$session_data
写入数据库而没有任何问题。这一切都很好,但是它并没有解释为什么它首先不起作用。我主要说这是因为在切换语句后,一切都继续工作。同样,我现在无法重现这个问题。所以我很难说这首先是问题所在。
希望这有助于某人。我一直无法找到有关它的更多信息,但它确实显示出来我肯定会在这里添加它。