CodeIgniter 的 char_set 和 dbcollat 必须显式设为 utf8mb4,否则 emoji 会截断或报错;init_commands 中 SET NAMES utf8mb4 冗余且可能出错;表索引需截断至191字符;my.cnf 的 character-set-server 须同步配置。

CodeIgniter 的 char_set 和 dbcollat 必须显式设为 utf8mb4
CodeIgniter 不会自动从 MySQL 服务端继承 utf8mb4,哪怕 my.cnf 已配好。若只改了数据库和表的字符集,但 $db['default']['char_set'] 仍为 'utf8',PDO 或 mysqli 连接初始化时仍用旧编码握手,emoji 会被截断成 ??? 或触发 Incorrect string value 错误。
必须在 application/config/database.php 中明确设置:
$db['default'] = array(
// ... 其他配置
'char_set' => 'utf8mb4',
'dbcollat' => 'utf8mb4_unicode_ci', // 或 utf8mb4_general_ci
);
-
char_set控制连接层的 client/connection/results 字符集,缺一不可 -
dbcollat影响新字段默认排序规则,也参与 WHERE、ORDER BY 的比较逻辑 - 不要写成
utf8—— MySQL 的utf8实际是utf8mb3,不支持 emoji
连接建立后执行 SET NAMES utf8mb4 是冗余操作
CodeIgniter 在底层已通过 mysqli_set_charset()(mysqli)或 PDO::MYSQL_ATTR_INIT_COMMAND(PDO)完成等效设置,只要 char_set 正确,无需手动加 init 命令。
如果你看到有人在 database.php 里写:
'hostname' => 'localhost', 'username' => 'root', 'password' => '', 'database' => 'test', 'dbdriver' => 'mysqli', 'char_set' => 'utf8mb4', 'dbcollat' => 'utf8mb4_unicode_ci', 'init_commands' => "SET NAMES utf8mb4", // ❌ 不必要,且可能在某些驱动下报错
请删掉 init_commands 行。它不仅多余,还可能在连接复用或长连接场景下引发重复执行警告。
表字段长度与索引限制必须同步调整
utf8mb4 字符最多占 4 字节,而 InnoDB 单列索引最大长度是 767 字节(MySQL 5.7 默认),换算下来只能索引 191 个字符。如果字段定义是 VARCHAR(255) 并直接建索引,会报错 Specified key was too long。
解决方案分两步:
- 修改字段定义:确保建表或 ALTER 时指定
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 建索引时显式截断长度:
INDEX idx_content (content(191)),不能写INDEX (content) - 检查现有表:用
SHOW CREATE TABLE your_table确认字段的COLLATE是否为utf8mb4_*,不是就用ALTER TABLE ... MODIFY COLUMN ...修正
PHP 层不需要对 emoji 做额外编码转换
只要 HTTP 请求头 Content-Type 含 charset=utf-8(现代浏览器默认)、CI 数据库连接正确、表字段支持 utf8mb4,PHP 接收的 $_POST 或 file_get_contents('php://input') 就是合法 UTF-8 字节流,可直存。
常见误区:
- 用
mb_convert_encoding($str, 'UTF-8', 'GBK')强转 —— 没有来源编码混杂时纯属画蛇添足 - 用正则过滤 emoji(如
/[\x{1F600}-\x{1F64F}]/u)再入库 —— 生产环境应交由数据库约束兜底,而非 PHP 层拦截 - 认为需要开启
mbstring.func_overload—— CI 本身不依赖该配置,且 PHP 8+ 已废弃该选项
真正容易被忽略的是:my.cnf 中的 character-set-server 和 collation-server 必须与应用层一致,否则新建库/表会回落到 utf8,后续排查会绕远路。

















