PHP自5.2版本开始,原生提供了JSON的封包和解包的函数,PHP的JSON操作对JSON的格式要求比较严格。
参考http://www.phpddt.com/php/json_decode-bom.html一文得知:
json_decode要求的字符串比较严格:
(1)使用UTF-8编码
(2)不能在最后元素有逗号
(3)不能使用单引号
(4)不能有\r,\t,如果有请替换
因此,返回NULL的情况还不少,这个得靠大家写代码的时候多多细心。本文要讲的是我从POST获取的JSON格式的字符串,我确保字符串打印出来,看起来没有任何错误,但是json_decode就是返回NULL。这个奇葩的问题,在网上找了很久,有些网友说是字符集的问题,我测试确认后不是,那到底是什么问题呢?
首先,我发送一个webservice请求:
post操作封装函数:
(1)发起POST请求:
(2)接着,获取POST返回的数据:
(3)打印从POST获取的数据$userReg:
{"resultcode":"6","resultdesc":"the userid already exists"}
(4)调用json_decode()函数解析该JSON字符串:
$regRes = json_decode($userReg);
var_dump($regRes);
var_dump会打印出来其参数的数据类型和值,打印出来的值是NULL
从上面打印出来$userReg的JSON字符串来看,没有任何问题啊,为啥json_decode()解析不了呢?
(1)首先,想到的是,查看到底是什么原因导致的返回值是NULL。PHP提供了json_last_error()和json_last_error_msg()两个函数返回json_decode()函数解析JSON字符串失败的错误代号和错误信息。打印这两个错误信息,获取到:
json_last_error(),打印值为”4“;json_last_error_msg()打印值为”syntax error“。
意思是,错误代号为4,错误信息为”语法错误“。
(2)语法错误,说明肯定JSON字符串中某个部分写错了,怀疑是该JSON字符串格式不对,然后将上面(3)中打印出来的JSON字符串{"resultcode":"6","resultdesc":"the userid already exists"},作为一个字符串变量,直接进行json_decode(),看看是否可以正确解析。
$userReg = '{"resultcode":"6","resultdesc":"the userid already exists"}';
$regRes = json_decode($userReg);
var_dump($regRes);
解析成功!打印结果: object(stdClass)#1 (2) { ["resultcode"]=> string(1) "6" ["resultdesc"]=> string(25) "the userid already exists" }
(3)把POST传过来的JSON字符串,直接进行json_decode失败,但是将其值作为一个变量来解析就成功,难道是字符集的问题?JSON只支持utf8字符集。但是,我的项目工程和该PHP页面都设置的是utf-8编码啊,应该不是字符集问题,但是为了保险起见,我还是在$userReg = do_post_request($url, $data);后面加了一句话,来验证是否是字符集问题:
echo mb_detect_encoding($userReg, array("ASCII","GB2312","GBK","UTF-8"));
打印结果是UTF-8,说明字符集确实没问题。
(4)能想的办法都想了,就是解决不了,网上有些网友说是BOM问题,但是又有网友说UTF-8字符集不存在BOM,总结起来就是从POST获取的字符串会比变量定义的相同字符串多几个字符。这些字符不是空格、换行、TAB之类的,所以看不到,也不占视觉空间,所以,看起来跟不存在一样。真的是这样吗?我们做个验证就知道了。思路是,将从POST获取到的JSON字符串的长度打印出来,同时将JSON字符串值作为变量,长度也打印出来,看看二者是否一致。
打印结果如下:
{"resultcode":"6","resultdesc":"the userid already exists"}
[1]userReg's length = 62
{"resultcode":"6","resultdesc":"the userid already exists"}
[2]userReg's length = 59
从打印结果来看,两个JSON字符串打印出来,视觉上看起来长度确实是一样的。但是打印出来的长度确有差异!从POST获取的JSON字符串长度,要比变量JSON字符串长度多出来3个字符!
这样看起来,从POST获取的JSON字符串不做任何处理的话,确实有问题,由于有些网友说UTF-8不存在BOM问题,所以,此处我也无法确定这三个字符是不是BOM信息,因为我对WEB开发一窍不通啊哈哈。
不过,既然问题找出来了,解决起来就简单了,就是将POST信息头部多出来的无法看到的3个字节给去掉:
$userReg = substr($userReg, 3);
这个问题,对于我这种初学者确实很奇葩,上天无路入地无门的节奏,但是翻阅了网上无数大神的帖子和博客,找出来问题,解决起来也就是一行简单的取子字符串代码的问题。
最后,我个人对WEB开发一窍不通,刚开始学习,但是既然遇到了BOM问题,那么下面援引网上的一段对BOM的介绍,算是扩展知识吧:
DOM:(Document Object Model) 文档对象模型。BOM:(Browser Object Mode) 浏览器对象模型。从上面的对比中,可以很清晰的看出,BOM与DOM的最大区别既是B(Browser)和D(Document)的区别,那Browser和Document有什么差别呢,从下面的一张图上看,DOM的根节点是document。经常编写JavaScript代码,也许你会想到window对象,为啥DOM里面没有window,这就是BOM与DOM的区别了,window是JavaScript的顶端对象之一,它是隶属于浏览器层次的,它独立于文档内容与浏览器之间。
BOM解析:
1. BOM是browser object model的缩写,简称浏览器对象模型
2. BOM提供了独立于内容而与浏览器窗口进行交互的对象
3. 由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对象是window
4. BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性
5. BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C
6. BOM最初是Netscape浏览器标准的一部分BOM结构图window对象是BOM的顶层(核心)对象,所有对象都是通过它延伸出来的,也可以称为window的子对象。