天天看点

PHP POST获取的JSON使用json_decode返回NULL

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操作封装函数:

<span style="font-size:14px;">function do_post_request($url, $data, $optional_headers = null)
{
	$params = array('http' => array(
			'method' => 'POST',
			'content' => $data
	));
	if ($optional_headers !== null) {
		$params['http']['header'] = $optional_headers;
	}
	$ctx = stream_context_create($params);
	$fp = @fopen($url, 'rb', false, $ctx);
	if (!$fp) {
		throw new Exception("Problem with $url, $php_errormsg");
	}
	$response = @stream_get_contents($fp);
	if ($response === false) {
		throw new Exception("Problem reading data from $url, $php_errormsg");
	}
	return $response;
}</span>
           

(1)发起POST请求:

<span style="font-size:14px;"><span style="font-family:Tahoma;font-size:12px;">$url = 'http://*******/index.php/Home/Interface/createUser';
$data = '{
"subsysid":"ASDF",
"userid":"yangwulang", 
"pwd":"96e79218965eb72c92a549dd5a330112",
"email":"[email protected]",
"nickname":"杨五郎"
}';</span></span>
           

(2)接着,获取POST返回的数据:

<span style="font-size:14px;">$userReg = do_post_request($url, $data);
echo $userReg."<br>";</span>
           

(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字符串值作为变量,长度也打印出来,看看二者是否一致。

<span style="font-size:14px;">$userReg = do_post_request($url, $data);
echo $userReg."<br>";
echo "[1]userReg's length = ".strlen($userReg)."<br>";


$userReg = '{"resultcode":"6","resultdesc":"the userid already exists"}';
echo $userReg."<br>";
echo "[2]userReg's length = ".strlen($userReg)."<br>";</span>
           

打印结果如下:

{"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的子对象。