• 展开微博窗口
  • QQ:52619941
  • 微信:cnmemory
  • 展开分类目录
  • 还没有账号?

Memory

记一CI框架的$_POST编码问题

最近在做支付回调接口时,碰到一个编码问题,由于第三方支付平台异步通知post方式请求使用的是GBK编码,而我们项目服务端使用UTF-8编码开发,所以在做signature验证时,我们需要将post的数据进行编码转换

iconv("GBK//IGNORE", 'UTF-8', $_POST[$key]);

然而转换的结果竟然和原文并不一致,导致MD5后的签名和第三方通知过来的签名不匹配。于是决定脱离CI框架写一个简单的demo来获取第三方平台通知的数据内容是否正确,发现在原生php下,第三方平台post过来的数据是正常的,而在CI框架下,$_POST获取到数据的汉字编码字符却和原生PHP下$_POST获得的字符不一致。为了解决问题,尝试使用

$data = file_get_contents("php://input");

来获取原始数据,简单的将方法进行封装

function get_input_value() {
    static $content = null;
    if ($content === null) {
        parse_str(file_get_contents("php://input"), $content);
    }
    return $content;
}

function get_input($index) {
    $array = get_input_value();
    if (isset($array[$index])) {
        return $array[$index];
    } else {
        return null;
    }
}

这样通过get_input(‘xxx’)就能获取到post的数据,在CI框架中用这种方法代替$_POST获取post数据后,中文字符竟然被正确编码了。于是决定敲开CI的源码一探究竟。

在CI核心源码中搜索$_POST,果然不出所料的找到了线索,原来CI在加载CI_Input时对$_POST进行了一次编码,约在core/input.php的697行可见

// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
   $str = $this->uni->clean_string($str);
}

继续深入到clean_string函数,在core/Utf8.php文件中可见

public function clean_string($str)
{
   if ($this->is_ascii($str) === FALSE)
   {
      if (MB_ENABLED)
      {
         $str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
      }
      elseif (ICONV_ENABLED)
      {
         $str = @iconv('UTF-8', 'UTF-8//IGNORE', $str);
      }
   }

   return $str;
}

可以看到,当支持iconv时,会使用iconv函数对数据进行编码转换,UTF-8//IGNORE,会将遇到无法转换成UTF8编码的字符忽略。于是出现了$_POST到GBK数据时,字符缺失的现象,导致结果不准确。

故事到这里终于了却一桩心事。

码字很辛苦,转载请注明来自雨林寒舍《记一CI框架的$_POST编码问题》

评论

  1. 廖二虎 #1

    :roll: :!:

    回复
    2017-09-14
  2. 三五 #2

    需要向博主学习的地方还有很多,很多,很多……

    回复
    2017-01-6