PHP和Javascript在某些方面总是惊人的相似,可是有时候却让人摸不着头脑。
案例1:Javascript原生支持的json格式,在编码上比PHP体积小,例如
$arr = array(array("name" => "php"));
$json = json_encode($arr);
echo $json;
//会输出[{"name":"php"}]
?>
而在Js中,上面的案例[{"name":"php"}]是可以被任何浏览器识别的,但是Javascript还支持更简单的写法var string = [{name:"php"}];
js可以省略属性名双引号,所以js占用体积小。可是,当我们使用js构造的json字符没有双引号直接传递给php之后,例如:
$json = '[{name:"php"}]';
$brr = json_decode($json, true);
var_dump($brr);
//坑爹的php竟然输出NULL
?>
介于这两种语言的差异,可以使用正则表达式来修正。
$json = '[{name:"php"}]';
$php = preg_replace('/(\w+)\s*:\s*/is', '"$1":', $json);
$crr = json_decode($php, true);
//这样就能正确解析js传入的json了
当然,如果你希望js从php获取的json的key不带双引号以节省传输量,还可以这样:
$arr = array(array("name" => "php"));
$json = json_encode($arr);
$js = preg_replace('/"(\w+)"\s*:\s*/is', '$1:', $json);
echo $js;
//将会输出:[{name:"php"}]
重大更新:如果你的数据非常简单,键值对中没有冒号,单双引号等特殊字符,上面的即可满足,可是一旦出现这些特殊符号,正则匹配将会出错。下面的复杂正则表达式希望可以解决这些问题:
header("content-type:text/html; charset=utf-8");
//变态情况下的数据
$json = '[{ id : \'301\' , pId : 11 ,name:"%u5730%u7403%u6751%2819%29",url:"#",target:"_self",iconSkin:"pIcon03"},{id:"111",pId:"11",name:"PK%289%29",url:"#",target:"_self",iconSkin:"pIcon03"},{id:"1",pId:0,name:"%u9986%u85CF%u5206%u7C7B",url:"javascript:void(0);",target:"_self",open:true,iconSkin:"pIcon01"}]';
$arr = json_decode_fix($json);
var_dump($arr);
//极有可能出现的情况
$json = '[{a:"3:4"},{b:"7:8"}]';
$brr = json_decode_fix($json);
var_dump($brr);
/**
* php解码js版本的json,兼容单引号和不带双引号情况
* @param string $json
* @return array
*/
function json_decode_fix($json)
{
$json = str_replace("',", '",', $json);
// 修复子元素带有'{"
if(($first = strpos($json, "'{\"")) !== false) {
$json = str_replace("'{\"", "'{\\\"", $json);
$last = strpos($json, "}");
$middle = str_replace('":', '\":', substr($json, $first, $last-$first));
$json = substr_replace($json, $middle, $first, $last-$first);
}
$result = json_decode($json, true);
if($result)
{
return $result;
}else{
//不允许以纯数字作为键名或在键名或值处出现冒号,否则可能修复失败
$pattern = '/(\w+\s*):([\s*\"\'|\d*]|true|false)+/is';
$json = preg_replace_callback($pattern, function($matches){
//处理纯数字或布尔值,其冒号之后为true、false、纯数字而非单双引号
$index = strpos($matches[0], ':');
$key = trim($matches[0]);
$last = substr($key, -1);
if($last === '"')
{
if(strpos($key, '""') !== false) {
$key = rtrim($key, '" ').'"';
}else{
$key = rtrim($key, '" ');
}
return '"'.trim(substr($key, 0, $index)).'":'.trim(substr($key, $index+1)).'"';
}else if($last === "'")
{
$key = rtrim($key, "' ");
return '"'.trim(substr($key, 0, $index)).'":"'.trim(substr($key, $index+1), "' ").(substr($key, $index+1) === false ? '' : '"');
}else{
$left = trim(substr($key, 0, $index));
return is_numeric($left) ? $matches[0] : '"'.trim(substr($key, 0, $index)).'":'.substr($key, $index+1);
}
}, $json);
return json_decode($json, true);
}
}
费了九牛二虎之力才编写出这个函数,测试虽然也花了很长时间,但是也不能面面俱到。
以上函数中,针对特殊函数类型如布尔值true和false,整数类型纯数字不带双引号的情况做了兼容。此外,针对值中含有冒号等特殊字符的情况也做了特殊处理。
案例2:PHP使用json_encode会导致中文汉字被编码为unicode,输出到js中虽然可以被识别,但是可读性大大降低。例如
$arr = array(array("word" => "中文"));
$json = json_encode($arr);
echo $json;
//会输出[{"word":"\u4e2d\u6587"}]
这时,通过js返回给浏览器时,中文会以unicode存在,对调试工作带来不便。这里介绍一个自动识别中文且不编码的方法,代码如下:
/**
*@功能:json_encode不编译中文成unicod
*@参数:类型为array,$array是待编码的数组
*@返回:类型为string
*/
function json_encode_cn($array)
{
arrayRecursive($array, 'urlencode', true);
$json = json_encode($array);
return urldecode($json);
}
/**************************************************************
*
* 使用特定function对数组中所有元素做处理
* @param string &$array 要处理的字符串
* @param string $function 要执行的函数
* @return boolean $apply_to_keys_also 是否也应用到key上
* @access public
*
*************************************************************/
function arrayRecursive(&$array, $function, $apply_to_keys_also = false)
{
static $recursive_counter = 0;
if (++$recursive_counter > 1000) {
die('possible deep recursion attack');
}
if(!empty($array))
{
foreach ($array as $key => $value) {
if (is_array($value)) {
arrayRecursive($array[$key], $function, $apply_to_keys_also);
} else {
$array[$key] = $function($value);
}
if ($apply_to_keys_also && is_string($key)) {
$new_key = $function($key);
if ($new_key != $key) {
$array[$new_key] = $array[$key];
unset($array[$key]);
}
}
}
}
$recursive_counter--;
}
案例2可以改为:header("content-type:text/html; charset=utf-8");
$arr = array(array("word" => "中文"));
$json = json_encode_cn($arr);
echo $json;
//会输出[{"word":"中文"}]
调试完成之后,上线的时候将json_encode_cn批量替换为json_encode即可,不替换也应该不会影响使用。
转载随意!带上文章地址吧。