【问题标题】:How can I unserialize session data to an arbitrary variable in PHP?如何将会话数据反序列化为 PHP 中的任意变量?
【发布时间】:2010-10-06 13:21:29
【问题描述】:

我想将session_encode()'d 的会话数据字符串反序列化到我自己的数组(即不是$_SESSION。)

似乎没有处理此问题的内置函数。有session_decode(),但它直接写入$_SESSION 超级全局。有 unserialize(),但它在 session_encode()'d 字符串上返回 false,因为它们的格式略有不同。

最好的方法是什么?

【问题讨论】:

    标签: php session serialization


    【解决方案1】:

    我注意到手动解码会话的已发布解决方案(在 php.net 上)并不完美,因此我提供了一个更强大的解决方案。

    preg_match 解决方案永远无法工作。找到一个可能会破坏反序列化的案例并不难。 在 jason-joeymail 的情况下中断:

    $_SESSION["test"] = ";oops|";
    

    您可以在下面找到我的解决方案。它不使用正则表达式,而是序列化操作的可逆性和序列化的“功能”在它认为完成时会忽略所有进一步的输入。这绝不是一个漂亮或特别快速的解决方案,但它是一个更强大的解决方案。 我为“php”和“php_binary”添加了一个反序列化器。为“wddx”添加一个应该很简单。

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

    用法:

    Session::unserialize(session_encode());
    

    【讨论】:

    • +1 代码有点丑,但这是对我有用的,其他解决方法没有。
    • 这对于任何想从命令行解析会话数据的人来说都很有用,因为session_decode 仅在您有一个打开的会话时才有效。
    • 与以下比较的任何基准? $cur = session_encode(); session_decode($encoded_data); /* encoded data put into $_SESSION */ session_decode($cur); /* current $_SESSION restored */
    • @Halycon 你有这个反序列化代码的序列化方法吗?
    【解决方案2】:

    查看 PHP 手册的 session_decode 页面中的 cmets。它有一堆用户函数来处理手动解码session_encode 字符串。据我所知,这是唯一的出路。

    【讨论】:

    • 我使用了该手册页上的第一个答案。我已经编辑了我的帖子以包含指向该答案的直接链接。
    • 我注意到发布的解决方案 php.net 存在严重缺陷。我贡献了自己的解决方案,避免使用正则表达式。我也会在这里发布。
    • 手动读取会话文件数据的重点是不启动与其关联的会话,这在 SSE 的情况下会在 Blink/Chrome 中产生延迟错误。
    【解决方案3】:

    上面的自定义“php”反序列化函数可以通过避免“增量偏移”方法来简化,有利于逐渐消耗输入会话字符串。

    我没有检查它在速度方面的比较,但它肯定更整洁(并且在 while 循环中保存了对 strlen 的重复调用)

    $r = array();
    while ($i = strpos($str, '|'))
    {
        $k = substr($str, 0, $i);
        $v = unserialize(substr($str, 1 + $i));
        $str = substr($str, 1 + $i + strlen(serialize($v)));
        $r[$k] = $v;
    }
    return $r; // session data are now in a normal array
    

    【讨论】:

    • @Michael Szyndel:我的回答特别提到了上面的“php”处理程序,因为这是“case”语句中的一个特定值。通过不必要地编辑我的帖子来启动“PHP 反序列化..”这个细节已丢失。
    【解决方案4】:

    根据http://php.net/manual/session.configuration.php#ini.session.serialize-handler可以设置

    session.serialize_handler = php_serialize
    

    然后就可以使用php的serialize()/unserialize()函数了。

    【讨论】:

      【解决方案5】:

      这对我有用:

      /* storre current session */
      $current_session = session_encode(); 
      
      /* extract $other_user_session from file or database,
         into the $_SESSION global variable */
      session_decode($other_user_session); 
      
      /* use the other user session data:  $something = $_SESSION['something']; */
      
      /* restore previous sesison info */
      session_decode($current_session); /* current $_SESSION restored */
      

      【讨论】:

      • 我喜欢这个答案,因为它不会尝试解析那么容易破坏的东西(有点像人们寻找正则表达式来解析 HTML 时 - 永远不会结束!)。我唯一(可能是不合理的)担心是将$_SESSION 变量设置为另一个用户的变量。我不明白为什么会出现问题,但这让我很紧张:v。不过,这是我在这里看到的最好的解决方案。又快又脏!
      • 同样,手动读取会话文件的目的是不启动会话
      【解决方案6】:
      function data_session_decode($data){
          $data = array_filter(explode(';',$data));
          $list_data = array();
          foreach($data as $key => $dat){
              if(!empty($dat)){
                $data[$key] = array_filter(explode('|',$dat));
                if(substr($data[$key][1], 0, 1) == 'i'){
                    $list_data[$data[$key][0]] = strstr($data[$key][1], ':');
                    $list_data[$data[$key][0]] = substr($list_data[$data[$key][0]], 1);
                }elseif(substr($data[$key][1], 0, 1) == 's'){
                    $list_data[$data[$key][0]] = strstr($data[$key][1], '"');
                    $list_data[$data[$key][0]] = substr($list_data[$data[$key][0]], 0, -1);
                    $list_data[$data[$key][0]] = substr($list_data[$data[$key][0]], 1);
                }else{
                    unset($data[$key]);
                }
              }
          }
          unset($data);
          return $list_data;
      }
      

      // 这里的数据会话 EX:

      $dataSession = 'user_name|s:8:"你的名字";日期|i:1459396063';

      //输出

      print_r($this->data_session_decode($dataSession));

      【讨论】:

        【解决方案7】:

        你为什么不做这样的事情?

        $myVariable = serialize($_SESSION);
        $sessionCopy = unserialize($myVariable);
        

        祝你好运!

        【讨论】:

        • 因为会话以不同的格式序列化以序列化/反序列化()
        • 嗯,是的,但是您可以将 session.serialize_handler 设置为 php_serialize。详情见php.net/manual/…
        猜你喜欢
        • 1970-01-01
        • 2015-12-09
        • 1970-01-01
        • 1970-01-01
        • 2013-10-05
        • 1970-01-01
        • 2015-06-19
        • 2012-02-09
        • 1970-01-01
        相关资源
        最近更新 更多