json_encode序列化空字节

Hal*_*yon 6 php json

我今天碰到了这个问题.来自PHP.net doc:serialize

注意: Object的私有成员的类名前置于成员名称; 受保护的成员在成员名称前面加上'*'.这些前置值在任一侧都有空字节.

我正在使用debug_backtrace为调试报告生成跟踪,该报告得到json_encoded.在内部,它使用序列化器生成跟踪数据.

这是:(部分)输出json_encode:

{"\u0000MyObject\u0000my_var":[]}
Run Code Online (Sandbox Code Playgroud)

问题是json_decode无法处理这个问题,它会抱怨null字节.

json_encode高兴写出json_decode无法解码的空字节.这对我来说似乎有点不稳定.我希望能够json_encode处理必要的转义,或者至少json_decode可以解析由json_encode它产生的任何东西,但事实并非如此.

我想我有几个解决方案:

  • 从跟踪中删除空字节,我对反序列化不太感兴趣,我只想要一个字符串表示.
  • 从跟踪中一起剥离私有变量.
  • 修复,json_encode以便它不会产生空字节
  • 修复json_decode,使其接受空字节

有没有人遇到这个问题,你是如何解决它的?


样品:

<?php
class MyClass {
    public $mypublic = 1;
    private $myprivate = 2;
    public function myfunc() {
        return debug_backtrace();
    }
}
$c = new MyClass();
$json = json_encode(call_user_func_array(array($c, "myfunc"), new MyClass()));
echo $json;
echo json_decode($json); // <-- Fatal error: Cannot access property started with '\0' in test.php on line 12
Run Code Online (Sandbox Code Playgroud)

因为call_user_func_array当第二个参数call_user_func_array不是数组时,PHP 5.3 会抛出警告.在那之前你必须自己检查一下.

Pas*_*TIN 7

(对不起,这可能会更好地作为评论,因为它没有完全回答你的问题 - 但它有点太长了)


我尝试用PHP 5.3和5.2来复制你描述的内容,这就是我得到的内容:

首先,让我们创建一个具有私有属性的类并实现它:

class A {
    public $pub = 10;
    private $priv = 20;
}

$a = new A();
var_dump($a);
Run Code Online (Sandbox Code Playgroud)

哪个让我:

object(A)[1]
  public 'pub' => int 10
  private 'priv' => int 20
Run Code Online (Sandbox Code Playgroud)


现在,如果我是serialize()我的对象:

$serialized = serialize($a);
var_dump($serialized);
Run Code Online (Sandbox Code Playgroud)

我明白了:

string 'O:1:"A":2:{s:3:"pub";i:10;s:7:"?A?priv";i:20;}' (length=46)
Run Code Online (Sandbox Code Playgroud)

这几乎就是你描述的内容:-property的名字null周围有那些字节private.


让我们继续json_encode():

$jsoned = json_encode($serialized);
var_dump($jsoned);
Run Code Online (Sandbox Code Playgroud)

就像你说的那样,这给了我一些字符串\u0000:

string '"O:1:\"A\":2:{s:3:\"pub\";i:10;s:7:\"\u0000A\u0000priv\";i:20;}"' (length=64)
Run Code Online (Sandbox Code Playgroud)


现在,如果我尝试json_decode()这个字符串:

$unjsoned = json_decode($jsoned);
var_dump($unjsoned);
Run Code Online (Sandbox Code Playgroud)

这是我得到的:

string 'O:1:"A":2:{s:3:"pub";i:10;s:7:"?A?priv";i:20;}' (length=46)
Run Code Online (Sandbox Code Playgroud)

=>空字节似乎没有丢失:它们是从JSON字符串中正确地重新创建的.


并呼吁unserialize():

$unserialized = unserialize($unjsoned);
var_dump($unserialized);
Run Code Online (Sandbox Code Playgroud)

我找回了我的初始对象:

object(A)[2]
  public 'pub' => int 10
  private 'priv' => int 20
Run Code Online (Sandbox Code Playgroud)

因此,在序列化+编码和解码+反序列化时,我似乎没有重现您的问题...

我应该补充一点,我无法在这两个方面找到任何关于这种错误的信息:

  • php的bug追踪器,
  • 和json扩展的SVN历史.



现在,如果我尝试使用更复杂的对象,使用包含私有成员的类,该成员本身就是一个包含私有属性的对象:

class A {
    private $priv;
    public function __construct() {
        $this->priv = new B();
    }
}

class B {
    private $b = 10;
}
Run Code Online (Sandbox Code Playgroud)


我得到完全相同的行为:一切正常 - 这是我得到的输出,当使用var_dump()与以前完全相同的动作和调用时:

object(A)[1]
  private 'priv' => 
    object(B)[2]
      private 'b' => int 10

string 'O:1:"A":1:{s:7:"?A?priv";O:1:"B":1:{s:4:"?B?b";i:10;}}' (length=54)

string '"O:1:\"A\":1:{s:7:\"\u0000A\u0000priv\";O:1:\"B\":1:{s:4:\"\u0000B\u0000b\";i:10;}}"' (length=84)

string 'O:1:"A":1:{s:7:"?A?priv";O:1:"B":1:{s:4:"?B?b";i:10;}}' (length=54)

object(A)[3]
  private 'priv' => 
    object(B)[4]
      private 'b' => int 10
Run Code Online (Sandbox Code Playgroud)

在这里,我无法重现你描述的问题.



如果我试试这个:

var_dump( 
    unserialize( 
        json_decode('{"\u0000MyObject\u0000my_var":[]}')
    )
);
Run Code Online (Sandbox Code Playgroud)

我确实遇到了麻烦:

Fatal error: Cannot access property started with '\0'
Run Code Online (Sandbox Code Playgroud)

但是,考虑一下,如果我尝试解码它"我自己",我真的不知道你是如何获得这样的JSON字符串的......

你确定其他地方没有问题吗?喜欢在编码过程中?