PHP操作数据库时出现乱码是很常见的问题,很多开发者遇到这种情况第一反应是代码写错了,实际上大部分乱码都是字符集配置不一致导致的。下面我们先看一张常见的字符集配置示意图,直观了解各层的字符集关系。

乱码出现的常见原因
乱码本质是数据在存储、传输、读取过程中使用的字符集不一致,常见的不一致场景有这几个:
- PHP连接数据库时没有指定字符集,默认使用了和数据库不一致的编码
- 数据库本身的默认字符集不是utf8或者utf8mb4,和项目需求不匹配
- 数据表的字符集和数据库默认字符集不一致,或者字段单独设置了不同字符集
- HTML页面没有设置正确的字符集,导致读取到的正常数据展示时出现乱码
各层字符集配置调整方法
1. PHP连接层配置
如果是使用mysqli扩展连接MySQL,需要在建立连接后设置字符集,示例代码如下:
<?php
// 数据库连接配置
$host = '127.0.0.1';
$user = 'root';
$pass = '123456';
$dbname = 'test_db';
// 建立mysqli连接
$conn = new mysqli($host, $user, $pass, $dbname);
// 检查连接是否成功
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// 设置连接字符集为utf8mb4,支持更多特殊字符
if (!$conn->set_charset("utf8mb4")) {
die("设置字符集失败: " . $conn->error);
}
echo "数据库连接成功,字符集已设置为utf8mb4";
?>如果使用PDO连接,需要在初始化PDO对象时指定字符集,代码如下:
<?php
$host = '127.0.0.1';
$dbname = 'test_db';
$user = 'root';
$pass = '123456';
try {
// 初始化PDO时指定字符集为utf8mb4
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
// 设置错误模式为异常,方便调试
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "PDO连接成功,字符集已设置为utf8mb4";
} catch (PDOException $e) {
die("连接失败: " . $e->getMessage());
}
?>2. 数据库层配置
可以通过SQL语句修改数据库的默认字符集,避免新建表时默认字符集不一致:
-- 修改已有数据库的默认字符集为utf8mb4 ALTER DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 查看数据库当前的字符集配置 SHOW CREATE DATABASE test_db;
如果是新建数据库,可以直接指定字符集:
-- 新建数据库时指定字符集 CREATE DATABASE IF NOT EXISTS test_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
3. 数据表层配置
修改已有数据表的字符集,同时会转换表中已有数据的编码:
-- 修改数据表的字符集和排序规则 ALTER TABLE user_info CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 查看数据表的字符集配置 SHOW CREATE TABLE user_info;
新建数据表时指定字符集的示例:
-- 新建数据表时指定字符集
CREATE TABLE IF NOT EXISTS user_info (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
intro TEXT
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;4. 页面展示层配置
在HTML页面的<head>标签中添加字符集声明,保证浏览器用正确的编码解析页面内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>数据展示页面</title>
</head>
<body>
<?php
// 这里可以放读取数据库数据的代码
?>
</body>
</html>验证配置是否生效
可以插入一条带中文的数据,再查询出来验证是否正常显示:
<?php
// 假设已经建立了上面的$conn mysqli连接
$sql = "INSERT INTO user_info (username, intro) VALUES ('张三', '这是一条测试中文数据')";
if ($conn->query($sql)) {
echo "数据插入成功<br>";
// 查询刚插入的数据
$select_sql = "SELECT username, intro FROM user_info WHERE username = '张三'";
$result = $conn->query($select_sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
echo "查询到的用户名:" . $row['username'] . "<br>";
echo "查询到的简介:" . $row['intro'];
}
} else {
echo "数据插入失败:" . $conn->error;
}
$conn->close();
?>如果插入和查询的中文都正常显示,说明字符集配置已经全部正确,乱码问题就解决了。如果还是出现乱码,可以按照PHP连接层、数据表层、数据库层、页面层的顺序逐一检查字符集配置,找到不一致的地方调整即可。