PHP过滤字符串中4字节utf8字符
抓取第三方接口的时候发现有一些字段无法入库,本来以为是字段长度太大,于是加大了mysql的字段长度,发现还是不行。详细跟进到具体记录时,发现这样的记录存在特殊符号,这样的符号只有在firefox下才能看到占位。但是接口字符确实是utf8编码的,那为何会有非法字符呢?
utf8是变长编码,我们常用的汉字编码是3字节,但是还存在4字节编码的特殊符号,如emoji表情等等。mysql在比较新的版本里添加了utf8mb4编码的支持,但是我们线上数据库依然是5.1的老版本。只能在代码中将特殊字符过滤掉了。
直接从百度百科copy下来这段表格。
Unicode/UCS-4 | bit数 | UTF-8 | byte数 | 备注 |
---|---|---|---|---|
0000 ~007F | 0~7 | 0XXX XXXX | 1 | |
0080 ~07FF | 8~11 | 110X XXXX10XX XXXX | 2 | |
0800 ~FFFF | 12~16 | 1110XXXX10XX XXXX10XX XXXX | 3 | 基本定义范围:0~FFFF |
1 0000 ~1F FFFF | 17~21 | 1111 0XXX10XX XXXX10XX XXXX10XX XXXX | 4 | Unicode6.1定义范围:0~10 FFFF |
20 0000 ~3FF FFFF | 22~26 | 1111 10XX10XX XXXX10XX XXXX10XX XXXX10XX XXXX | 5 | 说明:此非unicode编码范围,属于UCS-4 编码早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中 |
400 0000 ~7FFF FFFF | 27~31 | 1111 110X10XX XXXX10XX XXXX10XX XXXX10XX XXXX10XX XXXX | 6 |
可以看到1-3字节的utf8编码字符,对应的unicode编码范围是0~FFFF
,而1-4字节的utf8编码字符,对应的unicode编码范围是0~10 FFFF
。那么显而易见,4字节编码的utf8字符,对应unicode范围是10000~10FFFF
。
所以我们在代码中使用preg_replace
直接将4字节字符过滤掉即可。
//这里/u的修饰符表示使用unicode编码
$str = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $str);
之后就可以成功入库了。