Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将PHP会话数据保存到数据库而不是文件系统中?_Php_Mysql_Database_Session - Fatal编程技术网

如何将PHP会话数据保存到数据库而不是文件系统中?

如何将PHP会话数据保存到数据库而不是文件系统中?,php,mysql,database,session,Php,Mysql,Database,Session,我有两个网站,一个是TLS,另一个不是,都是为同一个客户,但我需要的网站,以分享彼此(只有彼此)的用户,订单,帐户等共同数据 这通常是通过$\u SESSION数据来完成的,但是我很明显这些不能跨其他站点工作,我发现我可以将会话数据存储在数据库(MySQL)中,而不是文件系统中 我四处挖掘,发现了和这个一样古老但 . 我还发现,它的MySQL略为更新 我已经编写了一个接口类,但它只能部分工作,它将会话数据存储在数据库中,但无法检索。我也用过 我的MySQL(从上面的前几个链接复制): 请注意:

我有两个网站,一个是TLS,另一个不是,都是为同一个客户,但我需要的网站,以分享彼此(只有彼此)的用户,订单,帐户等共同数据

这通常是通过
$\u SESSION
数据来完成的,但是我很明显这些不能跨其他站点工作,我发现我可以将会话数据存储在数据库(MySQL)中,而不是文件系统中

我四处挖掘,发现了和这个一样古老但 . 我还发现,它的MySQL略为更新

我已经编写了一个接口类,但它只能部分工作,它将会话数据存储在数据库中,但无法检索。我也用过

我的MySQL(从上面的前几个链接复制):

请注意: 在我向您展示我的接口类之前,请知道Db connetion使用了我自己定制的接口,而且它本身工作得非常完美

$sessionDBconnectionUrl
包含会话数据库连接详细信息,因为我将会话保存在与主网站内容分离的数据库中

我的接口类(基于以上所有链接)


在几个小时的调试过程中,我发现在众多Google搜索中找到的引用文章以及堆栈溢出答案的重要子集(如和)都提供了无效或过时的信息

