【问题标题】:mysqli not setting charset to utf8mb4mysqli 未将字符集设置为 utf8mb4
【发布时间】:2016-08-22 00:58:56
【问题描述】:

发现问题

问题似乎是$mysqli->set_charset() 不接受 `utf8mb4' 作为有效编码(正如我在第一次更新中“推测”的那样)。 MySQL 版本是 5.5.41,PHP 版本是 5.4.41(没问题)。


对不起标题,我一直在搜索/阅读问题出在哪里/哪里,我已经对此感到困惑......

我最近开始在 mysql 中使用 utf8mb4。我使用 utf8mb4 作为字符集,使用 utf8mb4_unicode_ci 作为所有表/列的排序规则。

所以我首先改变了:

$mysqli->set_charset('utf8');

$mysqli->set_charset('utf8mb4');

确保我的 php 文件为 utf8(我使用 Visual Studio Code,因此文件默认以 UTF-8 创建),并且 php/html 标头设置为 utf8:

index.php

header('Content-type: Text/HTML; Charset=UTF-8');

main.php(包含在 index.php 的末尾)

<meta http-equiv="Content-Type" content="Text/HTML" />
<meta charset="UTF-8" />

问题在于,对于某些表,我必须手动插入数据,并且这些数据按原样存储:带有特殊字符、带重音符号、ñ 等......当我在我的网站上显示这些数据时,我可以看到这些字符 已经替换了特殊/重音字符。

所以我的问题是:有什么方法可以在 mysql 中按原样存储数据(不替换/转换特殊/重音字符)并能够正常显示(按原样)?

如果我恢复到$mysqli-&gt;set_charset('utf8');,数据显示正常...所以这让我想知道按原样存储 utf-8 字符应该没有问题,并且某处存在一些编码问题...

我正在使用 sqlyog 社区(使用 wine)我在某处读到,有时当您更改某些 db/table 配置时 gui 无法正常工作,唯一的方法是旧方法(自己运行查询) ,但我还没有尝试过。我运行查询来设置所有表/列的字符集和排序规则。

你怎么看?

更新

我开始认为 mysqli 不接受 utf8mb4 作为有效的字符编码,并使用 php 而不是 mysql 的 utf8 ...我也认为 mysql fckd 创建 utf8mb4 而不是更新现有的 utf8 以支持 4 个字节....

当我使用 mysqli charset utf8 进行测试时,所有内容都按原样存储并按原样显示(mysql charset 和排序规则设置为 utf8mb4...)。

更新 2

SELECT name, HEX(name) FROM person LIMIT 1

这是它的输出:

New Person has name Altaïr 416C7461C3AF72

但正如我已经说过的,这是使用:

$mysqli->set_charset('utf8');

插入和选择。如果我使用 utf8mb4 来代替它存储的内容:

Altaïr

但显示正常。不显示的问题是,如果名称按原样存储,则显示的名称将为Alta�r

所以问题是:为什么mysqli/mysql 使用utf8mb4 将ï 存储为ï?为什么在mysqli中设置utf8mb4时,php会显示ï等特殊字符为

有人可以确认mysqli::set_charset 接受 utf8mb4 作为有效编码吗?

更新 3

我有一个从表“es”中选择字符串的类函数,例如:Iniciar Sesión(这是存储的)如果 mysqli charset 是 utf8,则选择/显示的是 Iniciar Sesión

这可能是一个完全不同的问题,但它显然是另一个编码问题。据我了解,如果表/列是 utf8mb4 并且 mysqli 设置为 utf8,则 mysql 必须从 utf8(3 字节)编码为 ut8mb4(全字节支持)。所以这意味着mysqli 不使用 php 中的 utf8,而是使用 mysql 中的 utf8。这是正确的,对吧?

我的应用程序目前在编码方面遇到了困难...(但可能是一些服务器配置问题...)

更新 4

问题可能出在这里吗?我真的不知道这种配置:

SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8               |
| character_set_connection | utf8               |
| character_set_database   | utf8mb4            |
| character_set_filesystem | binary             |
| character_set_results    | utf8               |
| character_set_server     | latin1             |
| character_set_system     | utf8               |
| collation_connection     | utf8_general_ci    |
| collation_database       | utf8mb4_unicode_ci |
| collation_server         | latin1_swedish_ci  |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

UPDATE 4-1/2(从评论中复制)

CREATE TABLE `es` (
    id int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 
    text varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 
    PRIMARY KEY (id), 
    UNIQUE KEY name (name)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci` 

【问题讨论】:

  • 没有转换?你是说BLOB?处理 UTF8 的经验法则是:始终记录转换 + 编码 + 解码的方法。
  • 什么是 BLOB?我以为php为我处理了...如果php与utf8一起使用并从mysql中获取utf8mb4,需要什么样的转换?
  • BLOB 是一种 MySQL 数据类型,通常用于存储大量文本或二进制数据。见这里dev.mysql.com/doc/refman/5.7/en/blob.html
  • 对了。不,我不使用 BLOB,我只是使用基本数据类型如 text 和 var/char。
  • 要检查的另一件事是您在列定义中为特殊字符分配了足够的空间。例如,varchar(255) 不够大,无法包含 255 个特殊字符。

