UTF-8编码的页面使用UTF-8编码发送数据到MySQL,但是输入结果混乱。

3

我知道有很多类似的问题,但是这种情况下没有建议的解决方案适用。

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

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

当我将其打印在页面上时,它正确地打印出来了。因此,echo $hometeam 显示了字符串“Крылья Советов”,正如应该显示的那样。
头部中的内容元标记设置如下:
<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中输入Cyrillic字符串时,它一开始看起来很好(保存后它正确地显示)。 但是重新加载表格后,它会像插入的那些一样以HEX形式显示。对于在问题中提供的错误信息,我深感抱歉。实际上,这应该意味着问题出现在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

@Salem 文件的编码也是UTF-8。 - sveti petar
@jovan 刚刚为你关于团队的另一个问题准备好了答案,可惜你把它删除了。 - Prix
@Prix 对不起,我发现问题不在查询中 - 我有一些错误的数据导致了这个问题,所以没有必要再麻烦别人了。 - sveti petar
数据库行是varchar还是char? - Jorge Y. C. Rodriguez
如果你使用 print_r 打印 $_POST,那里面的值是否正确? - Jorge Y. C. Rodriguez
显示剩余7条评论
4个回答

2
你在 phpMyAdmin 中得到了这个十六进制字符串吗?我猜当你通过例如 PHPMySQL 控制台客户端 SELECT 插入的值时,你会得到预期的 Cyrillic UTF8 字符串。
如果是这样,那么这是一个与 phpMyAdmin 配置有关的问题,请参见此处:http://theyouri.blogspot.ch/2010/12/phpmyadmin-collated-db-in-utf8bin-shows.html

phpMyAdmin collated db in utf8_bin shows hex data instead of UTF8 text

$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问题中的讨论)。 ”
“编辑2:也许您还可以提供一些片段,例如SHOW CREATE TABLE tablenameSHOW VARIABLES LIKE“%character_set%”。可能有所帮助。”

当我从数据库中打印出值时(我已经尝试过使用和不使用utf_encode),我没有得到正确的西里尔文本。至于SQL注入,我知道这个问题,谢谢。这只是一个例子。这是共享主机上的问题,所以我认为我无法以那种方式配置phpMyAdmin。 - sveti petar
请澄清一下:当您选择该值时,是否会得到您提到的十六进制字符串?您在何处以及如何从数据库中“打印出”这些值? - stef77
请看一下我编辑过的答案,也许当您提供更多信息时我们可以找到更多线索。 - stef77
抱歉耽搁了,我现在正在用手机,明天早上我会按照你建议的去做。 - sveti petar
在 PHP 代码中,我没有对字符串进行 utf_encode。如果我使用您在页面上建议的代码片段,则正确的 Cyrillic 字符串将同时显示在页面和页面源中。完整的页面源代码在此处:http://pastebin.com/1RtAJ0RQ-刮擦本身是脚本的大部分,也许有人可以在自己的服务器上尝试它。您说得对,没有防注入保护,我在测试期间将其删除以查看是否与此有关。现在正在处理您的其他建议。 - sveti petar

1

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')

我认为问题几乎肯定在数据库方面 - 请检查我对问题的编辑。 - sveti petar
@jovan 我看到了你的更新 - 那么问题肯定在你的表中!请报告 show create table tablename 的完整输出! - Tomas
我已经将输出添加到问题中。在我看来,它看起来还不错 - 也许问题在于整个MySQL配置?由于这是共享托管,也许我可以请托管支持人员帮助我解决问题?顺便说一句,我尝试切换到utf8_general_ci,但没有改变任何东西。 - sveti petar
不用在意上面的评论 - 当我改变了表和列的排序规则后,它开始正常工作了。顺便说一下,你有什么想法为什么会发生这种情况吗?utf_bin 不应该适用于所有情况吗? - sveti petar
@jovan(您可能还参考了我的其他答案)- 这不是很清楚,但我认为utf8_general_ci应该适用于所有情况。 - Tomas

1
当我直接在phpMyAdmin中输入一个Cyrillic字符串时,它一开始看起来很好(保存后正确显示)。但是重新加载表格后,它会像插入的那些一样以HEX形式显示。这几乎肯定是您的表格存在问题!运行“show create table tablename”命令。我敢打赌,因为您将其设置为character_set_database变量的默认值,所以其中可能包含latin1而不是utf8。
要更改此设置,请运行以下命令:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

这个操作将把你所有的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。 - Tomas
是的,我已经将表格和列的排序规则更改为utf8_general_ci,现在可以正常工作了。谢谢! - sveti petar

1

根据评论,您似乎无法更新数据库配置,是吗?

我猜您的编码出现了问题,因为我在官方文档 MySQL Documentation 中看到了这一点。

我可以提供一个PHP解决方案。由于许多编码问题,您可以在将字符串插入数据库之前对其进行转换。您必须找到PHP和数据库之间的共同语言。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接