php json 乱码

JSON 是一种轻量级的数据交换格式,完全语言无关,但是采用了类似于C系列语言的约定,更详细的介绍可以参考:  http://json.org

由于将数组/对象 序列化为JSON字符串的时候基本上只支持 UTF-8/ASCII, 而我们现在很多网站出于历史原因或者支持国产的原因,采用了GBK/GB2312编码,这个时候,直接使用json_encode/json_decode的时候就可能会出问题了。

我们从B/S两个方面谈这个问题。

首先从B(Browser)方面来讲,我们使用JSON作为和S(Server)数据交换的格式,无论如何,S返回的JSON字符串都已经是Unicode的了,由于JavaScript内部采用了Unicode 的编码,JavaScript会根据客户端的编码的不同而自动转化编码,JSON的解析也就不成问题了。比如: 返回的数据是

"\u4e2d\u56fd\u4eba"

无论你的页面是GBK,还是UTF-8的,都将可以正确解析为

“中国人"

比较简单的方式是调用Javascript的eval函数:

try{ eval("var ret = " +"\"\u4e2d\u56fd\u4eba\";");} catch(e){}; alert(ret);

再来看看S(Server)端,json_encode/json_decode会假定给定的数据是UTF-8编码的,这儿就有几种思路了:

  1. 将数据转化为UTF-8编码的,然后再调用json_encode, 或者首先json_decode,然后再转化为GBK编码的。
  2. 将数据urlencode,这样所有的数据都是ASCII的了,调用json_encode就没有问题了,json_decode之后也需要 urldecode下。
  3. 自己编写函数将GBK编码直接转换为unicode代码。

其实第一种和第二种都是同样的思路,即将其编码转换为可encode的编码,下面看看上面提到的解决方案的具体代码:

encode之前转换为utf-8,decode之后转回gbk:

function tb_json_encode($value, $options = 0)
{
  return json_encode(tb_json_convert_encoding($value, "GBK", "UTF-8"));
}

function tb_json_decode($str, $assoc = false, $depth = 512)
{
  return tb_json_convert_encoding(json_decode($str, $assoc), "UTF-8", "GBK");
}


function tb_json_convert_encoding($m, $from, $to)
{
  switch(gettype($m)) {
    case 'integer':
    case 'boolean':
    case 'float':
    case 'double':
    case 'NULL':
      return $m;

    case 'string':
      return mb_convert_encoding($m, $to, $from);
    case 'object':
      $vars = array_keys(get_object_vars($m));
      foreach($vars as $key) {
        $m->$key = tb_json_convert_encoding($m->$key, $from ,$to);
      }
      return $m;
    case 'array':
      foreach($m as $k => $v) {
        $m[tb_json_convert_encoding($k, $from, $to)] = tb_json_convert_encoding($v, $from, $to);
      }
      return $m;
    default:
  }
  return $m;
}

encode之前urlencode,decode之后urldecode:

function tb_json_encode(array $value, $options = 0) {

   array_walk_recursive($value,'tb_json_encode');

   return $value;

}

function tb_json_decode($value, $assoc = false, $depth = 512) {

   array_walk_recursive($value,'tb_json_decode');

   return $value;

}

function tb_urlencode(&$value, &$key) {

   $key = urlencode($key);

   $value = urlencode($value);

}

function tb_urldecode(&$value, &$key) {

   $key = urldecode($key);

   $value = urldecode($value);

}

第三种方式,在这儿就不详细介绍了。

 

参考:

  1. http://gggeek.altervista.org/sw/article_20061113.html
  2. http://json.org

 

 

经过测试发现PHP的递归实现是在是太慢了,于是尝试将地一种方案修改成了使用PHP内置的函数, 相比而言要好很多:

function tb_json_encode_ex($value, $options = 0)
{
  array_walk_recursive($value, "tb_json_convert_encoding_g2u");
  return json_encode($value);
}
function tb_json_decode_ex($value, $assoc = true, $depth = 512)
{
  $value = json_decode($value);
  array_walk_recursive($value, "tb_json_convert_encoding_u2g");
  return $value;
}
function tb_json_convert_encoding_g2u(&$value, &$key)
{
  $value = mb_convert_encoding($value, "UTF-8", "GBK");
}
function tb_json_convert_encoding_u2g(&$value, &$key)
{
  $value = mb_convert_encoding($value, "GBK", "UTF-8");
}

事实上,第一种方式有一个优点是和基本的json_decode兼容,而第二种则不行。

第二种方式还可以有好多"变种",比如使用base64_encode/base64_decode 等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值