【问题标题】:Page with UTF-8 encoding sends data to MySQL with UTF-8 encoding but entry is scrambled使用 UTF-8 编码的页面使用 UTF-8 编码向 MySQL 发送数据,但条目被打乱
【发布时间】:2013-07-07 08:10:36
【问题描述】:

我知道有十几个类似的问题,但其中建议的解决方案都不适用于这种情况。

我在页面上有一个 PHP 变量,初始化为:

$hometeam="Крылья Советов";    //Cyrrilic string

当我在页面上打印出来时,它会正确打印出来。所以echo $hometeam 应该显示字符串Крылья Советов。

header中的content meta标签设置如下:

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">

而且,在页面的最开始,我有以下内容(正如我在搜索中找到的解决方案之一中所建议的那样):

ini_set('default_charset', 'utf-8');

所以应该没问题。

我试图将其保存到的 MySQL 表和相关列将 utf8_bin 作为其编码。当我去phpMyAdmin并手动输入КрыльяСоветов时,它会正确保存在该字段中。

但是,当我尝试通过页面上的查询保存它时,使用以下基本查询:

mysql_query("insert into tablename (round,hometeam) values ('1','$hometeam') ");

mysql 入口如下所示:

c390c5a1c391e282acc391e280b9c390c2bbc391c592c391c28f20c390c2a1c390c2bec390c2b2c390c2b5c391e2809ac390c2bec390c2b2

那么这里发生了什么?如果页面上一切正常,并且 MySQL 本身一切正常,那么问题出在哪里?有什么我应该添加到查询本身以使其保持字符串 UTF-8 编码的吗?

请注意,我在连接数据库后(在页面顶部)设置了mysql_set_charset('utf8');

编辑:运行查询SHOW VARIABLES LIKE "%character_set%" 给出以下结果:

Variable_name   Value
character_set_client    utf8
character_set_connection    utf8
character_set_database  latin1
character_set_filesystem    binary
character_set_results   utf8
character_set_server    latin1
character_set_system    utf8
character_sets_dir  /usr/share/mysql/charsets/

似乎这里可能有一些东西,因为该列表中有 2 个 latin1。你怎么看?

另外,当我直接在 phpMyAdmin 中输入西里尔文字符串时,它起初看起来很好(保存后它会正确显示)。但是重新加载表格,它以十六进制显示,就像插入的表格一样。对于问题中有关此问题的错误信息,我深表歉意。事实证明,这应该意味着问题出在 phpMyAdmin 或数据库本身。

编辑 #2:这是 show create table tablename 返回的内容:

CREATE TABLE `tablename` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `round` int(11),  `hometeam` varchar(32) COLLATE utf8_bin NOT NULL,  `competition` varchar(32) CHARACTER SET latin1 NOT NULL DEFAULT 'Russia',  PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=119 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

【问题讨论】:

  • 您之前是否进行过类似“SET NAMES 'utf8'”的查询? stackoverflow.com/questions/2159434/set-names-utf8-in-mysql
  • @steven 我没有这样做,不,但现在我的问题仍然存在,所以没有帮助。
  • @jovan 源代码文件的编码是什么?在使用西里尔编码的类似设置中进行测试,我只得到一个空字符串。使用 utf8 一切都按预期进行。
  • @Salem 文件的编码也是UTF-8。
  • @jovan 刚刚为您关于团队的其他问题准备好了答案,可惜您删除了它。

标签: php mysql encoding utf


【解决方案1】:

你在phpMyAdmin 中得到这个十六进制字符串吗?我想当你 SELECT 插入值时,例如PHPMySQL 控制台客户端,您将获得预期的西里尔 UTF8 字符串。

如果是这样,这是 phpMyAdmin 的配置问题,请参阅例如这里:http://theyouri.blogspot.ch/2010/12/phpmyadmin-collated-db-in-utf8bin-shows.html

utf8_bin 中的 phpMyAdmin 整理的数据库显示十六进制数据而不是 UTF8 文本

$cfg['DisplayBinaryAsHex'] = false;

此外,请不要那样使用mysql_query,因为您对 SQL 注入完全开放。我也不确定你是否真的想使用 utf8_bin,参见例如本次讨论:utf8_bin vs. utf_unicode_ci 或本次:UTF-8: General? Bin? Unicode?

