文档章节

PHP的多字节处理拾遗

立Q
 立Q
发布于 2013/01/05 13:23
字数 667
阅读 80
收藏 1

在处理已一个PHPwind对于敏感词识别错误的问题中,发现了phpWind对于多字节处理存在很大的问题,例如admin\cache.php中如下代码:

<!-- lang: php -->
$query = $db->query("SELECT * FROM pw_wordfb WHERE classid NOT IN ($classid) ORDER BY id");
while (@extract($db->fetch_array($query))) {
	if ($word) {
		$word = trim(preg_quote($word,'/'));
		//$word = preg_replace("/\\\{(\d+)\\\}/", ".{0,\\1}", $word);
		switch ($type) {
			case 1:
				$wordsfb[$word] = $wordreplace;
				break;
			case 2:
				$alarm[$word] = $wordreplace;
				break;
			case 3:
				$replace[$word] = $wordreplace;
				break;
			default:
				$replace[$word] = $wordreplace;
				break;
		}
	}
}

这里对于关键词作了$word = trim(preg_quote($word,'/'));处理,这条语句咋一眼看上去没有什么问题,但是别忘了,preg_quote是为单字节而设计的函数,因此当用他处理多字节串字符串的时候就有可能出错,为什么说有可能呢?那是因为这跟编码有关系,例如,在GBK编码下执行:

<!-- lang: php -->
echo preg_quote('遊行');

他会莫名奇妙的输出運[行,这其实一点也不奇怪,这是因为遊行对应的字节码为DF 5B D0 D0,这其中5B对应相对于ASCII中的编码即为[,也就是说 preg_quote函数把DF 5B(遊)这个整体拆分开来处理了,把的第二个编码当成了单个的ascii码[处理,给他也加上了\反斜杠进行转义,于是原先的编码就变成了DF 5C 5B D0 D0,即運[行

其实仔细考虑下,多字节编码的问题其实是普遍存在的,例如我们常用的str_replace函数,还有spilt函数,这些常用函数其实都是存在多字节处理出错风险的。只是因为大部分情况下不大容易出错,因此我们就忽略这些风险。当然对于多字节的字符串的处理PHP官方库中还是有相对应的mb_api进行处理的,PHP多字节处理函数,但是发现这其中居然没有mb_str_replace()这个函数,这是我最急需的一个函数,在该页的comments中发现了一个宝贝。

<!-- lang: php -->
function mb_str_replace($search, $replace, $subject) {

if(is_array($subject)) {
	$ret = array();
	foreach($subject as $key => $val) {
		$ret[$key] = mb_str_replace($search, $replace, $val);
	}
	return $ret;
}

foreach((array) $search as $key => $s) {
	if($s == '') {
		continue;
	}
	$r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
	$pos = mb_strpos($subject, $s);
	while($pos !== false) {
		$subject = mb_substr($subject, 0, $pos) . $r . mb_substr($subject, $pos + mb_strlen($s));
		$pos = mb_strpos($subject, $s, $pos + mb_strlen($r));
	}
}

return $subject;
}

该函数能比较完美的处理多字节的字符串替换需求。基于此也诞生了多字符串正则转义函数。

<!-- lang: php -->
function mb_preg_quote($subject){
	$search = array('.','\\','+','*','?','[','^',']','$','(',')','{','}','=','!','<','>','|',':','-');
	$replace = array('\.','\\\\','\+','\*','\?','\[','\^','\]','\$','\(','\)','\{','\}','\=','\!','\<','\>','\|','\:','\-');
	return mb_str_replace($search,$replace,$subject);
}

当然,要想多字节字符串处理函数有效,需要确保两点

  1. 安装了mb扩展
  2. mb_internal_encoding()函数 — 设置/获取内部字符编码

© 著作权归作者所有

立Q
粉丝 12
博文 6
码字总数 1595
作品 0
常州
CTO(技术副总裁)
私信 提问
php mbstring扩展库处理中文字符

mbstring(Multibyte String 多字节字符串) 以前处理字符都是通过 substr strlen,但是现在要求精确多国语言并存就意味着多字节,PHP内置的字符串长度函数strlen无法正确处理中文字符串,它得到...

Junn
2012/11/13
826
0
Mac环境PHP踩过的“坑” (一)函数重载

零、问题¶ 在Mac下开发本来很高兴,可是有一个地方把人恶心到了,Apache+ModPHP方式,出现了一个strtoupper('汉字')乱码的问题。。结果一个 strtoupper('法克'); 输出乱码,把我搞了一个下午...

NILYANG
2015/05/07
321
0
CTNetworking源码拾遗

一句话简介:CTNetworking为casa大神针对iOS网络层方案的一个架构实例。 架构详解: 传送门 Github: 传送门 PS: 本拾遗系列文章只专注于代码以及工程层面知识点拾遗,架构层面作者文章已经进行...

AliThink
2016/09/05
0
0
PHP| 开发拾遗 0x01

date: 2018-2-4 17:35:11 title: PHP| 开发拾遗 0x01 记录 PHP 开发中的二三事 提纲: 请使用 const 常量 再说 原生函数 一次「压平」 if 的踩坑记录 简单的「频次限制」, 常见场景比如重复点...

daydaygo
2018/02/04
0
0
解决分割中文时出乱码的方法 mb_substr() or mb_strcut

原因:字符编码的问题,GB2312中文占两个字符,utf-8中文占3个字符,分割的时候要看中文字符是否结束,否则久乱码 解决方法: PHP substr()函数可以 分割文字,但要分割的文字如果包括中文字...

kobe52099
2014/01/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSM初识(三)OSM Data

一 导出数据 将XML格式的OSM数据转换成另一种格式。 二 提取数据 剪切你选择区域内的数据,或者提取出特定区域特定的特征 三 数据格式 OSM文件仅属于OSM,不能用别的软件打开。其中后缀为bz2...

yuankaichao
33分钟前
7
0
Queue

class Queue { constructor() { this._items = []; } enqueue(item) { this._items.push(item); } dequeue() { this._items.shift();......

gtandsn
35分钟前
5
0
数据防泄漏系统有何实用价值?企业文件加密软件哪个好?江苏风奥科技

数据防泄漏系统的发展,减少了国内数据泄露事件的发生,保护了个人信息安全,企业信息安全,保密级数据安全等互联网时代发展的重点关注话题,国内信息化步伐的加快,改变了传统的办公以及发展...

fasoft
35分钟前
7
0
Helm 3 发布 | 云原生生态周报 Vol. 27

作者 | 墨封、元毅、冬岛、敖小剑、衷源 业界要闻 1.Helm 3 发布 美国时间 11 月 13 日,Helm 团队发布 Helm 3 第一个稳定版本。Helm 3 以 Helm 2 的核心特性为基础,改进了 chart 存储库、版...

一肥仔
43分钟前
3
0
Spring Boot2.x 内置Tomcat调优,使用Apr模式

启用Apr模式,需要调用方法 org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#setProtocol windows下安装配置native和apr只需要在环境变量path里能够找到 tcna...

xiaomin0322
49分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部