MySQL 连接、表存储、PHP 内部编码、页面输出编码**任一环节不一致**即会导致乱码。核心链路:
PHP 脚本 (内部编码) → MySQL 连接 (字符集) → 表/列 (字符集) → 页面输出 (HTTP Header/Content-Type)
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'
skip-character-set-client-handshake = 1 # 强制忽略客户端声明的字符集
重启 MySQL 生效。推荐 utf8mb4(完整支持 Emoji),而非旧 utf8(仅 3 字节)。
PDO (推荐):
$dsn = "mysql:host=localhost;dbname=test;charset=utf8mb4";
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
mysqli:
$mysqli = new mysqli('localhost', $user, $pass, 'test');
$mysqli->set_charset('utf8mb4'); // 必须在查询前调用
旧 mysql_* 函数 (已移除):mysql_set_charset('utf8mb4', $link);
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
已有表转换:ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
<?php
// 脚本开头设置
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
mb_http_input('UTF-8');
mb_regex_encoding('UTF-8');
// 或 php.ini 全局生效
// mbstring.internal_encoding = UTF-8
// mbstring.http_output = UTF-8
?>
<?php
// 必须在任何输出前
header('Content-Type: text/html; charset=utf-8');
?>
<meta charset="utf-8"> <!-- HTML5 简写 -->
config.inc.php:$cfg['DefaultCharset'] = 'utf-8';0xE4B8AD 形式导入后变乱码。utf8mb4?SHOW CREATE TABLE users;SET NAMES utf8mb4 / set_charset?mb_internal_encoding 是否为 UTF-8?Content-Type 是否含 charset=utf-8?<meta charset="utf-8"> 是否存在?| 误区 | 真相 |
|---|---|
用 SET NAMES utf8 就够 | utf8 是 MySQL 别名,实际仅 3 字节,存 Emoji 会截断报错。必须用 utf8mb4。 |
| phpMyAdmin 设置了 DefaultCharset 就行 | phpMyAdmin 只是管理工具,不影响应用程序连接字符集。 |
| 数据库默认 latin1,改表字符集就好 | 需 CONVERT TO CHARACTER SET 重写数据,单纯 ALTER ... CHARSET 只改默认值,现有数据不转换。 |
character-set-server = utf8mb4 + skip-character-set-client-handshake。CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci。charset=utf8mb4。header('Content-Type: ...; charset=utf-8') + mb_internal_encoding('UTF-8')。.gitattributes * text=auto eol=lf。