编辑发生了一些奇怪的事情。如果您将给定的十六进制字符串翻译成 UTF8 字符,您会得到:“ÐšÑ€Ñ‹Ð»ÑŒÑ ¡¡¡Ð¾Ð²ÐµÑ‚о¡²”(参见例如http://software.hixie.ch/utilities/cgi/unicode-decoder/utf8-decoder)。如果你utf8_decode 这个,你会得到想要的“Крылья Советов”。所以,它似乎至少被 utf8 编码了两次(除了它在某处显示为十六进制字符的问题)。

能否提供完整的脚本?你utf8_encode你的字符串在任何地方吗?如果您的脚本是这个并且只有这个(除了一个有效的、打开的 MySQL 连接):

<?php
$hometeam="Крылья Советов";    //Cyrrilic string
// open mysql connection here
mysql_set_charset('utf8');
mysql_query("INSERT INTO tablename (round, hometeam) VALUES ('1', '$hometeam')");
$result = mysql_query("SELECT * FROM tablename WHERE round = '1'");
$row = mysql_fetch_assoc($result);
echo $row['hometeam'];
?>

而你调用页面,结果是什么(在浏览器的页面源中,不是浏览器中显示的)?

另外,请检查如果您将排序规则更改为 utf8_unicode_ci 会发生什么,如此处另一个答案中所建议的那样。这至少涵盖了显示二进制数据时的 phpMyAdmin 问题,并且可能无论如何都是您想要的(因为您可能希望 ORDER BY 子句按预期执行,请参阅我上面链接的 SO 问题中的讨论)。

EDIT2也许你也可以提供一些像SHOW CREATE TABLE tablenameSHOW VARIABLES LIKE "%character_set%"这样的sn-ps。可能会有所帮助。

【讨论】:

  • 当我打印出数据库中的值时(我已经尝试过使用和不使用 utf_encode)我没有得到正确的西里尔文文本。至于sql注入,我知道了,谢谢。这只是一个例子。这是在共享主机上,所以我认为我不能那样配置 phpMyAdmin。
  • 澄清一下:当您选择值时,您会得到您提到的十六进制字符串?您在哪里以及如何“打印”数据库中的值?
  • 请看我编辑的答案,也许当您提供更多信息时我们可以找到更多信息。
  • 抱歉耽搁了,我现在在打电话,明天早上我会按照你的建议做。
  • 我不在 PHP 代码中的任何地方对字符串进行 utf_encode。如果我使用您在页面上建议的代码 sn-p,正确的西里尔文字符串会同时出现在页面和页面源代码中。完整的页面源代码在这里:pastebin.com/1RtAJ0RQ - 抓取本身是脚本的大部分,也许有人可以在自己的服务器上尝试。您是对的,没有针对注射的保护措施,我在测试期间将其删除,以查看是否可能与它有关。现在正在处理您的其他建议。
【解决方案2】:

另外,当我直接在 phpMyAdmin 中输入西里尔文字符串时,它 起初看起来很好(保存后它显示正确)。但 重新加载表格,它以十六进制显示,就像插入的表格一样。

这几乎可以肯定看起来您的表有问题!运行show create table tablename。我敢打赌有 latin1 而不是 utf8,因为你在 character_set_database 变量中将它设置为默认值。

要更改此设置,请运行以下命令:

ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

will convert 你所有的varchar 字段到utf8。但要小心表中已有的记录,因为它们已经是格式错误的,如果您将它们转换为 UTF8,它们将保持格式错误。也许最好的办法是重新创建数据库,只需在表定义的末尾添加以下命令:

CREATE TABLE `tablename` (
    ....
) ENGINE=<whatever you use> DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci

【讨论】:

  • @jovan,然后尝试将 utf8_bin 更改为 utf8_general_ci。请注意,您的专栏 competition 仍然是 latin1。
  • 是的,不是我将表和列的排序规则都更改为utf8_general_ci,它可以工作。谢谢!
【解决方案3】:

1) 尝试使用 PhpMyAdmin 将条目保存到数据库中,然后在 PhpMyAdmin 中查看结果。它看起来好吗?如果是,则数据库已正确创建和设置。

2) 尝试改用utf8_general_ci。这应该没关系,但请尝试一下。

3) 在 PHP 端调整所有必要的设置 - 关注这篇文章: http://blog.loftdigital.com/blog/php-utf-8-cheatsheet 。尤其是试试这个技巧:

echo htmlentities($hometeam, ENT_QUOTES, 'UTF-8')

【讨论】:

  • 我认为问题几乎肯定出在数据库方面 - 请检查我对问题的编辑。
  • @jovan 我读了你的更新——那么问题肯定出在你的桌子上!请报告show create table tablename的完整输出!
  • 我已将输出添加到问题中。对我来说它看起来不错 - 也许问题出在整体 MySQL 配置中?既然是共享主机,也许我可以让主机支持人员帮助我?顺便说一句,我尝试切换到 utf8_general_ci,并没有改变任何东西。
  • 别介意上面的评论 - 当我更改表和列的排序规则时,它开始正常工作。作为旁注,您知道为什么会发生这种情况吗? utf_bin 不应该适用于所有事情吗?
  • @jovan(您可能还参考了我的其他答案)- 这不是很清楚,但我认为 utf8_general_ci 应该适用于所有事情。
【解决方案4】:

正如我在 cmets 中看到的那样,您无法更新您的数据库配置,不是吗?

我猜你的编码配置有误,因为我在官方文档MySQL Documentation看到了这一点

我可以向您推荐一个 PHP 解决方案。由于存在很多编码问题,您可以在将字符串插入数据库之前对其进行转换。你必须找到一种通用语言在 PHP 和数据库之间进行交流。

我在另一个项目中尝试的方法是使用url_encode($string)url_decode($string) 转换字符串。

【讨论】:

    猜你喜欢
    • 2018-01-27
    • 2017-06-20
    • 1970-01-01
    • 2021-03-22
    • 2017-03-15
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多