最近,我的会话和相应的会话变量出现了问题。
问题是,当我发布sessions1.php时,会话变量似乎有效,并被转移到sessions2.php中。
但是,当点击转到sessions3.php的链接时,在sessions3.php中似乎没有设置会话变量。因此,在“if / else”条件内从“else”块返回代码。
当我使用数据库或/ tmp文件设置来存储数据时,似乎发生了类似的事情。
在数据库示例中,会话将写入会话表。但是,当我单击链接时,从sessions2.php开始,这会将我带到sessions3.php,似乎没有设置会话变量。而且,当我点击sessions3.php中的“注销”按钮时,链接会将我带回sessions1.php,这应该是应该发生的事情。但是,当我检查数据库(或至少刷新会话表)时,根据SessionHandler类应该发生的事情,会话不会被删除或销毁。
此外,仍然使用数据库示例:当我提交sessions1.php并将其带到sessions2.php时,会话表中会创建正确的会话行。但是,当我单击指向sessions3.php的链接时,会话表中会创建另一行:这次,数据列中没有任何数据。
另一方面,在没有数据库的测试中,使用文件系统代替:在提交sessions1.php之后,文件出现在/ tmp目录中。但是,在检查时,该文件仍为空。请记住,当使用简单的文件系统示例,“SessionHandler”和数据库连接时,代码不存在于文件中。
任何可能的解决方案?。
我使用的是PHP7,Apache 2.4和MySQL 5.6.27。而且,我想知道我的配置设置(php.ini和/或httpd)是否可能与问题有关(因为,即使没有数据库,sessions2.php和sessions3.php之间的交互也会产生类似的结果(当我到达sessions3.php时,会话变量未设置))。
代码:
sessions1.php(下面)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Session Test</title>
</head>
<body>
<form method="post" action="sessions2.php">
<p>
<label for="name">Enter your first name: </label>
<input type="text" name="name" id="name">
</p>
<p>
<input type="submit" name="submit" value="Submit">
</p>
</form>
</body>
</html>
session2.php (below)
<?php
use SomeNamespace\Sessions\SessionHandler;
require_once('/databases/dbConnect.php');
require_once('/classes/Sessions/SessionHandler.php');
$handler = new SessionHandler($db);
session_set_save_handler($handler);
session_start();
if (isset($_POST['name'])) {
if (!empty($_POST['name'])) {
$_SESSION['name'] = htmlentities($_POST['name']);
} else {
$_SESSION['name'] = 'Nobody Here!';
}
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Session Test</title>
</head>
<body>
<p>Hello, <?php
if (isset($_SESSION['name'])) {
echo $_SESSION['name'];
} else {
echo 'stranger';
}
?>.</p>
<p><a href="sessions3.php">Go to page 3</a></p>
</body>
</html>
session3.php (below)
<?php
use SomeNamespace\Sessions\SessionHandler;
require_once('/databases/dbConnect.php');
require_once('/classes/Sessions/SessionHandler.php');
$handler = new SessionHandler($db);
session_set_save_handler($handler);
session_start();
if (isset($_POST['logout'])) {
$_SESSION = [];
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 86400, $params['path'],
$params['domain'], $params['secure'], $params['httponly']);
session_destroy();
header('Location: sessions1.php');
exit;
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Session Test</title>
</head>
<body>
<p>Hello<?php
if (isset($_SESSION['name'])) {
echo ' again, ' . $_SESSION['name'];
} else {
echo ', Nobody!';
}
?>.</p>
<form method="post" action="<?= $_SERVER['PHP_SELF']; ?>">
<p><input type="submit" name="logout" value="Log Out"></p>
</form>
</body>
</html>
SessionHandler.php (below) The session handler class.
namespace SomeNamespace\Sessions;
class SessionHandler implements \SessionHandlerInterface
{
protected $db;
protected $useTransactions;
protected $expiry;
protected $table_sess = 'sessions';
protected $col_sid = 'sessionID';
protected $col_expiry = 'expiry';
protected $col_data = 'data';
protected $unlockStatements = [];
protected $collectGarbage = false;
public function __construct(\PDO $db, $useTransactions = true)
{
$this->db = $db;
if ($this->db->getAttribute(\PDO::ATTR_ERRMODE) !== \PDO::ERRMODE_EXCEPTION) {
$this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
$this->useTransactions = $useTransactions;
$this->expiry = time() + (int) ini_get('session.gc_maxlifetime');
}
public function open($save_path, $name)
{
return true;
}
public function read($session_id)
{
try {
if ($this->useTransactions) {
$this->db->exec('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
$this->db->beginTransaction();
} else {
$this->unlockStatements[] = $this->getLock($session_id);
}
$sql = "SELECT $this->col_expiry, $this->col_data
FROM $this->table_sess WHERE $this->col_sid = :sessionID";
if ($this->useTransactions) {
$sql .= ' FOR UPDATE';
}
$selectStmt = $this->db->prepare($sql);
$selectStmt->bindParam(':sessionID', $session_id);
$selectStmt->execute();
$results = $selectStmt->fetch(\PDO::FETCH_ASSOC);
if ($results) {
if ($results[$this->col_expiry] < time()) {
return '';
}
return $results[$this->col_data];
}
if ($this->useTransactions) {
$this->initializeRecord($selectStmt);
}
return '';
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollBack();
}
throw $e;
}
}
public function write($session_id, $data)
{
try {
$sql = "INSERT INTO $this->table_sess ($this->col_sid,
$this->col_expiry, $this->col_data)
VALUES (:sessionID, :expiry, :data)
ON DUPLICATE KEY UPDATE
$this->col_expiry = :expiry,
$this->col_data = :data";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':expiry', $this->expiry, \PDO::PARAM_INT);
$stmt->bindParam(':data', $data);
$stmt->bindParam(':sessionID', $session_id);
$stmt->execute();
return true;
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollback();
}
throw $e;
}
}
public function close()
{
if ($this->db->inTransaction()) {
$this->db->commit();
} elseif ($this->unlockStatements) {
while ($unlockStmt = array_shift($this->unlockStatements)) {
$unlockStmt->execute();
}
}
if ($this->collectGarbage) {
$sql = "DELETE FROM $this->table_sess WHERE $this->col_expiry < :time";
$stmt = $this->db->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
$this->collectGarbage = false;
}
return true;
}
public function destroy($session_id)
{
$sql = "DELETE FROM $this->table_sess WHERE $this->col_sid = :sessionID";
try {
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sessionID', $session_id);
$stmt->execute();
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollBack();
}
throw $e;
}
return true;
}
public function gc($maxlifetime)
{
$this->collectGarbage = true;
return true;
}
protected function getLock($session_id)
{
$stmt = $this->db->prepare('SELECT GET_LOCK(:key, 50)');
$stmt->bindValue(':key', $session_id);
$stmt->execute();
$releaseStmt = $this->db->prepare('DO RELEASE_LOCK(:key)');
$releaseStmt->bindValue(':key', $session_id);
return $releaseStmt;
}
protected function initializeRecord(\PDOStatement $selectStmt)
{
try {
$sql = "INSERT INTO $this->table_sess ($this->col_sid, $this->col_expiry, $this->col_data)
VALUES (:sessionID, :expiry, :data)";
$insertStmt = $this->db->prepare($sql);
$insertStmt->bindParam(':sessionID', $session_id);
$insertStmt->bindParam(':expiry', $this->expiry, \PDO::PARAM_INT);
$insertStmt->bindValue(':data', '');
$insertStmt->execute();
return '';
} catch (\PDOException $e) {
if (0 === strpos($e->getCode(), '23')) {
$selectStmt->execute();
$results = $selectStmt->fetch(\PDO::FETCH_ASSOC);
if ($results) {
return $results[$this->col_data];
}
return '';
}
if ($this->db->inTransaction()) {
$this->db->rollback();
}
throw $e;
}
}
}