PHP在数据库中保存会话。 Read方法似乎不起作用

时间:2012-12-21 21:31:58

标签: php mysql session

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

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'];

3 个答案:

答案 0 :(得分:4)

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

只需删除不起作用的代码,然后使用Codeigniter的功能。您只需要配置它。


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

  1. 了解会话保存处理程序的每个回调函数。特别是它们接收哪些数据以及采用哪种格式(不这样做会导致至少一个错误能够触发您描述为“不工作”的行为)。
  2. 执行错误记录。导致出现错误的保存处理程序出现问题可能会使它们看不见,因为不再可能输出到浏览器。这要求您将错误记录到文件中。使用会话savehandler进行故障排除时,这非常重要。
  3. 将数据库交互代码移开。这样,您还可以在数据库交互失败时提供更好的错误信息(不这样做会隐藏至少一个错误,导致您描述为“无法正常工作”的行为)。
  4. 删除不需要的代码。我的意思是,这不是必需的。拥有不需要的代码可能包含导致此处“不工作”情况的错误。因此,你无法无缘无故地完成任务。一个例子:ini_set("session.save_handler", "user"); - 只要你不知道你做了什么,就不要这样做。在PHP中没有名为user的预定义savehandler,也没有定义那个。
  5. 基本上就是这样。所以我可以发现导致这种情况的两个真正的错误,其他步骤是必要的,这样你就可以处理未来的问题:

    1. 确保始终与同一数据库表相关。例如,如果您写入表MY_SESSIONS并从表SESSIONS中读取,那么这将永远不会有效。
    2. 确保您提供给PHP的数据与其预期的数据兼容。例如,如果将数据Base64编码存储到数据库并将其返回给PHP Base64编码,则PHP无法对该数据执行任何操作。
    3. 您的代码中无法看到的其他潜在问题:

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

      4. 示例代码:

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

答案 1 :(得分:1)

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

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

有关此问题的详细信息是HERE

答案 2 :(得分:-1)

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

session_start();

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

ECHO $_SESSION['test'];

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

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

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