本文目录导读:

在 PHP 项目中处理 Emoji 表情,主要涉及存储、显示和传输三个环节,由于 Emoji 使用 4 字节的 UTF-8 编码,而传统 MySQL 的 utf8 字符集最多只支持 3 字节,因此处理不当会导致数据丢失或乱码。
以下是针对 PHP + MySQL 项目的完整解决方案:
数据库层面:解决存储问题
这是最核心、最需要优先解决的问题,如果你使用 MySQL,默认的 utf8 字符集(utf8_general_ci 等)不支持 Emoji。
✅ 方案一:升级到 utf8mb4(推荐)
将数据库、数据表、字段的字符集从 utf8 改为 utf8mb4。
-
修改数据库字符集:
ALTER DATABASE your_database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-
修改数据表字符集:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
修改字段字符集(如果只想动某个字段):
ALTER TABLE your_table_name MODIFY your_column_name TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
修改数据库连接字符集(PHP 端):
- PDO:
// 在 DSN 中指定 charset $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass'); - mysqli:
$mysqli = set_charset('utf8mb4'); // 或 mysqli_set_charset($conn, "utf8mb4");
- PDO:
注意: 某些字符(如 💩、🔫)需要 utf8mb4 才能存储,升级前建议先备份数据。
✅ 方案二:使用 BLOB 类型
如果无法更改字符集,可以将存储 Emoji 的字段类型改为 BLOB。BLOB 存储原始字节,不进行字符集检查,因此可以存下任意的二进制数据(包括 Emoji)。
ALTER TABLE your_table_name MODIFY your_column_name BLOB;
缺点: 无法对字段内容进行正常的排序、查找、索引等操作。
❌ 方案三:编码后存储(不推荐)
将 Emoji 转义成类似 😀 或 \u1F600 的形式存入数据库,取出时再解码。
缺点: 编码/解码增加性能开销,代码难以维护,无法直接在数据库工具中看到真实内容,也无法进行全文检索。
PHP 代码层面:处理函数
判断字符串是否包含 Emoji
Emoji 的 UTF-8 编码以特定字节序列开头,可以通过正则判断,但标准 Unicode 范围较复杂,推荐使用 PHP 的 mb_strlen 和 strlen 配合:一个 Emoji 占 4 字节,其 mb_strlen 返回 1,而 strlen 返回 4。
function hasEmoji($string) {
$mb_len = mb_strlen($string, 'UTF-8');
$str_len = strlen($string);
// 如果字节长度大于字符长度,说明存在多字节字符(可能是 Emoji)
// 更精确:检查是否有 4 字节 UTF-8 字符
return preg_match('/[\x{10000}-\x{10FFFF}]/u', $string) === 1;
}
去除 Emoji(如果需要过滤)
使用正则去除所有 Emoji:
function removeEmoji($string) {
// 匹配所有补充平面字符(即 4 字节 UTF-8 字符)
$regex = '/[\x{1F600}-\x{1F64F}' // 表情符号
. '\x{1F300}-\x{1F5FF}' // 杂项符号和 pictographs
. '\x{1F680}-\x{1F6FF}' // 运输和地图符号
. '\x{1F1E0}-\x{1F1FF}' // 区域指示符
. '\x{2600}-\x{26FF}' // 杂项符号
. '\x{2700}-\x{27BF}' // 装饰符号
. '\x{FE00}-\x{FE0F}' // 变体选择器
. '\x{1F900}-\x{1F9FF}' // 补充符号和 pictographs
. '\x{1FA00}-\x{1FA6F}' // 象棋符号等
. '\x{1FA70}-\x{1FAFF}' // 符号和 pictographs 扩展 A
. '\x{200D}' // 零宽度连接符(ZWJ)
. '\x{20E3}' // 组合用围音符
. ']/u';
return preg_replace($regex, '', $string);
}
截取字符串时注意长度
使用 mb_substr 代替 substr,否则会截断 Emoji 导致乱码:
$safe_substr = mb_substr($text, 0, 10, 'UTF-8');
JSON 编码时的 Emoji 处理
PHP 的 json_encode 默认会将 Emoji 转义为 \uXXXX 形式,JSON 中直接包含 UTF-8 Emoji,需要确保 JSON 字符串的编码为 UTF-8,且客户端也能正确解析。
// 输出 JSON 时,Emoji 会以 UTF-8 原始形式存在
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE); // 避免将 Emoji 转义
显示与输出
- HTML 页面: 确保
<meta>标签指定charset="UTF-8",浏览器会自动显示 Emoji。 - 移动端/桌面端: 操作系统自带 Emoji 字体(如 iOS 的 Apple Color Emoji、Android 的 Noto Color Emoji、Windows 的 Segoe UI Emoji),只要以 UTF-8 形式输出,用户端就能正确渲染。
- PDF/图片生成: 需确保使用的字体支持 Emoji,常用免费 Emoji 字体:
Noto Color Emoji、Twemoji Mozilla,使用imagettftext时,需指定支持 Emoji 的字体文件路径。
常见踩坑点
-
数据库连接未设置
utf8mb4
即使数据库、表、字段都是utf8mb4,PHP 连接时声明的字符集是utf8,写入时 MySQL 仍会将 4 字节 Emoji 当作非法字符丢弃。 -
MySQL 版本过低
MySQL 5.5.3 之前不支持utf8mb4,建议使用 MySQL 5.7+ 或 MariaDB 10.2+。 -
mbstring扩展未开启
许多 Emoji 处理函数依赖mb_*系列函数,请确保php.ini中extension=mbstring已启用。 -
正则表达式失效
PHP 在处理 Unicode 属性时,需开启u修饰符(UTF-8 模式),且 PCRE 版本不能太旧,建议 PCRE 版本 >= 8.32。 -
表单提交时数据丢失
检查 HTML 表单的accept-charset是否设为UTF-8,不过现代浏览器默认都是 UTF-8,一般不需要显式设置。
总结推荐方案
| 步骤 | 推荐做法 |
|---|---|
| 数据库存储 | 使用 utf8mb4 字符集(表 + 字段 + 连接) |
| PHP 输入处理 | 直接使用 $_POST 接收,不做额外转义 |
| 字符串操作 | 始终用 mb_* 函数(mb_substr, mb_strlen) |
| JSON 输出 | 加 JSON_UNESCAPED_UNICODE 选项 |
| 显示 | 页面声明 UTF-8,操作系统自带 Emoji 字体 |
只要把数据库和数据库连接的字符集统一为 utf8mb4,90% 的 Emoji 问题都能解决,后续只需在字符串截取、JSON 输出等少数环节稍加注意即可。