You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

排查补充信息

  1. 数据库连接字符集检查:
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;
  1. 会话变量与全局变量差异:
    查询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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:47:47