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

本文讲述了在PHP中使用json_decode解析从POST获取的JSON数据时遇到的NULL问题。经过排查,发现不是字符集、JSON格式或BOM问题,而是POST数据头部存在额外3个无法显示的字节。解决方案是使用substr函数去除这3个字节,从而成功解析JSON。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

[php]  view plain  copy
 print ?
  1. <span style="font-size:14px;">function do_post_request($url$data$optional_headers = null)  
  2. {  
  3.     $params = array('http' => array(  
  4.             'method' => 'POST',  
  5.             'content' => $data  
  6.     ));  
  7.     if ($optional_headers !== null) {  
  8.         $params['http']['header'] = $optional_headers;  
  9.     }  
  10.     $ctx = stream_context_create($params);  
  11.     $fp = @fopen($url'rb', false, $ctx);  
  12.     if (!$fp) {  
  13.         throw new Exception("Problem with $url, $php_errormsg");  
  14.     }  
  15.     $response = @stream_get_contents($fp);  
  16.     if ($response === false) {  
  17.         throw new Exception("Problem reading data from $url, $php_errormsg");  
  18.     }  
  19.     return $response;  
  20. }</span>  

(1)发起POST请求:

[php]  view plain  copy
 print ?
  1. <span style="font-size:14px;"><span style="font-family:Tahoma;font-size:12px;">$url = 'http://*******/index.php/Home/Interface/createUser';  
  2. $data = '{  
  3. "subsysid":"ASDF",  
  4. "userid":"yangwulang",   
  5. "pwd":"96e79218965eb72c92a549dd5a330112",  
  6. "email":"123@163.com",  
  7. "nickname":"杨五郎"  
  8. }';</span></span>  


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

[php]  view plain  copy
 print ?
  1. <span style="font-size:14px;">$userReg = do_post_request($url$data);  
  2. 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字符串值作为变量,长度也打印出来,看看二者是否一致。

[php]  view plain  copy
 print ?
  1. <span style="font-size:14px;">$userReg = do_post_request($url$data);  
  2. echo $userReg."<br>";  
  3. echo "[1]userReg's length = ".strlen($userReg)."<br>";  
  4.   
  5.   
  6. $userReg = '{"resultcode":"6","resultdesc":"the userid already exists"}';  
  7. echo $userReg."<br>";  
  8. 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的子对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值