php中str_replace导致乱码的诡异问题
支付宝内搜索 9155838 即可领现金红包 每天都能领哦
10:19:17
朋友有个站的文章内容有时候会显示乱码,让我给看看。
拿到服务器权限后,我上去一看,php都几百个,觉得有点头大,感觉无从查起,并且我也不想在本地重新布置环境,要下载代码和数据库好麻烦。
就只能在线调试了,改了点东西就可能500了,坑爹的是在php.ini里面打开报错,重启后仍然看不到错误信息,在nginx日志和php日志里面也看不到错误信息,不知服务器配置是怎么设置的,但也不想去研究配置了 -_-||
凭着我三脚猫的功夫经过大半天的排查修改,将近凌晨的时候终于在几十个模块中将问题定位到str_replace函数上面了:
问题出在有一行str_replace是将全角空格替换为半角空格的代码(即下图第9行),将其注释即搞定。
现在将问题现象重新整理重现一下,将无关代码全部剔除,只提取最关键代码,又发现一个新的现象:原文本里面的“场。”经过替换后会变成“常”,这真是有点奇怪,如图:
这时,没出现乱码的原因是我将mb_substr函数删掉了,因为这个时候乱码的问题已经不重要了,一个字变成另一个没替换过的字的问题才更诡异。
经测试任何版本的php都有此奇异现象
简要代码如下(php文件编码为gb2312):
<!DOCTYPE html><html><head><meta charset="gbk" />
<?php
header("Content-type:text/html; charset=gbk");
$arr1='这是心灵博客的一个测试用例,具体请见http://blog.dngz.net/phpstrreplace.htm,今天心灵博客发生了个开心的事,但你不在场。';
$arr1 = textReplace($arr1);
echo $arr1;
function textReplace($str)
{
$str = str_replace(' ','',$str); //屏蔽此行则正常
$str = str_replace('开心','happy',$str);
return $str;
}
php技术大佬帮我看看吧,但愿不是什么php对中文支持不够友好的说法……
2019-11-22 23:00:38 补充:
产生这个问题的原因:
将这几个字的编码转换一下:
场。 常
编码转码后:
%b3%a1 %a1%a3 %a1%a1 %b3%a3
“场”的后半部分和句号的前半部分正好组成全角的%a1%a1被替换为空,然后剩余部分正好组成%b3%a3,正好是“常”的编码。
感谢php大神自由勇给出的解决方法:
我有时连续几个月每天PHP编程10小时,很多时候都在处理这类问题。
这个问题PHP短期内无法处理,因为它是属于全角字符的编码的原因。以前写过7年的ASP程序,ASP、JavaScript就不存在这个问题,它们都是把全角字符认为是一个字符。而PHP在GBK/GB2312下,把全角字符拆分成2个字符,UTF-8编码下,拆分成3个字符。
如果要专项替换这个全角空格,还有一个办法,不使用str_replace,稍微有点复杂,但是这个方法(公式)在项目中会特别常用。
以GB2312编码为例,让循环程序检索整个字符串,进行累加。例如:
$a1是字符串:
<?php
$a1='这是心灵博客的一个测试用 例';
$j=strlen($a1)-1;$c1='';
for ($i=0;$i<=$j;$i++){$a=$a1[$i];if (ord($a)>126){$a=$a.$a1[$i+1];$i++;}
if ($a==' ') $a='';
$c1.=$a;
}
echo $c1;?>
运行结果:这是心灵博客的一个测试用例
完美替换掉了全角空格。
当出现全角字符时,ord的值会大于126时,说明此字符一定是全角汉字,此时$i++会向下跳过一个半角字符。
同理,如果是UTF-8编码,则改为:
if (ord($a)>126){$a=$a.$a1[$i+1].$a1[$i+2];$i+=2;}
更新于:2019-11-22 23:05:04 栏目:网站周边/代码 关键词:php,php代码,str_replace
本站使用「署名 4.0 国际」创作共享协议,可转载、引用,但需署名作者且注明文章出处
出现这个问题,的确是PHP对中文的支持有点不好,PHP的一个bug。这是因为PHP,全角字符是拆成2部分的编码。恰好有2个连续的字,第1个字的后半部分,和第2个字的前半部分,组成了如程序中的“ ”空格这个字符(屏蔽此行则正常)。
测试中,如果把这行改为 $str = str_replace(' ','abc',$str); ,后面的结果是“砤bc”,证实了这一点。
这个暂时没有办法解决,只能把 $str = str_replace(' ','',$str); 这一行删除。这样的话,一般会很少遇到这种bug。
@自由勇
高手,正好验证了我的想法。
刚刚又看了下,将这几个字的编码转换一下:
场。 常
转码后:
%b3%a1%a1%a3%a1%a1%b3%a3
场的后半部分和句号的前半部分正好组成全角的%a1%a1,然后剩余部分正好组成%b3%a3的常。
这样看来,在适当的时候str_replace很有可能导致非常多的异常问题。
这样的问题提给php不知道会不会处理。
@xylx
谢谢!我有时连续几个月每天PHP编程10小时,很多时候都在处理这类问题。
这个问题PHP短期内无法处理,因为它是属于全角字符的编码的原因。以前写过7年的ASP程序,ASP、JavaScript就不存在这个问题,它们都是把全角字符认为是一个字符。而PHP在GBK/GB2312下,把全角字符拆分成2个字符,UTF-8编码下,拆分成3个字符。
如果要专项替换这个全角空格,还有一个办法,不使用str_replace,稍微有点复杂,但是这个方法(公式)在项目中会特别常用。
以GB2312编码为例,让循环程序检索整个字符串,进行累加。例如:
$a1是字符串:
$a1='这是心灵博客的一个测试用 例';
$j=strlen($a1)-1;$c1='';
for ($i=0;$i126){$a=$a.$a1[$i+1];$i++;}
if ($a==' ') $a='';
$c1.=$a;
}
echo $c1;
运行结果:这是心灵博客的一个测试用例
完美替换掉了全角空格。
当出现全角字符时,ord的值会大于126时,说明此字符一定是全角汉字,此时$i++会向下跳过一个半角字符。
同理,如果是UTF-8编码,则改为:
if (ord($a)>126){$a=$a.$a1[$i+1].$a1[$i+2];$i+=2;}
@自由勇
上述程序被过滤掉了:
$a1='这是心灵博客的一个测试用 例';
$j=strlen($a1)-1;$c1='';
for ($i=0;$i126){$a=$a.$a1[$i+1];$i++;}
if ($a==' ') $a='';
$c1.=$a;
}
echo $c1;
运行结果:这是心灵博客的一个测试用例
完美替换掉了全角空格。
当出现全角字符时,ord的值会大于126时,说明此字符一定是全角汉字,此时$i++会向下跳过一个半角字符。
@自由勇
程序中还是有很多字符被过滤掉了,我把程序贴在了这里:
http://www.auiou.com/1.htm
@自由勇
看到了,已保存,谢谢。
或者替换的目的是为了删除文章中每段的2个全角空格,这一行改为双空格,就不会有乱码了:
$str = str_replace(' ','',$str);
这肯定还在哪里埋了坑……
都是高手,我完全看不懂😕。不过,下意识看了下我的静态博客编码设置:“”。应该不会有类似的问题吧?
@执迷不悟
你的博客也折腾得挺好的啊
涨知识了……
不懂技术的我,只能在一旁观看了~~
一些不容易注意到的地方 排查起来麻烦的很~ PS:贵站貌似换域名了?
@龙笑天
十几年都是这个域名没变过
@xylx
0.0 那估计我记错了...
我什么也没看懂,但是还是要留个言!
@猫叔
猫叔叔,我的logo呢? 眼看就快过年了 o(╥﹏╥)o
@xylx
呀呀呀!给忘记了,这咋办。。。。。。。。
除了感觉到复杂以外,啥也看不懂
@云中君
还好我弄的是静态博客,否则只能干瞪眼了
这么长时间没有更新了,我以为。。。
gb2312,感觉一下回到15年前
@石樱灯笼
utf8并不是含着金钥匙出生的吧?编码没有优劣之分吧?不同的情况下用不同的编码是有它的优势的,小范围使用不用共享数据等情况下至少能省空间。
@xylx
“欢迎来到日本”
鸟叔看的满头雾水,囧
看开头就在想,应该是编码的问题。建议统一使用utf8
@灰狼
不关编码的事
我感觉就是对中文的问题。。。emmmm
不过一说到乱码,我第一时间居然会想到编码。emmmmmm
开启报错这个,.ini文件,或者直接在文件头加开启报错呗。也许哪里直接屏蔽了报错。2333
@姜辰
ini里和nginx都修改了,但是还是不显示,挺奇怪的。
@xylx
在php文件头添加一句:error_reporting(E_ALL);
@姜辰
试过哦,没用,他那个服务器安全配置做得太强了,一时找不出来哪里限制了。
精通PHP,羡慕啊
考验技术的时候就是没有搜索引擎的时候是否能解决问题。。牛。有时候感觉就因为有了搜索引擎,很多技能都不想学习了。。。遇到问题,直接搜,有依耐性。
@郑永
哈哈,我喜欢先自己折腾,折腾不出来再去搜索。
能找到问题都是高手
@闲鱼
高手是短时间内找到问题原因,我是瞎猫碰到死耗子,要花很久的时间。
虽然看不懂,但是不明觉厉
编码兼容世纪难题
学习了,这就是每个程序语言的不同处,很多方法处理不一样,虽然是一样的逻辑但是需要不同的方式,各种总有些许差别,又学到一招。
@Sam.Z
php处理中文太弱了
没想到现在还有这么高产、历史这么悠久、人气也很高的个人博客!点个赞
被php的博大精深给吓到了