douyan1970 2016-01-02 07:11
浏览 29

遇到PHP Mysql会话问题

Recently, I have been having a problem with my sessions, and corresponding session variables.

The problem, is that, when I POST sessions1.php, the session variable seems to work, and gets carried over into sessions2.php.

But, when the link to go to sessions3.php is clicked, the session variable doesn't seem to be set, when in sessions3.php. Thus, returning code from the "else" block, within the "if/else" conditional.

Something similar seems to be happening when I use either a database, or /tmp file setup, for storing data.

In the database example, the session is written to the sessions table. However, when I click the link, going from sessions2.php, which takes me to sessions3.php, the session variable doesn't seem to be set. And, when I click the "logout" button, within sessions3.php, the link takes me back to sessions1.php, which is what is supposed to happen. However, when I check the database (or at least refresh the sessions table), the session is not removed, or destroyed, according to what should be happening in line with the SessionHandler class.

Furthermore, still with the database example: when I submit sessions1.php, and am taken to sessions2.php, the right session row is created within the sessions table. However, when I click on the link that takes me to sessions3.php, another row is created, within the sessions table: this time, without any data, in the data column.

On the other hand, in an test without a database, thus, resorting to using the file-system instead: after submitting sessions1.php, the file appears in the /tmp directory. However, on inspection, that file remains empty. Please, also bear in mind that, when using a simple file-system example, the "SessionHandler", and db connection, code is not present within the files.

Any possible solutions?.

I am using PHP7, Apache 2.4, and MySQL 5.6.27. And, I am wondering whether my config settings (php.ini, and/or httpd) may have anything to do with the problem (since, even without a database, the interactions between sessions2.php, and sessions3.php produce somewhat similar results (session variable not set, by the time I get to sessions3.php)).

THE CODE:

sessions1.php(below)

<!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;
        }
    }

}
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 有了解d3和topogram.js库的吗?有偿请教
    • ¥100 任意维数的K均值聚类
    • ¥15 stamps做sbas-insar,时序沉降图怎么画
    • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
    • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
    • ¥15 关于#Java#的问题,如何解决?
    • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
    • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
    • ¥15 cmd cl 0x000007b
    • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line