3

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化されたセッションデータを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();

どんな助けでも大歓迎です。

4

2 に答える 2

2

PHP7に更新するときに同じ問題が発生しました。

アクティブなセッションが必要なため、その警告が表示されsession_decode()、$_SESSION が設定されます。これは必要ありません。Redis に保存するデータをシリアル化解除するだけです。

これは私が見つけた最良の解決策です。このクラスを使用して、セッションを非シリアル化できます。

<?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;

}
于 2016-07-10T22:56:03.130 に答える
0

これを正解として扱うべきかどうかはわかりませんが、うまくいきそうな解決策です。

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

このオプションを使用すると、session_decode が不要になり、write メソッド内で unserialze() に置き換えることができます。

public function write($id, $data) {

    $data = unserialize($data);

    /** do something **/

}

私にとって、これは回避策のように見えます。

于 2016-06-20T03:26:50.060 に答える