json_decode这个函数是json_encode的反函数,一般传递数据的时候为了压缩数据,会将数组格式的数据转换成json格式,用到的函数就是json_encode,然后接收到数据之后再用json_decode转换回数组,这里本来应该不会出现什么问题, 但也有意外,这个意外应该可以说也是自己造成,bom头导致的bug,其实准确来说也不算bug,但就是让你的数据无法正确转换回来;
bom头的产生应该是你的文件在windows下用记事本这些东西编辑过之后的后果,可能无意之间就给这个bug的产生带来了隐患;但是就算出现这个问题也不用慌张, 凡是都有解决的办法;
json_decode($json)之后可能出现返回空,null等结果,这个时候一般都是json格式出问题, 可以用json_last_error()来检查,json_last_error()函数的使用方式就是在json_decode之后添加这个函数, 函数会返回值,返回0说明格式没错, 我遇到的事返回4,说明格式错误,之前用json在线检测工具检测数据,显示是正确的,这两个居然矛盾,让我大惑不解,不过如果知道bom头这个概念立马就应该反应过来, bom头是看不见的, 所以转换的时候前面多了三个字节,当然看不见, 在线检测的时候复制这个数据没有bom头的三个字节,当然也就正确了, 所以立马用$json=substr($json,3);这个函数,去掉头部的三个字节, 转换之后ok了;
问题解决之后感概万千, 因为这个问题我找了两天,本来问题影藏的不深,只是代码不是自己写的, 其次本地环境与服务器环境不一致, 反正诸多原因,一直没想到会是这个问题;最后一步一步排查,锁定这个函数;感觉以后编辑文件一定不能图方便, 一个小错误就直接用记事本大概编辑一下就行了, 很容易出现这个bom头问题;而且自己还不知道;
这里贴出一段代码, 可以去除网站所有文件的bom头信息;
1 <?php
2 if (isset($_GET['dir'])){ //设置文件目录
3 $basedir=$_GET['dir'];
4 }else{
5 $basedir = '.';
6 }
7 $auto = 1;
8 checkdir($basedir);
9 function checkdir($basedir){
10 if ($dh = opendir($basedir)) {
11 while (($file = readdir($dh)) !== false) {
12 if ($file != '.' && $file != '..'){
13 if (!is_dir($basedir."/".$file)) {
14 echo "filename: $basedir/$file ".checkBOM("$basedir/$file")." <br>";
15 }else{
16 $dirname = $basedir."/".$file;
17 checkdir($dirname);
18 }
19 }
20 }
21 closedir($dh);
22 }
23 }
24 function checkBOM ($filename) {
25 global $auto;
26 $contents = file_get_contents($filename);
27 $charset[1] = substr($contents, 0, 1);
28 $charset[2] = substr($contents, 1, 1);
29 $charset[3] = substr($contents, 2, 1);
30 if (ord($charset[1]) == 239 && ord($charset[2]) == 187 && ord($charset[3]) == 191) {
31 if ($auto == 1) {
32 $rest = substr($contents, 3);
33 rewrite ($filename, $rest);
34 return ("<font color=red>BOM found, automatically removed._<a href=http://www.k686.com>http://www.k686.com</a></font>");
35 } else {
36 return ("<font color=red>BOM found.</font>");
37 }
38 }
39 else return ("BOM Not Found.");
40 }
41 function rewrite ($filename, $data) {
42 $filenum = fopen($filename, "w");
43 flock($filenum, LOCK_EX);
44 fwrite($filenum, $data);
45 fclose($filenum);
46 }
这段代码也是网上找来的, 用了觉得还是蛮方便,不过不敢在服务器上用,以免造成位置的别的什么错误;
所以想到一个折中的办法, 现在本地跑了一下,把出现bom的文件全都替换,然后服务器上的问题并没有解决,然后又在转换json的时候添加了一个判断
if(preg_match('/^\xEF\xBB\xBF/',$json))
{
$json=substr($json,3);
}
这样如果检测得到bom头信息去掉就好了;