PHP使用ltrim、rtrim以及trim处理中文时遇到的“坑”

说坑有点过分,更多的是自己写代码的时候,没有考虑全面,导致自己踩坑了。

案例复现

$source = 'CSDN科技';
$source = rtrim($source, "】");

发现经过rtrim处理的字符串无法入库,检查后发现数据库报错信息:

General error: 1366 Incorrect string value: ‘xxxxxxx’ for column xxxxx

其实看到这个报错,就能立马意识到问题所在:字符串被不正确的截取,导致数据库驱动无法识别为正确的UTF8编码的文本。
而导致这问题的根本原因是rtrim以及一系列的方法是二进制安全的。
我们先把最后一个字符的字节码打印出来:

var_dump(unpack('C*', '技'));
var_dump(unpack('C*', '】'));
//结果如下
array(3) { [1]=> int(230) [2]=> int(138) [3]=> int(128) } //技
array(3) { [1]=> int(227) [2]=> int(128) [3]=> int(145) } //】

其中的端倪:的最后一个字节和的第二个字节相同。
trim方法是二进制安全的,会把当做三个字符去递归处理原始文本,导致的最后一个字节被截取,只剩两个字节,已经不是原来的了,无法识别。
也就是说,只要原始字符串的尾部字节(包括递归处理后)包含在trim的第二个参数内,都会被依次递归处理。
下面这段代码跟我们最开始写的那段没有本质区别。

$source = 'anlige';
$source = rtrim($source, "aeb");

解决方案

封装三个mb开头方法,去处理多字节编码的文本,逻辑比较暴力,代码有待优化。
注意:封装的$char参数是单个字符,有兴趣也可以修改成递归处理多个字符。

if(!function_exists('mb_ltrim')){
    function mb_ltrim($str, $char){
        if(empty($str)) return '';
        while (mb_substr($str, 0, 1) == $char){
            $str = mb_substr($str, 1);
        }
        return $str;
    }
}
if(!function_exists('mb_rtrim')){
    function mb_rtrim($str, $char){
        if(empty($str)) return '';
        while (mb_substr($str, -1, 1) == $char){
            $str = mb_substr($str, 0, -1);
        }
        return $str;
    }
}
if(!function_exists('mb_trim')){
    function mb_trim($str, $char){
        return mb_rtrim(mb_ltrim($str, $char), $char);
    }
}

总结

1、PHP大部分方法都是二进制安全的,因此在使用的时候要注意。
2、并不是二进制安全的方法都会遇到这个问题,主要是trim系列的特殊处理方式:根据第二个参数传递的值,递归处理首尾字符。
3、遇到问题不可怕,能迅速想到问题的来源和解决方案才最重要的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anlige

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值