我今天遇到了这个serialize
gotcha 。来自PHP.net doc:
注意: Object的私有成员具有该成员前面的类名 名称;受保护的成员在成员名称前面加上'*'。这些 前置值在任一侧都有空字节。
我正在使用debug_backtrace为调试报告生成跟踪,获取json_encode
d。在内部,它使用序列化器生成跟踪数据。
这是json_encode
:( / p>)的(部分)输出
{"\u0000MyObject\u0000my_var":[]}
问题是json_decode
无法解决这个问题,它会抱怨空字节。
所以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
解决方案
由于PHP 5.3
call_user_func_array
会在第二次时发出警告call_user_func_array
的参数不是数组。在那之前,你必须自己检查一下。
答案 0 :(得分:7)
(对不起,这可能会更好地作为评论,因为它没有完全回答你的问题 - 但它有点太长了)
我已经尝试用PHP 5.3和5.2来复制你描述的内容,这就是我得到的内容:
首先,让我们创建一个具有私有属性的类并实现它:
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()
我的对象:
$serialized = serialize($a);
var_dump($serialized);
我明白了:
string 'O:1:"A":2:{s:3:"pub";i:10;s:7:"�A�priv";i:20;}' (length=46)
这几乎就是你描述的内容:null
- private
- 属性名称周围有json_encode()
个字节。
让我们继续$jsoned = json_encode($serialized);
var_dump($jsoned);
:
\u0000
这就像你说的那样,给了我一些带有string '"O:1:\"A\":2:{s:3:\"pub\";i:10;s:7:\"\u0000A\u0000priv\";i:20;}"' (length=64)
的字符串:
json_decode()
现在,如果我尝试$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)
这是我得到的:
unserialize()
<强> =&GT;空字节似乎没有丢失:它们是从JSON字符串中正确重新创建的。
并且,在那上面调用$unserialized = unserialize($unjsoned);
var_dump($unserialized);
:
object(A)[2]
public 'pub' => int 10
private 'priv' => int 20
我找回了我的初始对象:
class A {
private $priv;
public function __construct() {
$this->priv = new B();
}
}
class B {
private $b = 10;
}
所以,在序列化+编码和解码+反序列化时,我似乎没有重现你的问题......
我应该补充说,我无法在这两个方面找到任何关于此类错误的内容:
现在,如果我尝试使用更复杂的对象,使用包含私有成员的类,该成员本身就是一个包含私有属性的对象:
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
调用时:
var_dump(
unserialize(
json_decode('{"\u0000MyObject\u0000my_var":[]}')
)
);
在这里,我也无法重现你描述的问题。
但是,如果我试试这个:
Fatal error: Cannot access property started with '\0'
我确实遇到了麻烦:
{{1}}
但是,考虑一下,如果我尝试将其解码为“我自己”,我真的不知道你是如何获得这样的JSON字符串......
你确定其他地方没有问题吗?就像编码过程一样?
答案 1 :(得分:-1)
你可以简单地使用正则表达式从JSON字符串中去掉\ u0000然后如果你解码它就应该没问题。
答案 2 :(得分:-1)
尝试将编码更改为utf8。我假设您从数据库中获取数据
mysql_query('SET CHARACTER SET utf8');
它应该有用。如果它赢了“T”,请在解码对象之前尝试转义空字符
preg_replace('|\\u0000|', ' ', $json);
如果它不起作用,试试这个
<?php
$json = '{"\u0000MyObject\u0000my_var":[]}';
$json = preg_replace('/\\\\u([0-9A-F]{4})/i', '', $json);
$json = json_decode($json);
print_r($json);