2

所以,我试图将会话存储在 mysql 数据库中。一切似乎都很顺利,因为它会将数据写入会话表等。但是,我只是注意到我可以写出会话数据,尽管我的读取方法是空的。因此,如果您查看代码,最终的 echo 语句将写入“值”——即使定义了零逻辑。有任何想法吗?谢谢!

class SessionManagement{

    private $_hostname;
    private $_username;
    private $_password;
    private $_database;
    private $_timeout;

    public function __construct() {
        $CI =& get_instance();
        $CI->load->database();

        $this->_hostname = $CI->db->hostname;
        $this->_username = $CI->db->username;
        $this->_password = $CI->db->password;
        $this->_database = $CI->db->database;       
        $this->_timeout  = 60 * 60 * 10;    
    }

    public function _open()
    {
        return TRUE;
    }

    public function _close()
    {
        return TRUE;
    } 

    public function _read($id)
    {
                mysql_connect($this->_hostname, $this->_username, $this->_password);
    mysql_select_db($this->_database);

    $id = mysql_real_escape_string($id);

    $sql = "SELECT session_data
            FROM   sessions
            WHERE  session_id = '$id'";

    if ($result = mysql_query($sql)) {
        if (mysql_num_rows($result)) {
            $record = mysql_fetch_assoc($result);

            return $record['session_data'];
        }
    }

    return '';  
    }

    public function _write($id, $data)
    {

        mysql_connect($this->_hostname, $this->_username, $this->_password);
        mysql_select_db($this->_database);

        $id = mysql_real_escape_string($id);
        $data = mysql_real_escape_string(base64_encode(serialize(strip_tags($data))));  
        $access = time() + $this->_timeout;

        $sql = "REPLACE INTO session (session_id, session_data, session_expires) VALUES('$id','$data', $access)";

        return mysql_query($sql);
    }
    public function _gc($max)
    {
        return TRUE;
    }

    public function _destroy($id)
    {
        mysql_connect($this->_hostname, $this->_username, $this->_password);
        mysql_select_db($this->_database);

        $id = mysql_real_escape_string($id);

        $sql = "DELETE
                FROM   session
                WHERE  session_id = '$id'";

        return mysql_query($sql);
    }
}

ini_set("session.save_handler", "user");

session_name("test");
session_set_cookie_params(0, '/', '.test.com');

$s = new SessionManagement();

session_set_save_handler(
        array($s, '_open'),
        array($s, '_close'),
        array($s, '_read'),
        array($s, '_write'),
        array($s, '_destroy'),
        array($s, '_gc')
); 

session_start();

$_SESSION['test'] = "value";

ECHO $_SESSION['test'];
4

3 回答 3

4

您正在使用 Codeigniter。它具有将会话存储到已内置数据库中的功能。

只需删除不起作用的代码并改用 Codeigniter 的功能。您只需要配置它。


除此之外,如果你真的想“和你在一起”,你的代码还有很多问题。如果您遵循以下几点,它们很容易被发现:

  1. 阅读会话保存处理程序的每个回调函数。尤其是他们接收的数据和格式(不这样做会导致至少一个错误,该错误能够触发您描述为“不工作”的行为)。
  2. 做错误记录。导致错误的保存处理程序出现问题可能会使它们看不见,因为不再可能输出到浏览器。这需要您将错误记录到文件中。当您使用会话保存处理程序进行故障排除时,这一点非常重要。
  3. 将数据库交互代码移开。这还允许您在数据库交互失败的情况下提供更好的错误信息(不这样做会隐藏至少一个能够导致您描述为“不工作”的行为的错误)。
  4. 删除不需要的代码。我的意思是,它不需要。拥有不需要的代码可能包括导致您在此处遇到的“不工作”场景的错误。因此,您无缘无故地阻碍自己完成工作。一个例子:ini_set("session.save_handler", "user");- 只要您不知道自己在做什么,就不要这样做。PHP 中没有调用预定义的保存处理程序user,您也没有定义那个。

基本上就是这样。所以我可以发现两个真正的错误导致这个,其他步骤是必要的,这样你就可以处理未来的问题:

  1. 确保您始终与同一个数据库表相关。例如,如果您写入 tableMY_SESSIONS并从 table 读取SESSIONS,这将永远不会起作用。
  2. 确保您返回给 PHP 的数据与其期望的数据兼容。例如,如果您将 Base64 编码的数据存储到数据库中并将其返回给 PHP Base64 编码,那么 PHP 无法处理该数据。

从您的代码中看不到的其他潜在问题:

  1. 您拥有的数据库架构不适合您存储在其中的数据(您尚未提供表架构,因此不能说这是否会导致您出现问题)。
  2. 数据库链接标识符可能会更改,因为 codeigniter 本身正在创建数据库连接。这可能会导致潜在的副作用。显式提供数据库连接的链接标识符有助于放松睡眠。
  3. 由于缺少对数据库部分的错误处理,SQL 查询中的错误未被注意到。

