Hyperf项目需三重utf8mb4配置:PDO连接层设SET NAMES utf8mb4、MySQL服务端配置character-set-server=utf8mb4且skip-character-set-client-handshake=OFF、建表字段显式声明COLLATE utf8mb4_unicode_ci,缺一不可。

Hyperf项目中MySQL连接没设utf8mb4,Emoji写入直接报错
Hyperf默认用PDO连接MySQL,但PDO不会自动声明连接字符集,哪怕数据库、表、字段全设成utf8mb4,只要连接层还是utf8,就会触发Incorrect string value: '\xF0\x9F\x98\x80'这类错误。
必须在PDO初始化时显式执行SET NAMES utf8mb4,不能依赖服务端配置兜底。Hyperf的config/autoload/db.php里要加这个选项:
'driver_options' => [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci',
],
漏掉这行,哪怕my.cnf里character-set-server=utf8mb4配得再全也没用——Hyperf启动后建立的每个连接都默认按服务端character_set_client走,而它常是latin1或utf8。
Hyperf部署时MySQL服务端配置被忽略
很多团队只改了Hyperf配置,却没碰MySQL服务端,结果本地能存Emoji,上生产就崩。关键变量有三个,缺一不可:
character-set-server = utf8mb4collation-server = utf8mb4_unicode_ci-
skip-character-set-client-handshake = OFF(或显式设为FALSE,防止客户端“自作主张”)
配置文件路径通常是/etc/mysql/mysql.conf.d/mysqld.cnf或/etc/my.cnf,改完必须重启mysqld,用mysql -e "SHOW VARIABLES LIKE 'character\_set%';"确认生效。特别注意:skip-character-set-client-handshake如果为ON,客户端传什么编码,MySQL就信什么,完全绕过服务端配置。
Hyperf迁移脚本里字段没指定collation,Emoji查出来变问号
即使数据库和连接都对了,字段级字符集不明确,仍会静默降级。Hyperf用Phinx或DB::statement()建表时,必须显式声明COLLATE utf8mb4_unicode_ci,不能只靠表默认值。
比如这样写不行:
ALTER TABLE users MODIFY nickname VARCHAR(255) CHARACTER SET utf8mb4;
得补上排序规则:
ALTER TABLE users MODIFY nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
TEXT类型字段更要注意:InnoDB索引限制是767字节,utf8mb4下VARCHAR(255)索引长度只有191字符(因为4字节/字符),所以如果字段要建索引,得同步调小长度,否则CREATE INDEX会失败。
Hyperf日志或Redis缓存里Emoji显示异常
Emoji存储成功不代表展示没问题。Hyperf默认日志输出可能用file_put_contents写文件,若PHP运行环境locale不是en_US.UTF-8或zh_CN.UTF-8,日志里emoji会变成???;Redis缓存如果用serialize()存数组,PHP序列化本身不损坏数据,但用redis-cli命令行看时,终端编码不对也会显示乱码。
检查点有三个:
- PHP进程启动时的
LANG环境变量是否含UTF-8 - Hyperf日志驱动是否强制指定了
encoding(如StreamHandler可设useLocking但不控制编码) - Redis客户端是否开启
redis.string_response(某些旧版扩展会把二进制响应转成字符串丢失高位字节)
最稳妥的做法:所有涉及输出emoji的地方,用mb_convert_encoding($str, 'UTF-8', 'auto')兜底,别信环境默认值。


