在将会话数据保存到数据库时可能导致[严重]问题的事项:

  • 虽然所有联机示例都说明您可以“填充”会话设置保存处理程序,但没有一个示例说明您还必须设置注册关闭功能(“会话写入关闭”)

  • 一些(较旧的)指南引用了过时的SQL数据库结构,因此不应使用。将会话数据保存到数据库所需的数据库结构是:
    id
    /
    access
    /
    数据
    。就这样。正如我在一些“指南”和示例中看到的那样,不需要各种额外的时间戳列

    • 一些较旧的指南也有过时的MySQL语法,如
      DELETE*FROM…
  • 类[在我的问题中生成]必须是
    sessionhandler接口
    。我看到过一些指南(上面提到过),其中给出了
    sessionHandler
    的实现,但这不是一个合适的接口。可能以前版本的PHP有一个稍有不同的方法(可能open返回要读取的行,而另一种方法是只返回
    true
    false

  • 这就是我最初问题的原因:我使用了自定义会话名称(实际上,会话名称的id和会话id是一样的!)根据,这将生成一个128个字符长的会话名称。由于会话名称是需要破解的唯一密钥,因此需要破解该密钥才能破坏会话并用一个较长的名称/id接管会话,因此使用较长的名称/id是一件非常好的事

    • 但是,这导致了一个问题,因为MySQL正在悄悄地将会话id从128个字符减少到32个字符,因此它永远无法在数据库中找到会话数据。这是一个完全沉默的问题(可能是因为我的数据库连接类没有发出此类警告)。但这是一个需要注意的问题。如果您在从数据库检索会话时遇到任何问题,请首先检查完整会话id是否可以存储在提供的字段中
  • 因此,除了这些,还有一些额外的细节需要补充:

    PHP手册页面(链接在上面)显示了一堆不适合类对象的行:

    然而,如果您将其放入类构造函数中,它也可以正常工作:

    class MySessionHandler implements SessionHandlerInterface {
    
        private $database = null;
    
    public function __construct(){
    
        $this->database = new Database(whatever);
    
        // Set handler to overide SESSION
        session_set_save_handler(
            array($this, "open"),
            array($this, "close"),
            array($this, "read"),
            array($this, "write"),
            array($this, "destroy"),
            array($this, "gc")
            );
        register_shutdown_function('session_write_close');
        session_start();
        }
    ...
    }
    
    这意味着,要在输出页面上启动会话,您只需要:

    <?php
    require "path/to/sessionhandler.class.php"; 
    new MySessionHandler();
    
    //Bang session has been setup and started and works
    

    我猜最糟糕的问题是域之间的cookie共享(是的,客户端)…为什么?你能再解释一下吗?这两个网站将使用一个传输页面,因此所有从主站点访问购物网站的人都将通过一个传输页面,该页面在将用户传递到其目标页面之前设置会话数据传输。请看,会话密钥存储在浏览器上的cookie中,以便网站知道它是同一个访问者(每个请求中都会发送cookie),但是它们会被域沙盒。如果
    http://mywebsite.com/
    尝试访问您的
    http://google.com/
    cookies,这是被禁止的,并且存在安全漏洞(有人可能会窃取你的gmail会话)。这就是为什么不会发生这种情况,两个站点都引用存储在数据库中的会话。因此,通过将标识标记从一个站点传递到另一个站点,可以在新会话cookie中检索所有数据。仅供参考:open()未使用$savepath参数会话最初添加到数据库的时间是什么时候?您的
    open
    函数实际上应该只检查是否存在到数据库的有效连接。现在它似乎正在检查数据库中是否已经存在有效会话--如果这是正在创建的新会话,我会这样做ubt它将返回
    true
    @paul查看原始接口实现:公共函数open($savePath,$sessionName){$this->savePath=$savePath;if(!is_dir($this->savePath)){mkdir($this->savePath,0777);}返回true;}@Martin,会话变量在第二页设置为空。我在一个页面中设置会话值,这些值存储到数据库中,但当我在另一个页面上检索它时,它将我注销,并将会话变量设置为空数组,你知道为什么吗?@ZOLDIK
    open
    类只是告诉PHP核心它可以继续尝试从会话读取/写入
    <?php
    require "class.sessionHandler.inc.php";
    $HSH = new HafSessionHandler("connection.session.dbxlink.php");
    session_set_save_handler( $HSH, TRUE );
    session_start();
    
    print "<p>Hello this is an index page</p>";
    $_SESSION['horses'] = "treesx3";
    $_SESSION['tiespan'] = (int)$_SESSION['tiespan']+7;
    
    print "<p>There should be some session data in the database now. <a href='index3.php'>link</a></p>";
    var_dump($_SESSION);
    
    
    exit;
    
    $handler = new MySessionHandler();
    session_set_save_handler($handler, true);
    session_start();
    
    class MySessionHandler implements SessionHandlerInterface {
    
        private $database = null;
    
    public function __construct(){
    
        $this->database = new Database(whatever);
    
        // Set handler to overide SESSION
        session_set_save_handler(
            array($this, "open"),
            array($this, "close"),
            array($this, "read"),
            array($this, "write"),
            array($this, "destroy"),
            array($this, "gc")
            );
        register_shutdown_function('session_write_close');
        session_start();
        }
    ...
    }
    
    <?php
    require "path/to/sessionhandler.class.php"; 
    new MySessionHandler();
    
    //Bang session has been setup and started and works
    
    <?php
    /***
     * Created by PhpStorm.
     ***/
    class MySessionHandler implements SessionHandlerInterface {
        private $database = null;
    
        public function __construct($sessionDBconnectionUrl){
            /***
             * Just setting up my own database connection. Use yours as you need.
             ***/ 
    
                require_once "class.database.include.php";
                $this->database = new DatabaseObject($sessionDBconnectionUrl);
    
            // Set handler to overide SESSION
            session_set_save_handler(
                array($this, "open"),
                array($this, "close"),
                array($this, "read"),
                array($this, "write"),
                array($this, "destroy"),
                array($this, "gc")
            );
            register_shutdown_function('session_write_close');
            session_start();
        }
    
        /**
         * Open
         */
        public function open($savepath, $id){
            // If successful
            $this->database->getSelect("SELECT `data` FROM sessions WHERE id = ? LIMIT 1",$id,TRUE);
            if($this->database->selectRowsFoundCounter() == 1){
                // Return True
                return true;
            }
            // Return False
            return false;
        }
        /**
         * Read
         */
        public function read($id)
        {
            // Set query
            $readRow = $this->database->getSelect('SELECT `data` FROM sessions WHERE id = ? LIMIT 1', $id,TRUE);
            if ($this->database->selectRowsFoundCounter() > 0) {
                return $readRow['data'];
            } else {
                return '';
            }
        }
    
        /**
         * Write
         */
        public function write($id, $data)
        {
            // Create time stamp
            $access = time();
    
            // Set query
            $dataReplace[0] = $id;
            $dataReplace[1] = $access;
            $dataReplace[2] = $data;
            if ($this->database->noReturnQuery('REPLACE INTO sessions(id,access,`data`) VALUES (?, ?, ?)', $dataReplace)) {
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * Destroy
         */
        public function destroy($id)
        {
            // Set query
            if ($this->database->noReturnQuery('DELETE FROM sessions WHERE id = ? LIMIT 1', $id)) {
                return true;
            } else {
    
                return false;
            }
        }
        /**
         * Close
         */
        public function close(){
            // Close the database connection
            if($this->database->dbiLink->close){
                // Return True
                return true;
            }
            // Return False
            return false;
        }
    
        /**
         * Garbage Collection
         */
        public function gc($max)
        {
            // Calculate what is to be deemed old
            $old = time() - $max;
    
            if ($this->database->noReturnQuery('DELETE FROM sessions WHERE access < ?', $old)) {
                return true;
            } else {
                return false;
            }
        }
    
        public function __destruct()
        {
            $this->close();
        }
    
    }