PHP:自定义会话处理程序反序列化不适用于Windows

时间:2015-06-25 12:30:45

标签: php sql-server session deserialization

我的应用程序的开发环境是Zend Framework 1.11,MSSQL Server 2012,SQLSRV扩展,用于与PDO,Windows 7,IIS 7进行数据库连接。会话通过使用自定义会话处理程序类存储在数据库中。

问题在于,当我在bootstrap.php文件中编写的session_start()之后打印$ _SESSION时,它不会显示完整的非序列化会话数据数组。似乎会话数据由会话类处理程序的“读取”方法返回,由于某种原因未被反序列化。这是我的源代码: -

bootstrap.php中

protected function _initSession() {
    $handler = new Mcd_Core_SessionHandler_Database();

    session_set_save_handler(
        array($handler, 'open'),
        array($handler, 'close'),
        array($handler, 'read'),
        array($handler, 'write'),
        array($handler, 'destroy'),
        array($handler, 'gc')
    );        
    session_start();
    echo "<pre>";
    print_r($_SESSION);
}

SessionHandler类

<?php
class My_Core_SessionHandler_Database
{

    protected $dbh;
    protected $ipAddress = '';

    public function __construct() {   
        $this->dbh = My_Core_Config::get_dbinstance();
    }

    public function open($savePath, $sessionId) {
        return true;
    }

    public function close()  {
        return true;
    }

    public function read($sessionId) {                

        $query = "SELECT TOP 1 CAST(session as varchar(max)) as session
            FROM t_php_session
            WHERE php_session_id = '".$sessionId."'
                AND DATEADD(minute, ".My_Core_Config::get_value('session_timeout_period').", created) >= GETDATE()
                AND user_ip = '".$this->ipAddress."'";

        $stmt = $this->dbh->prepare($query);
        $stmt->execute();
        $result = $stmt->fetchColumn();       

        if ($result === false) {
            return '';
        }
        return $result;
    }

    public function write($sessionId, $sessionData) {
        $query = "
            SELECT id
            FROM t_php_session
            WHERE php_session_id = ?
        ";
        $stmt = $this->dbh->prepare($query);
        $stmt->execute(array($sessionId));
        $result = $stmt->fetchColumn();

        if (empty($result)) {            
            $query = "INSERT INTO t_php_session (php_session_id, session, user_ip, created) VALUES (?, CONVERT(VARBINARY(max), ?), ".$this->ipAddress.", GETDATE())";
            $stmt = $this->dbh->prepare($query);            
            $stmt->execute(array($sessionId, $sessionData));
        } else {
            $query = "
                UPDATE t_php_session
                SET session = CONVERT(VARBINARY(max), ?),
                    user_ip = ".$this->ipAddress.",
                    created = GETDATE()
                WHERE id = ?
            ";
            $stmt = $this->dbh->prepare($query);
            $stmt->execute(array($sessionData, $result));
        }
        return true;
    }

    public function destroy($sessionId) {
        $query = 'DELETE FROM t_php_session WHERE php_session_id = ?';
        $stmt = $this->dbh->prepare($query);
        $stmt->execute(array($sessionId));

        return true;
    }

    public function gc($maxlifetime) {
        $query = "
            DELETE FROM t_php_session
            WHERE DATEADD(minute, ".My_Core_Config::get_value('session_timeout_period').", created) < GETDATE()";

        $stmt = $this->dbh->prepare($query);
        $stmt->execute();

        return true;
    }
}

数据库表中会话字段的数据类型为varbinary(max)。我猜这可能是问题,但不确定。

会话处理程序类的 read 方法的输出是:

My_Core_Session|a:1:{s:16:"My_Core_Session";a:4:{s:19:"previous_controller";N;s:15:"previous_action";N;s:18:"current_controller";s:16:"authentification";s:14:"current_action";s:5:"login";}}

Bootstrap.php中$ _SESSION的输出是:

Array
(
    [My_Core_Session] => 
)

输出应该在哪里:

Array
(
    [My_Core_Session] => Array
        (
            [My_Core_Session] => Array
                (
                    [previous_controller] => 
                    [previous_action] => 
                    [current_controller] => authentification
                    [current_action] => login
                )

        )

)

此应用程序在Linux上作为相同的数据库工作正常,正在使用源代码,但具有不同的环境,如Apache 2.2,FreeTDS,Dblib。我们刚刚将此应用程序从Linux迁移到Windows并面临此问题。

1 个答案:

答案 0 :(得分:1)

我找到了解决方案,并希望与可能面临同样问题的人分享。问题是PHP引擎无法deserialize从MSSQL Server数据库获取的会话数据可能是数据带来的一些垃圾。字段的数据类型(保存会话的位置)为varbinary (max)。我只是将其更改为varchar (max)以查看它是否有效并且有效:)

这是一个特定的用例,其中自定义会话处理程序在带有MSSQL Server数据库的zend框架中使用。幸运的是,现在已经解决了:)

祝你好运!!