其中charset数据将存储在数据库中

时间:2018-01-11 11:11:59

标签: php mysql encoding utf-8 character-encoding

我的数据库是latin1,排序规则是latin1_swedish_ci。另外在我的php文件中我使用的是iso-8859-1。但是,如果我存储一些像'é'和其他一些字符,我在下载内容时遇到问题。所以我们在my.cnf文件中添加了默认字符集到utf8和skip-character-set-client-handshake。在每次建立连接之后和执行任何查询之前,还会在查询中添加“set-name utf8”。这解决了这个问题。但我已经做了一些观察,如下所示

Case 1:
Mysql conf file: No default character-set and no skip-character-set-client-handshake
Query: No set names
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | latin1                     |<br/>
| character_set_connection | latin1                     |<br/>
| character_set_database   | latin1                     |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | latin1                     |<br/>
| character_set_server     | latin1                     |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>

stored ->é(utf8)(Hex->C3A9)<br/>


Case2:
Mysql conf file: Default character-set - utf8 and no skip-character-set-client-handshake
Query: No set names<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | latin1                     |<br/>
| character_set_connection | latin1                     |<br/>
| character_set_database   | utf8                       |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | latin1                     |<br/>
| character_set_server     | utf8                       |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
<br/>
stored ->é(utf8)(Hex->C3A9)<br/>


Case3:
Mysql conf file: Default character-set - utf8 and skip-character-set-client-handshake
Query: No set names<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | utf8                       |<br/>
| character_set_connection | utf8                       |<br/>
| character_set_database   | utf8                       |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | utf8                       |<br/>
| character_set_server     | utf8                       |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(latin1)(Hex->E9)<br/>


Case4:
Mysql conf file: no Default characterset - utf8 and skip-character-set-client-handshake
Query: No set names<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | utf8                       |<br/>
| character_set_connection | utf8                       |<br/>
| character_set_database   | utf8                       |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | utf8                       |<br/>
| character_set_server     | utf8                       |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(utf8)(Hex->C3A9)<br/>


Case5:
Mysql conf file: Default characterset - utf8 and skip-character-set-client-handshake
Query: set names utf8<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | utf8                       |<br/>
| character_set_connection | utf8                       |<br/>
| character_set_database   | utf8                       |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | utf8                       |<br/>
| character_set_server     | utf8                       |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(latin1)(Hex->E9)<br/>


Case6:
Mysql conf file: Default characterset - utf8 and no skip-character-set-client-handshake
Query: set names utf8<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | latin1                     |<br/>
| character_set_connection | latin1                     |<br/>
| character_set_database   | utf8                       |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | latin1                     |<br/>
| character_set_server     | utf8                       |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(latin1)(Hex->E9)<br/>


Case7:
Mysql conf file: no Default characterset  and no skip-character-set-client-handshake
Query: set names utf8<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | latin1                     |<br/>
| character_set_connection | latin1                     |<br/>
| character_set_database   | latin1                     |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | latin1                     |<br/>
| character_set_server     | latin1                     |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(latin1)(Hex->E9)<br/>


Case8:
Mysql conf file: no Default characterset  and  skip-character-set-client-handshake
Query: set names utf8<br/>
Result: 
mysql> show variables like '%charac%';<br/>
+--------------------------+----------------------------+<br/>
| Variable_name            | Value                      |<br/>
+--------------------------+----------------------------+<br/>
| character_set_client     | latin1                     |<br/>
| character_set_connection | latin1                     |<br/>
| character_set_database   | latin1                     |<br/>
| character_set_filesystem | binary                     |<br/>
| character_set_results    | latin1                     |<br/>
| character_set_server     | latin1                     |<br/>
| character_set_system     | utf8                       |<br/>
| character_sets_dir       | /usr/share/mysql/charsets/ |<br/>
+--------------------------+----------------------------+<br/>
8 rows in set (0.00 sec)<br/>

stored ->é(latin1)(Hex->E9)<br/>



Output containing all the 8 cases together<br/>
+-----------+------------------------------------------------------------------+<br/>
| HEX(name) | desc                                                             |<br/>
+-----------+------------------------------------------------------------------+<br/>
| C3A9      | no skip handshake and no default  in conf and nothing in query   |<br/>
| C3A9      | no skip handshake and default utf8 in conf and nothing in query  |<br/>
| E9        | skip handshake and default utf8 in conf and nothing in query     |<br/>
| C3A9      |  skip handshake and no default  in conf and nothing in query     |<br/>
| E9        | skip handshake and default utf8 in conf and utf8 in query        |<br/>
| E9        | no skip handshake and default utf8 in conf and utf8 in query     |<br/>
| E9        | no skip handshake and no default  in conf and utf8 in query      |<br/>
| E9        |  skip handshake and no default  in conf and utf8 in query        |<br/>
+-----------+------------------------------------------------------------------+<br/>

数据存储在数据库中的基础是什么?有时它以latin1格式存储,有时以utf8格式存储。 它是基于选项(我的意思是变量,如character_set_client,character_set_server等......)或On my.cnf配置??

考虑到所有8个案例我都没有得出结论。 我还经历了'SET Names','skip-character-set-client-handshake'的解释。但仍然处于困惑之中。存储时或在显示时是否发生转换?

上述观察是使用包含以下行的PHP脚本完成的。