示例代码:

ob_start();

session_name("test");
session_set_cookie_params(0, '/', '.test.com');

$s = new SessionManagement();
$s->register();

session_start();

ECHO $_SESSION['test'], "\n"; # value

重构SessionManagement类:

class SessionManagement
{
    private $_timeout;
    private $_db;

    public function __construct() {

        $CI =& get_instance();
        $CI->load->database();

        $this->_db = new LegacyMysqlDatabase(
            $CI->db->hostname, $CI->db->username, $CI->db->password, $CI->db->database
        );

        $this->_timeout = 60 * 60 * 10;
    }

    public function _open() {

        return TRUE;
    }

    public function _close() {

        return TRUE;
    }

    public function _read($session_id) {

        $db         = $this->_db;
        $session_id = $db->escape($session_id);
        $sql        = "SELECT session_data
            FROM   SESSION
            WHERE  session_id = '$session_id'";

        if (!($result = $db->query($sql)) || !$result->getNumberOfRows()) {
            return '';
        }

        $record = $result->fetchAssoc();
        return $record['session_data'];
    }

    public function _write($session_id, $session_data) {

        $db              = $this->_db;
        $session_id      = $db->escape($session_id);
        $session_data    = $db->escape($session_data);
        $session_expires = time() + $this->_timeout;

        $sql = "REPLACE INTO SESSION (session_id,    session_data,    session_expires)
                             VALUES  ('$session_id', '$session_data', $session_expires)";

        return (bool)$db->query($sql); // cast to bool because PHP would cast to int
    }

    public function _gc($max) {

        return TRUE;
    }

    public function _destroy($id) {

        $db         = $this->_db;
        $session_id = $db->escape($id);
        $sql        = "DELETE
                FROM   SESSION
                WHERE  session_id = '$id'";

        return $db->query($sql);
    }

    public function register() {

        $registered = session_set_save_handler(
            array($this, '_open'),
            array($this, '_close'),
            array($this, '_read'),
            array($this, '_write'),
            array($this, '_destroy'),
            array($this, '_gc')
        );
        if (!$registered) {
            throw new Exception('Can not register session savehandler.');
        }
    }
}

带错误处理的数据库交互代码:

class LegacyMysqlDatabase
{
    private $_hostname;
    private $_username;
    private $_password;
    private $_database;

    private $_link;
    private $_initError = false;

    public function __construct($hostname, $username, $password, $database) {

        $this->_hostname = $hostname;
        $this->_username = $username;
        $this->_password = $password;
        $this->_database = $database;
    }

    public function query($sql) {

        $link   = $this->getLink();
        $result = mysql_query($sql, $link);
        if ($result === false) {
            trigger_error(sprintf('Query "%s" failed: #%d: %s', $sql, mysql_errno($link), mysql_error($link)));
            throw new Exception('Failed to query Mysql database.');
        }
        return new LegacyMysqlResult($result);
    }

    public function escape($string) {

        return mysql_real_escape_string($string, $this->getLink());
    }

    private function getLink() {

        if ($this->_initError) {
            throw new Exception('Failed to initialize the database.');
        }

        if ($this->_link === null) {
            $this->_initError = true;
            $result           = mysql_connect($this->_hostname, $this->_username, $this->_password);
            if (!$result) {
                throw new Exception('Can not connect to Mysql database.');
            }
            $this->_link = $result;
            $selected    = mysql_select_db($this->_database, $this->_link);
            if (!$selected) {
                trigger_error(sprintf('Can not select Mysql database "%s": #%d: %s', $this->_database, mysql_errno($result), mysql_error($result)));
                throw new Exception(sprintf('Can not select Mysql database "%"', $this->_database));
            }
            $this->_initError = false;
        }
        return $this->_link;
    }
}

class LegacyMysqlResult
{

    private $_result;

    public function __construct($result) {

        $this->_result = $result;
    }

    public function getNumberOfRows() {

        return mysql_num_rows($this->_result);
    }

    public function fetchAssoc() {

        return mysql_fetch_assoc($this->_result);
    }
}
于 2012-12-27T13:10:10.837 回答
1

实际上 _write 函数处理程序直到输出流关闭后才执行。

因此你$_SESSION['test'] = "value";只是一个数组所以它打印值,

有关此的详细信息在这里

于 2012-12-24T12:11:11.960 回答
-1

我不确定我是否理解你的问题。基本上你的脚本只有三行:

session_start();

$_SESSION['test'] = "value";

ECHO $_SESSION['test'];

会话管理的要点是,只要会话处于活动状态(在大多数浏览器中,直到您关闭浏览器),您就不必将值保存在数据库中。

您创建一个会话,php 将向您的浏览器发送一个会话 cookie,如果接受该 cookie,只要会话处于活动状态,您就可以在任何页面上输出 $_SESSION['test']。

编辑:查看http://php.net/manual/de/function.session-start.php

于 2012-12-21T21:57:37.460 回答