标签: php mysql encoding utf-8 utf8mb4


【解决方案1】:

谜团解开了! mysql 安装/升级/配置错误,未正确安装 utf8mb4。

该函数的问题在于它正在使用 utf8_encode() 重新编码 db 值,并且不知何故导致了这些字符 ó -> ó

【讨论】:

  • 能否请您详细告诉我们您是如何解决此问题的。我现在也有同样的问题,正在拔头发:(
  • 抱歉耽搁了,我很享受我的假期:) MySQL(在我的情况下是 MariaDB)缺少必要的文件,所以编码不存在。需要编译文件(我认为使用必要的标志重新编译)或重新安装最新版本。这发生在旧的 cent os 5 服务器上,因此在较新的版本中不应该发生这种情况,实际上我安装了 cent os 6.7 并且检测到 utf8mb4 没有问题。
【解决方案2】:

utf8mb4 阿泰尔是 41 6C 74 61 C383C2AF 72

哎哟。那就是“双重编码”。 latin1 EF 被转换为 utf8/utf8mb4 C3AF;然后C3错误地被视为拉丁1被转换为C383AFC2AF

以下是可能发生的事情:

  • 客户端的字符编码为 utf8(良好);和
  • SET NAMES latin1 谎称客户端有 latin1 编码;和
  • 表中的列声明CHARACTER SET utf8(或utf8mb4)(好)。

第二步应该

修复
$mysqli->set_charset('utf8mb4');

我假设您没有混合使用 mysql_*mysqli_* 接口。只使用后者。

发布一个简短的、可重现的测试用例怎么样。

【讨论】:

  • 是的,我希望能够重现它,但这可能是我的框架/应用程序本身的一些问题,我不知道从哪里开始......但是,我拥有的这个类函数是当 mysqli charset 为 utf8mb4 时,选择并显示一切正常,但我的应用程序的其余部分显示�。当 mysqli 字符集只是 utf8 时,此函数不会显示�,而是典型的 html 编码问题,我将更新我的问题以添加此内容。
  • 显示很棘手。浏览器是“宽容的”;他们会尝试不同的方式来解释字节,并且在某些情况下,使乱码文本看起来正确。黑色菱形出现在它无法成功时。
  • 如果您存储了大量“双重编码”数据,这里是修复数据的信息:mysql.rjweb.org/doc.php/charcoll#fixing_double_encoding_ 但您还必须修复代码以不继续存储。
  • 不,该应用程序仍在开发中,唯一重要的数据是城市等列表,但它们已正确插入(至少我认为它们很好)。要是我能找到导致这种情况的代码就好了……你看到我的问题的最新更新了吗?
  • 您提到C383C2AF 促使我谈论“双重编码”。 utf8utf8mb4 之间的区别仍然是个谜。 “更新 4”看起来“正常”。执行SET NAMES utf8mb4 将在连接期间更改其中的 4 个。
【解决方案3】:

问题可能源于您没有在 MySQL 列定义中使用 utf8mb4(至少您没有说明您使用的是什么编码)。

下面是一个 MySQL 表定义示例,其列使用utfmb4

CREATE TABLE `person` (
  `name` varchar(255) CHARACTER SET utf8mb4
)

更新

使用下表定义:

CREATE TABLE `person` (
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

以及以下 PHP 脚本:

<?php
$mysqli = new mysqli('localhost', 'username', 'password', 'database');
$mysqli->set_charset('utf8mb4');

$mysqli->query("INSERT INTO `person` VALUES ('Altaïr Ibn-La\'Ahad')");

$result = $mysqli->query("SELECT * FROM `person` LIMIT 1");

$person = $result->fetch_object();

if($person)
    printf ("New Person has name %s.\n", $person->name);

$result->close();
$mysqli->close();

当我将“Altaïr Ibn-La'Ahad”插入数据库时​​,名称会按原样存储而不会更改。该脚本还打印了未更改的名称:“New Person has name Altaïr Ibn-La'Ahad.

我希望这可以帮助您解决问题。让我知道它是否有。

【讨论】:

  • 我使用 utf8mb4 作为字符集,使用 utf8mb4_unicode_ci 作为所有表/列的排序规则。
  • 插入数据时,在数据库中看起来是否正确:1)直接插入数据库时​​; 2)当用PHP插入时?
  • 当我直接插入数据时,它看起来是这样的。但是当我用 php 插入它时,这取决于我如何处理 php 中的用户输入。如果我使用过滤器,它会转换特殊字符,但它们会按原样显示。例如:我插入名称“Altaïr Ibn-La'Ahad”,这就是存储的“Altaïr Ibn-La'Ahad”。如果我不过滤它只是 ï 转换为 ï.
  • 我已经用一个例子更新了我的原始答案。它会在按原样存储数据的同时产生您想要的输出。
  • 我已经用您的查询创建了表并执行了脚本。但正如我上次所说的那样存储名称,ï 存储为ï。我的mysql服务器一定有问题...我已将您的答案标记为正确,我将不得不进一步查看服务器配置。
猜你喜欢
  • 2016-05-31
  • 2016-11-13
  • 2016-11-28
  • 1970-01-01
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
相关资源
最近更新 更多