PHP real_escape_string()过滤Emoji问题:MySQL插入时表情丢失
real_escape_string()过滤并无法存入MySQL的问题 这问题我之前也踩过坑,核心原因真不是real_escape_string()本身的问题,而是MySQL的utf8字符集藏着个历史遗留坑——它其实是**utf8mb3**,最多只能存3字节的Unicode字符,而你用的Emoji(比如\ud83d\ude2e)属于4字节的Unicode补充平面字符,根本不在它的支持范围内。再加上你数据库连接的字符集没配置对,real_escape_string()会把这些“无效”的4字节字符直接过滤掉,最终导致插入后表情凭空消失。
下面是一步步的解决办法:
1. 把数据库、表、列的字符集改成utf8mb4
utf8mb4才是MySQL真正支持完整UTF-8的字符集,能容纳所有Unicode字符(包括4字节的Emoji)。你需要执行以下SQL命令(记得替换成你的数据库、表、列名):
- 修改整个数据库的字符集:
ALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; - 修改目标表的字符集(会自动转换所有列):
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; - 如果只需要修改特定列:
(把ALTER TABLE your_table_name MODIFY COLUMN your_column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;VARCHAR(255)换成你列的实际类型,比如TEXT)
2. 调整数据库连接的字符集设置
这一步绝对不能忘!如果你的数据库连接还是默认的utf8,real_escape_string()依然会把4字节字符当成无效内容过滤。在连接数据库成功后,必须执行以下命令设置连接字符集:
$db->set_charset('utf8mb4');
这样real_escape_string()就会按照utf8mb4的规则来转义字符,不会再过滤Emoji了。
3. 验证效果
现在你再测试插入"Foo bar! \ud83d\ude2e",经过real_escape_string()处理后,Emoji会被正确转义并存入数据库,查询出来也能正常显示。
补充说明
为什么之前用utf8_general_ci不行?因为MySQL的utf8是早年的不完整实现,官方早就推荐用utf8mb4来替代它处理全UTF-8字符。另外,排序规则utf8mb4_general_ci足够应付大部分场景,如果需要更精准的多语言排序,可以换成utf8mb4_unicode_ci。
最后记得修改前备份好数据库,避免意外数据丢失哦!
内容的提问来源于stack exchange,提问作者Mitya

