从一个字符串看出json_encode的有无

2017-09-21  本文已影响0人  舒小贱

今天解决客户现场的一个bug发现了此问题。先直接抛出两个json_encode后的字符串:

$str = '{"detail":{"base_config":{"ping_time":{"value":"60","inherit":"0","global":"0"},"net_env":{"value":"2","inherit":"0","global":"1"},"lib_update":{"value":"2","inherit":"0","global":"1"},"leak_update":{"value":"2","inherit":"0","global":"1"},"net_protocol":{"value":"1.0","inherit":"0","global":"0"}},"sd":{"sd_settings":{"sysfix":{"value":"2","inherit":"0","global":"1"},"compensate":{"value":"0","inherit":"0"},"bd_scan":{"value":"0"},"bd_moniter":{"value":"0"}}},"safe_control_list":{"list":[{"gid":"765","gname":"upanceshi","isactive":"1","time_range":"\u6240\u6709\u65f6\u95f4","time_range_id":"1","policy_tpl":"usb\u901a\u7528","policy_tpl_id":"14","isonline":"3","priority":"1"}]},"client_attribute":{"is_virtual":"0","cvm":""}},"gid":765,"client_type":0,"tpl_id":null,"id":164,"type":0}';

$str1 = '{"id":7,"tpl_id":null,"detail":"{\"dsec_devexclude\":{\"type\":\"set_movedevice_exclude\"},\"dsec_newudisk\":{\"type\":\"set_udisk_auth\",\"auth_stop_flag\":\"0\",\"auth_stop_tips\":\"\",\"auth_read_flag\":\"0\",\"auth_read_tips\":\"\",\"auth_readwrite_flag\":\"0\",\"auth_readwrite_tips\":\"\",\"param\":[{\"device_id\":\"000000000000000000\",\"authtype\":\"3\",\"todate\":\"\",\"pid\":\"\",\"vid\":\"\",\"security_level\":\"1\"}]},\"systeminfo\":{\"independent\":\"1\",\"pcname\":\"\",\"mode\":\"0\"},\"safe_control_list\":{\"list\":[]},\"audit_control_list\":{\"list\":[]}}","create_user":null,"update_user":null,"type":0,"gid":84,"tags":null,"start_ip":null,"end_ip":null,"update_time":"2016-05-31 00:37:11.481749","create_time":"2016-05-31 00:37:11.481749","start_time":"2016-05-31 00:00:00","name":null,"client_type":0}';

你发现了这两个字符串有什么不一样吗,这两个不一样跟json_encode有什么区别吗
你发现了第二个字符串,detail里面的*那些引号前面都有*吗,为什么会这样??因为第二个字符串里面,detail经过了一次单独的json_encode,然后才把整个数组再次json_encode,第二次json_encode的时候,就把第一次json_encode得到的字符串里面的引号前面加上了\。
实例验证:

$de1 = json_decode($str, true);
var_dump($de1["detail"]);
var_dump("111\n");
$de2 = json_decode($de1["detail"], true);
var_dump($de2);

输出结果为:

 ...
    ["is_virtual"]=>
    string(1) "0"
    ["cvm"]=>
    string(0) ""
  }
}
string(4) "111"
PHP Warning:  json_decode() expects parameter 1 to be string, array given in D:\Program Files (x86)\360\skylar6\php\3.php
Warning: json_decode() expects parameter 1 to be string, array given in D:\Program Files (x86)\360\skylar6\php\3.php on l
NULL
D:\Program Files (x86)\360\skylar6\php>

看到没:$str是进过一次json_encode形成的,把$str进行两次json_decode就会出错。
再验证一下$str1:

$de1 = json_decode($str1, true);
var_dump($de1["detail"]);
var_dump("111\n");
$de2 = json_decode($de1["detail"], true);
var_dump($de2);

结果为:

    string(1) "0"
  }
  ["safe_control_list"]=>
  array(1) {
    ["list"]=>
    array(0) {
    }
  }
  ["audit_control_list"]=>
  array(1) {
    ["list"]=>
    array(0) {
    }
  }
}

D:\Program Files (x86)\360\skylar6\php>

没有问题。

问题背景:客户现场多个分组,
(1)绝大部分分组是通过testrunCommand定时任务刷入到redis里面的,刷入逻辑为:
先将$policy["detail"]单独json_encode一次,然后再将整个$policy进行一次json_encode。(此时得到的应该是$str1)
(2)某几个分组是通过另外的接口刷入到redis里面的,刷入逻辑为:直接将整个$policy进行json_encode一次(此时得到的应该是$str)。

以上两种消费者,不同的操作,用的是同一个消费者:消费者先对¥str进行一次json_decode,得到$policy,然后将$policy["detail"]再次json_decode一次。

那么问题来了:
那几个分组进行第一次json_decode后,得到的$policy["detail"]就是一个数组,而不是一个字符串,那么对数组进行json_decode当然会出问题啊。所以bug就这样来了。

其实问题不是很难,但是比较难排查的原因是,消费逻辑是php-cgi异步消费的,并没有记录日志。。。前人埋坑,后人跳。。。

上一篇下一篇

猜你喜欢

热点阅读