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头信息去掉就好了;