【问题标题】:custom session_handler broken with php7 (session_set_save_handler)php7 破坏了自定义 session_handler (session_set_save_handler)
【发布时间】:2016-06-18 21:14:21
【问题描述】:

更新到 PHP7 后,我的应用程序会话处理出现了一些问题。

这似乎不是什么大问题但是PHP每次都会抛出这个错误:

[18-Jun-2016 20:49:10 UTC] PHP Warning:  session_decode(): Session is not active. You cannot decode session data in /var/www/app/phpsessionredis.php on line 90

session_handler 没什么特别的。它将 JSON 化的 sessiondata 存储到 redis 等。

class phpsessionredis implements \SessionHandlerInterface {


    public function __construct( &$redis ) {

        $this->__rc = $redis;

    }

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

    public function destroy($id) {
        try { $this->__rc->del($id); } 
        catch (\RedisException $e) { return false; }
    }

    public function close() {
        return true;
    }
    public function write($id, $data) {

        session_decode($data); // throws an error

        try{

            $this->__rc->setex( $id, 3600, json_encode($_SESSION) );

        } catch (\RedisException $e) { return false; }

        return true;

    }
    public function read($id) {

        try {

          $r = $this->__rc
          ->multi()
          ->get($id)
          ->expire($id, 3600)
          ->exec();

        } catch (\RedisException $e) { return false; }

        $_SESSION = json_decode( $r[0], true );


        if( isset( $_SESSION ) && ! empty( $_SESSION ) && $_SESSION != null ){

            return session_encode();

        } 

        return ''; 

    }


    public function gc($maxLifetime) {
        return true;
    }


}


$sessionhandler = new phpsessionredis( $redis );
session_set_save_handler($sessionhandler);
ob_start();
session_start();

欢迎任何帮助。

【问题讨论】:

    标签: php session session-set-save-handler


    【解决方案1】:

    我在更新到 PHP7 时遇到了同样的问题。

    您收到该警告是因为 session_decode() 需要一个活动会话,它将填充 $_SESSION。 这不是必需的,您只想将要存储到 Redis 的数据反序列化。

    这是我找到的最佳解决方案。 您可以使用这个class 来反序列化会话。

    <?php
    class Session {
        public static function unserialize($session_data) {
            $method = ini_get("session.serialize_handler");
            switch ($method) {
                case "php":
                    return self::unserialize_php($session_data);
                    break;
                case "php_binary":
                    return self::unserialize_phpbinary($session_data);
                    break;
                default:
                    throw new Exception("Unsupported session.serialize_handler: " . $method . ". Supported: php, php_binary");
            }
        }
    
        private static function unserialize_php($session_data) {
            $return_data = array();
            $offset = 0;
            while ($offset < strlen($session_data)) {
                if (!strstr(substr($session_data, $offset), "|")) {
                    throw new Exception("invalid data, remaining: " . substr($session_data, $offset));
                }
                $pos = strpos($session_data, "|", $offset);
                $num = $pos - $offset;
                $varname = substr($session_data, $offset, $num);
                $offset += $num + 1;
                $data = unserialize(substr($session_data, $offset));
                $return_data[$varname] = $data;
                $offset += strlen(serialize($data));
            }
            return $return_data;
        }
    
        private static function unserialize_phpbinary($session_data) {
            $return_data = array();
            $offset = 0;
            while ($offset < strlen($session_data)) {
                $num = ord($session_data[$offset]);
                $offset += 1;
                $varname = substr($session_data, $offset, $num);
                $offset += $num;
                $data = unserialize(substr($session_data, $offset));
                $return_data[$varname] = $data;
                $offset += strlen(serialize($data));
            }
            return $return_data;
        }
    }
    ?>
    

    您的write() 将是:

    public function write($id, $data) {
    
        $session_data = Session::unserialize($data);
        try{
    
            $this->__rc->setex( $id, 3600, json_encode($session_data) );
    
        } catch (\RedisException $e) { return false; }
    
        return true;
    
    }
    

    【讨论】:

    • 谢谢。 (迟到总比没有好)
    【解决方案2】:

    我不知道这是否应该作为一个正确的答案来处理,但它似乎是一个可行的解决方案。

    ini_set('session.serialize_handler', 'php_serialize');
    

    有了这个选项,我们就不需要 session_decode 并且可以在 write 方法中用 unserialze() 替换它。

    public function write($id, $data) {
    
        $data = unserialize($data);
    
        /** do something **/
    
    }
    

    对我来说,这看起来像是一种解决方法。

    【讨论】:

      猜你喜欢
      • 2019-11-13
      • 2016-03-11
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 2020-07-20
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      相关资源
      最近更新 更多