json_encode序列化空字节 [英] json_encode serialize null bytes
问题描述
我遇到了这个 serialize
gotcha 今天.来自PHP.net doc:
I ran into this serialize
gotcha today. From PHP.net doc:
注意: 对象的私有成员具有该成员的类名 姓名;受保护的成员的成员名称前带有"*".这些 前置值的两边均为空字节.
Note: Object's private members have the class name prepended to the member name; protected members have a '*' prepended to the member name. These prepended values have null bytes on either side.
我正在使用debug_backtrace生成调试报告的跟踪,该跟踪报告获取json_encode
d.在内部,它使用序列化器生成跟踪数据.
I'm using debug_backtrace to generate a trace for a debug report, which gets json_encode
d. Internally it uses the serializer to generate the data for the trace.
这是json_encode
的(部分)输出:
{"\u0000MyObject\u0000my_var":[]}
问题是json_decode
无法处理此问题,它将抱怨空字节.
The problem is that json_decode
can't handle this, it will complain about the null bytes.
因此json_encode
愉快地写入了json_decode
无法解码的空字节.对我来说,这似乎有些不可思议.我希望json_encode
处理必要的转义,或者至少json_decode
可以解析json_encode
产生的任何内容,但这似乎并非如此.
So json_encode
happily writes the null bytes, that json_decode
can't decode. This seems a little wonky to me. I would expect json_encode
takes care of the necessary escaping, or at least that json_decode
can parse anything produced by json_encode
, but this doesn't seem to be the case.
我想我有几种解决方法:
I guess I have several solutions:
- 从跟踪中剥离空字节,我对反序列化对象没有太大兴趣,我只想要一个字符串表示形式.
- 将专用变量从跟踪中剥离出来.
- 修复
json_encode
,使其不会产生空字节 - 修复
json_decode
,使其接受空字节
- Strip the null bytes from the trace, I'm not so much interested in unserializing the object, I just want a string representation.
- Strip private variables all together from the trace.
- Fix
json_encode
so that it doesn't produce null bytes - Fix
json_decode
so that it accepts null bytes
有人遇到这个问题了吗,您如何解决呢?
示例:
<?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
解决方案
因为PHP 5.3
call_user_func_array
在第二次call_user_func_array
的参数不是数组.在那之前,您必须自己检查一下.
Since PHP 5.3
call_user_func_array
will throw a warning when the second parameter ofcall_user_func_array
is not an array. Until then you'll have to check it yourself.
推荐答案
(对不起,这可能不适合作为注释,因为它不能完全回答您的问题,但是对于它来说太长了那个)
我尝试用PHP 5.3和5.2再现您描述的内容,这就是我得到的:
I've tried reproducing what you describe, with both PHP 5.3 and 5.2, and here's what I get :
首先,让我们创建一个具有私有属性的类并实例化它:
First, let's create a class with a private property and instanciate it :
class A {
public $pub = 10;
private $priv = 20;
}
$a = new A();
var_dump($a);
哪个让我:
object(A)[1]
public 'pub' => int 10
private 'priv' => int 20
现在,如果我serialize()
我的对象:
Now, if I serialize()
my object :
$serialized = serialize($a);
var_dump($serialized);
我得到了:
string 'O:1:"A":2:{s:3:"pub";i:10;s:7:"�A�priv";i:20;}' (length=46)
您所描述的几乎是什么:private
属性名称周围有那些null
字节.
Which is pretty much what you describe : there are those null
-bytes arround the private
-property's name.
让我们继续json_encode()
:
And let's continue with json_encode()
:
$jsoned = json_encode($serialized);
var_dump($jsoned);
正如您所说,这给了我一个带有一些\u0000
的字符串:
Which gives me, like you said, a string with some \u0000
:
string '"O:1:\"A\":2:{s:3:\"pub\";i:10;s:7:\"\u0000A\u0000priv\";i:20;}"' (length=64)
现在,如果我尝试json_decode()
此字符串:
Now, if I try to json_decode()
this string :
$unjsoned = json_decode($jsoned);
var_dump($unjsoned);
这就是我得到的:
string 'O:1:"A":2:{s:3:"pub";i:10;s:7:"�A�priv";i:20;}' (length=46)
=>空字节似乎并没有丢失:它们是通过JSON字符串正确创建的.
然后,调用unserialize()
:
And, calling unserialize()
on that :
$unserialized = unserialize($unjsoned);
var_dump($unserialized);
我拿回了我拥有的最初物体:
I get back the initial object I had :
object(A)[2]
public 'pub' => int 10
private 'priv' => int 20
所以,当进行序列化+编码和反编码+反序列化时,我似乎没有重现您的问题.
So, I don't seem to reproduce your problem when serializing+encoding and the de-encoding+unserializing...
我应该补充一点,我都没有找到关于这种错误的任何信息:
I should add that I have not been able to find anything about such a bug, in both :
- php的错误跟踪器
- 以及json扩展名的SVN历史记录.
现在,如果我尝试使用一个更复杂的对象,并使用一个包含私有成员的类,该成员本身就是一个包含私有属性的对象:
Now, if I try with a more complex object, with a class that contains a private member, which is itself an object which contains a private property :
class A {
private $priv;
public function __construct() {
$this->priv = new B();
}
}
class B {
private $b = 10;
}
我得到的行为完全相同:一切正常-在使用与以前完全相同的操作和var_dump()
调用时,这是我得到的输出:
I get exactly the same kind of behavior : everything works just fine -- and here is the output I get, when using exactly the same actions and var_dump()
calls as before :
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
这里,我也无法重现您所描述的问题.
Here too, I cannot reproduce the problem you describe.
还是,如果我尝试这样做:
Still, if I try this :
var_dump(
unserialize(
json_decode('{"\u0000MyObject\u0000my_var":[]}')
)
);
我确实遇到了麻烦:
Fatal error: Cannot access property started with '\0'
但是,考虑一下,如果我尝试将其解码为我自己",我真的看不到你怎么得到这样的JSON字符串...
But, thinking about it, if I try to decode it "myself", I don't really see how you'd have gotten such a JSON string...
您确定其他地方没有问题吗?就像在编码过程中一样?
Are you sure there is not a problem somewhere else ? Like in the encoding process ?
这篇关于json_encode序列化空字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!