mysqli 没有将字符集设置为 utf8mb4
mysqli not setting charset to utf8mb4
发现问题
问题似乎是 $mysqli->set_charset()
不接受 `utf8mb4' 作为有效编码(就像我在第一次更新中 "speculated" 一样)。 MySQL 版本是 5.5.41,PHP 版本是 5.4.41(没问题)。
对不起这个标题,我已经 searching/reading 关于 what/where 问题是什么,我已经对此感到很困惑...
我最近开始在 mysql 中使用 utf8mb4。我使用 utf8mb4 作为字符集和 utf8mb4_unicode_ci 作为所有 tables/columns.
的排序规则
所以我先改了:
$mysqli->set_charset('utf8');
至
$mysqli->set_charset('utf8mb4');
确保我的 php 文件是 utf8(我正在使用 Visual Studio 代码,因此文件默认以 UTF-8 创建),并且 php/html headers 设置为 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" />
问题是对于某些 tables 我必须手动插入数据,并且这些数据按原样存储:带有特殊字符、带有重音符号、ñ 等...当我显示时我网站上的这个数据我可以看到这些字符 �
已经替换了 special/accented 个字符。
所以我的问题是:有什么方法可以在 mysql 中按原样存储数据(没有 replacing/converting special/accented 个字符)并能够很好地显示它(按原样) ?
如果我恢复到 $mysqli->set_charset('utf8');
,数据显示正常...所以这让我想知道按原样存储 utf-8 字符应该没有问题,但某处存在一些编码问题。 ..
我正在使用 sqlyog 社区(与 wine)并且我在某处读到当您更改某些 db/table 配置时 gui 有时无法正常工作,唯一的方法是旧方法(运行 你自己查询),但我还没有试过这个。我 运行 查询设置所有 tables/columns.
的字符集和排序规则
你怎么看?
更新
我开始认为 mysqli 不接受 utf8mb4 作为有效字符编码并使用来自 php 而不是来自 mysql 的 utf8...我也认为mysql fckd 创建 utf8mb4 而不是更新现有的 utf8 以支持 4 个字节....
当我使用 mysqli 字符集 utf8 进行测试时,所有内容都按原样存储并按原样显示(mysql 字符集和排序规则设置为 utf8mb4...)。
更新 2
SELECT name, HEX(name) FROM person LIMIT 1
这是它的输出:
New Person has name Altaïr 416C7461C3AF72
但是正如我已经说过的,这是使用:
$mysqli->set_charset('utf8');
插入并select。如果我改用 utf8mb4,这就是它存储的内容:
Altaïr
但是显示正常。它没有显示的是,如果名称按原样存储,显示的名称将是 Alta�r
.
所以问题是:为什么 mysqli/mysql 使用 utf8mb4 将 ï
存储为 ï
?为什么在 mysqli 中设置了 utf8mb4 时 php 将 ï
等特殊字符显示为 �
?
有人可以确认 mysqli::set_charset
接受 utf8mb4 作为有效编码吗?
更新 3
我有一个 class 函数,它 select 是来自 table "es" 的字符串,例如:Iniciar Sesión
(这是存储的)和如果 mysqli 字符集是 utf8,则 selected/displayed 是 Iniciar Sesión
.
这可能是一个完全不同的问题,但它显然是另一个编码问题。据我了解,如果 tables/columns 是 utf8mb4 并且 mysqli 设置为 utf8,则 mysql 必须从 utf8(3 字节)编码到 ut8mb4(全字节支持)。所以这意味着 mysqli
不使用来自 php 的 utf8,而是来自 mysql。这是正确的,对吗?
我的应用程序目前在编码方面遇到困难...(但可能是某些服务器配置问题...)
更新 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)
更新 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`
问题可能源于您没有在 MySQL 列定义中使用 utf8mb4
(至少您没有说明您使用的是什么编码)。
这是一个 MySQL table 定义的示例,其中一列使用 utfmb4
:
CREATE TABLE `person` (
`name` varchar(255) CHARACTER SET utf8mb4
)
更新
使用以下 table 定义:
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 Altaïr is 41 6C 74 61 C383C2AF 72
哎呀。即"double encoding"。 latin1 EF
已转换为 utf8/utf8mb4 C3AF
;然后 C3
、 被错误地视为 latin1 被转换为 C383
并且 AF
被转换为 C2AF
.
这是可能发生的事情:
- 客户端的字符编码为utf8(好);和
SET NAMES latin1
谎称客户端有 latin1 编码;和
- 在table列声明
CHARACTER SET utf8
(或utf8mb4)(好)。
第二步应该已经被
修复了
$mysqli->set_charset('utf8mb4');
我假设您没有混合使用 mysql_*
和 mysqli_*
接口。只使用后者。
发布一个简短的、可重现的测试用例怎么样。
谜底解开了! installation/upgrade/config 和 mysql 有问题,utf8mb4 没有正确安装。
函数的问题在于它使用 utf8_encode() 重新编码 db 值,并且不知何故导致了这些字符 ó
-> ó
。
发现问题
问题似乎是 $mysqli->set_charset()
不接受 `utf8mb4' 作为有效编码(就像我在第一次更新中 "speculated" 一样)。 MySQL 版本是 5.5.41,PHP 版本是 5.4.41(没问题)。
对不起这个标题,我已经 searching/reading 关于 what/where 问题是什么,我已经对此感到很困惑...
我最近开始在 mysql 中使用 utf8mb4。我使用 utf8mb4 作为字符集和 utf8mb4_unicode_ci 作为所有 tables/columns.
的排序规则所以我先改了:
$mysqli->set_charset('utf8');
至
$mysqli->set_charset('utf8mb4');
确保我的 php 文件是 utf8(我正在使用 Visual Studio 代码,因此文件默认以 UTF-8 创建),并且 php/html headers 设置为 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" />
问题是对于某些 tables 我必须手动插入数据,并且这些数据按原样存储:带有特殊字符、带有重音符号、ñ 等...当我显示时我网站上的这个数据我可以看到这些字符 �
已经替换了 special/accented 个字符。
所以我的问题是:有什么方法可以在 mysql 中按原样存储数据(没有 replacing/converting special/accented 个字符)并能够很好地显示它(按原样) ?
如果我恢复到 $mysqli->set_charset('utf8');
,数据显示正常...所以这让我想知道按原样存储 utf-8 字符应该没有问题,但某处存在一些编码问题。 ..
我正在使用 sqlyog 社区(与 wine)并且我在某处读到当您更改某些 db/table 配置时 gui 有时无法正常工作,唯一的方法是旧方法(运行 你自己查询),但我还没有试过这个。我 运行 查询设置所有 tables/columns.
你怎么看?
更新
我开始认为 mysqli 不接受 utf8mb4 作为有效字符编码并使用来自 php 而不是来自 mysql 的 utf8...我也认为mysql fckd 创建 utf8mb4 而不是更新现有的 utf8 以支持 4 个字节....
当我使用 mysqli 字符集 utf8 进行测试时,所有内容都按原样存储并按原样显示(mysql 字符集和排序规则设置为 utf8mb4...)。
更新 2
SELECT name, HEX(name) FROM person LIMIT 1
这是它的输出:
New Person has name Altaïr 416C7461C3AF72
但是正如我已经说过的,这是使用:
$mysqli->set_charset('utf8');
插入并select。如果我改用 utf8mb4,这就是它存储的内容:
Altaïr
但是显示正常。它没有显示的是,如果名称按原样存储,显示的名称将是 Alta�r
.
所以问题是:为什么 mysqli/mysql 使用 utf8mb4 将 ï
存储为 ï
?为什么在 mysqli 中设置了 utf8mb4 时 php 将 ï
等特殊字符显示为 �
?
有人可以确认 mysqli::set_charset
接受 utf8mb4 作为有效编码吗?
更新 3
我有一个 class 函数,它 select 是来自 table "es" 的字符串,例如:Iniciar Sesión
(这是存储的)和如果 mysqli 字符集是 utf8,则 selected/displayed 是 Iniciar Sesión
.
这可能是一个完全不同的问题,但它显然是另一个编码问题。据我了解,如果 tables/columns 是 utf8mb4 并且 mysqli 设置为 utf8,则 mysql 必须从 utf8(3 字节)编码到 ut8mb4(全字节支持)。所以这意味着 mysqli
不使用来自 php 的 utf8,而是来自 mysql。这是正确的,对吗?
我的应用程序目前在编码方面遇到困难...(但可能是某些服务器配置问题...)
更新 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)
更新 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`
问题可能源于您没有在 MySQL 列定义中使用 utf8mb4
(至少您没有说明您使用的是什么编码)。
这是一个 MySQL table 定义的示例,其中一列使用 utfmb4
:
CREATE TABLE `person` (
`name` varchar(255) CHARACTER SET utf8mb4
)
更新
使用以下 table 定义:
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 Altaïr is 41 6C 74 61 C383C2AF 72
哎呀。即"double encoding"。 latin1 EF
已转换为 utf8/utf8mb4 C3AF
;然后 C3
、 被错误地视为 latin1 被转换为 C383
并且 AF
被转换为 C2AF
.
这是可能发生的事情:
- 客户端的字符编码为utf8(好);和
SET NAMES latin1
谎称客户端有 latin1 编码;和- 在table列声明
CHARACTER SET utf8
(或utf8mb4)(好)。
第二步应该已经被
修复了$mysqli->set_charset('utf8mb4');
我假设您没有混合使用 mysql_*
和 mysqli_*
接口。只使用后者。
发布一个简短的、可重现的测试用例怎么样。
谜底解开了! installation/upgrade/config 和 mysql 有问题,utf8mb4 没有正确安装。
函数的问题在于它使用 utf8_encode() 重新编码 db 值,并且不知何故导致了这些字符 ó
-> ó
。