$conn = mysqli_connect('<host>', '<username>', '<password>', 'table');<br/>
mysqli_query($conn, "SET NAMES 'utf8';");<br/>
mysqli_query($conn, 'insert into router.test values ("é");');<br/>

提前感谢您的回复。

3 个答案:

答案 0 :(得分:2)

  

我的数据库位于latin1,排序规则为latin1_swedish_ci。

这些是默认设置。创建列和表后,每列都有一个字符集和一个排序规则。更改默认值不会更改现有列和表定义。

  

在我的php文件中我正在使用iso-8859-1。

没关系。 Latin1 === iso-8859-1

  

但如果我存储了一些像'é'这样的字符以及其他一些字符,我在下载内容方面遇到了问题。

我猜您的意思是从表中检索内容然后将其发送到Web浏览器进行渲染的两步过程。这可能是错误的第二步。尝试在php / html文件的head部分设置它。

<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">

如果你设置了并且所有内容都正确呈现,那么你就完成了。您也可以将其设置为unicode,看看会发生什么。如果您没有设置它,浏览器会尝试使用神秘规则进行猜测。

  

所以我们在my.cnf文件中添加了默认字符集到utf8和skip-character-set-client-handshake。

同样,这不会更改表格中的现有列。

  

数据存储在数据库中的基础是什么?

再次,根据为每列选择的字符集。

  

有时它以latin1格式存储,有时以utf8格式存储。

这是真的。

最佳实践:在创建时为每个表提及字符集和排序规则。如果某些列有例外情况,请在创建

列时为其添加

最佳实践:对于新数据库,请使用utfmb4。

最佳实践:始终设置数据库连接字符集。

最佳实践:阅读有关如何在php中创建和操作unicode字符串的内容。

最佳实践:在建立新的MySQL服务器时,将服务器范围的默认值设置为utfmb4和utfmb4_general_ci。

不幸的是,将现有的php应用程序迁移到unicode可能是一件痛苦的事。

答案 1 :(得分:1)

您的客户端发送C3A9E9 - 独立于MySQL所说的任何内容

my.cnf和/或SET NAMES和/或连接参数确定SHOW VARIABLES LIKE 'character_set_%'中的3个值。

这些设置说明解释 C3A9E9latin1utf8

C3A9被解释为utf8:good(éC3A9被解释为latin1:Mojibake(éE9被解释为latin1:good(éE8解释为utf8:由于非utf8字节

,字符串被截断

但我们还没完成......

如果您是INSERTing,则服务器会查看目标列的编码,从上面(latin1或utf8)转换为列的声明。如果相同,则不需要转换,如果不同,则在存储期间发生转换。我很惊讶你没有偶然发现存储é的“双重编码”。当utf8字节(C3A9)被latin1(等)错误地声明为SET NAMES,然后存储到utf8列(因此进行另一次转换)时,会发生这种情况。

更多讨论:Trouble with UTF-8 characters; what I see is not what I storedhttp://mysql.rjweb.org/doc.php/charcoll

答案 2 :(得分:0)

感谢@Rick James的回应和链接。

实际上,我从其他链接以及Rick James的上述共享链接中得到了我的问题的答案。这满足了以上所有8个案例。

如果连接(utf8)和存储字符集(latin1)之间存在差异,MySQL会将内容从一种编码转换为另一种编码。

案例1:这里我们实际上是将UTF-8字符写入latin1数据库,每个UTF-8字节序列将被解释为单独的latin1字符。组成UTF-8字符(Ã)的每个字节被解释为单独的latin1字符,并且在写入表格时将每个字符转换为UTF-8(à - - >é - &gt; c3 A9)

,即插入的字符串是é,在UTF-8(Ã)中,字符表示为两个字节,十六进制表示为C3A9。当我们将UTF-8数据插入此表时,它只将两个字节视为两个latin1字符,不进行转换,并将它们保存到表中。在对utf8执行SET-NAMES之前,它以C3A9格式插入

的MySQL&GT;插入test.test值('é');

查询正常,1行受影响(0.00秒)

的MySQL&GT;从test中选择hex(text);

+ ----------- +
| hex(文本)|
+ ----------- +
| C3A9 |
+ ----------- +
1行(0.00秒)

案例2:当我们将set-NAMES设置为utf8时,我们尝试将任何数据插入表中,它会将其视为utf8,因为目标列(文本)的类型为latin1,它将转换utf8数据(2字节 - &gt; C3E9)至latin1(1byte - > E9)。

的MySQL&GT;设置名称'utf8';
查询OK,0行受影响(0.00秒)

的MySQL&GT;插入test.test值('é');
查询正常,1行受影响(0.00秒)

的MySQL&GT;从测试中选择十六进制(文本);
+ ----------- +
| hex(文本)|
+ ----------- +
| C3A9 |
| E9 |
+ ----------- +
2行(0.00秒)

所以在对utf8执行SET-NAMES之后,从客户端发送的任何数据,尤其是像é这样的字符都会转换并以latin1格式存储,而不会被视为2个单独的latin1字符。

同时在获取数据时,它将转换回原始格式。

SET NAMES表示客户端将用于将SQL语句发送到服务器的字符集。因此,SET NAMES'utf8'告诉服务器,“来自此客户端的未来传入消息是字符集utf8。”它还指定了服务器用于将结果发送回客户端的字符集。

SET NAMES'charset_name'语句等同于这三个语句:

SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;