PHP8.1+MySQL8.0页面显示’而非撇号的字符乱码问题
字符编码显示异常问题:
’替代’的排查与解决 问题现象
用户生成的帖子在网页上出现字符显示不一致,部分内容的撇号显示为’,例如:
I’m having trouble and can’t figure it out
但并非所有帖子都存在此问题,部分用户的撇号显示正常。推测问题可能与用户设备(Windows/Mac)或从Word复制粘贴至表单的操作有关,多数用户来自美国。
服务器环境配置
PHP 8.1 配置(php.ini)
default_mimetype = "text/html" default_charset = "UTF-8"
MySQL 8.0 全局配置
character_set_client = utf8mb4 character_set_connection = utf8mb4 character_set_database = utf8mb4 character_set_results = utf8mb4 character_set_server = utf8mb4 character_set_system = utf8mb3 character_sets_dir = /usr/share/mysql/charsets/ collation_connection = utf8mb4_0900_ai_ci collation_database = utf8mb4_0900_ai_ci collation_server = utf8mb4_0900_ai_ci default collation for utf8mb4 = utf8mb4_0900_ai_ci
所有数据库、表、字段的排序规则均设置为 utf8mb4_0900_ai_ci
页面编码设置
- HTML头部:
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
- PHP头部:
header("Content-Type: text/html; charset=utf-8");
查询与输出代码示例
$conn = mysqli_connect($hostname, $username, $password, $database) or die("Database Connection Error"); $result = mysqli_query($conn, "SELECT field FROM table WHERE id = 123") or die(mysqli_error($conn)); $row = mysqli_fetch_assoc($result); $message = htmlspecialchars($row['field'], ENT_QUOTES); echo $message;
排查补充信息
- 数据库连接字符集检查:
mysqli_set_charset($conn,"utf8mb4"); var_dump(mysqli_get_charset($conn));
输出结果:
object(stdClass)#2 (8) { ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["dir"]=> string(0) "" ["min_length"]=> int(1) ["max_length"]=> int(4) ["number"]=> int(45) ["state"]=> int(1) ["comment"]=> string(13) "UTF-8 Unicode" }
发现PHP连接使用的排序规则为utf8mb4_general_ci,与MySQL全局默认的utf8mb4_0900_ai_ci不一致,尝试以下设置未生效:
SET collation_connection = utf8mb4_0900_ai_ci; SET SESSION collation_connection = utf8mb4_0900_ai_ci;
- 会话变量与全局变量差异:
查询performance_schema.session_variables发现:
character_set_client = utf8mb4 character_set_connection = utf8mb4 character_set_database = utf8mb3 // 与全局变量不同 character_set_filesystem = binary character_set_results = utf8mb4 character_set_server = utf8mb4 character_set_system = utf8mb3 collation_connection = utf8mb4_unicode_ci // 与全局变量不同 collation_database = utf8mb3_general_ci // 与全局变量不同 collation_server = utf8mb4_0900_ai_ci
尝试更新这些变量时提示权限拒绝,重启MySQL后无变化。
核心疑问
是否需要在保存帖子到数据库前进行PHP转换?或需通过PHP处理以正确显示文本?标准做法是什么?
解决方案
1. 修复数据库连接与数据库级编码配置
mysqli_set_charset()仅设置字符集,不会同步排序规则,需在连接后显式设置会话级规则(确保数据库用户有足够权限):
$conn = mysqli_connect($hostname, $username, $password, $database) or die("Database Connection Error"); // 先设置字符集 mysqli_set_charset($conn, 'utf8mb4'); // 再设置会话排序规则 mysqli_query($conn, "SET SESSION collation_connection = 'utf8mb4_0900_ai_ci'");
若权限不足,需联系MySQL管理员调整目标数据库的编码规则(当前character_set_database和collation_database为utf8mb3是核心问题):
ALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
2. 统一用户输入编码
用户从Word或不同系统复制内容时,可能携带Windows-1252编码的特殊字符(如智能撇号’),接收表单数据时统一转码为UTF-8:
// 处理POST数据 foreach ($_POST as $key => $value) { if (!mb_check_encoding($value, 'UTF-8')) { $_POST[$key] = mb_convert_encoding($value, 'UTF-8', 'Windows-1252'); } }
3. 修复已有乱码数据
针对已存储的乱码内容,可通过以下SQL修复(执行前务必备份数据):
UPDATE your_table SET field = CONVERT(CONVERT(CONVERT(field USING latin1) USING binary) USING utf8mb4);
4. 输出环节验证
当前使用htmlspecialchars的方式正确,保持ENT_QUOTES参数即可,已设置的header和<meta>标签能保证页面编码为UTF-8,无需额外调整。
内容的提问来源于stack exchange,提问作者peppy
相关产品推荐
相关产品推荐

