MySQL中文乱码问题的解决第1/2页

转自:http://www.phpchina.cn/viewarticle.php?id=1584

下面要写的是一篇非常无聊的东西,充斥了大量各式各样的编码、转换、客户端、服务器端、连接……呃,我自己都不愿意去看它,但想一想,写下来还是有点意义的,原因有四:

MySQL 4.1 对多语言的支持有了很大变化 (这导致了问题的出现);
尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3 仍然占主导地位;但 MySQL 4.1 是 MySQL 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;
许多 PHP 程序以 MySQL 作为默认的数据库管理软件,但它们一般不区分 MySQL 4.1 与 4.1 以下版本的区别,笼统地称“MySQL 3.xx.xx 以上版本”就满足安装需求了;
因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题;
简单的说,MySQL 自身的变化和使用 MySQL 的 PHP 程序对此忽略,导致了问题的出现和复杂化,而由于大部分用户使用的是英文,使这种问题不被重视。这里提到的 PHP 程序,主要就 WordPress 而言。

MySQL 4.1 字符集支持的原理MySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢?

编译 MySQL 时,指定了一个默认的字符集,这个字符集是 latin1;
安装 MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的;
启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的;
此时 character_set_server 被设定为这个默认的字符集;
当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server;
当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集;
在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集;
当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集;
这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的;

简单的总结一下,如果什么地方都不修改,那么所有的数据库的所有表的所有栏位的都用 latin1 存储,不过我们如果安装 MySQL,一般都会选择多语言支持,也就是说,安装程序会自动在配置文件中把 default_character_set 设置为 UTF-8,这保证了缺省情况下,所有的数据库的所有表的所有栏位的都用 UTF-8 存储。

当一个 PHP 程序与 MySQL 建立连接后,这个程序发送给 MySQL 的数据采用的是什么字符集?MySQL 无从得知 (它最多只能猜测),所以 MySQL 4.1 要求客户端必须指定这个字符集,也就是 character_set_client,MySQL 的怪异之处在于,得到的这个字符集并不立即转换为存储在数据库中的那个字符集,而是先转换为 character_set_connection 变量指定的一个字符集;这个 connection 层究竟有什么用我不大明白,但转换为 character_set_connection 的这个字符集之后,还要转换为数据库默认的字符集,也就是说要经过两次转换;当这个数据被输出时,又要由数据库默认的字符集转换为 character_set_results 指定的字符集。

一个典型的环境典型的环境以我自己的电脑上安装的 MySQL 4.1 为例,我自己的电脑上安装着 Apache 2,PHP 5 和 WordPress 1.5.1.3,MySQL 配置文件中指定了 default_character_set 为 utf8。于是问题出现了:

WordPress 按照默认情况安装,所以所有的表都用 UTF-8 存储数据;
WordPress 默认采用的浏览字符集是 UTF-8 (Options->Reading 中设置),因此所有 WP 页面的 meta 中会说明 charset 是 utf-8;
所以浏览器会以 utf-8 方式显示所有的 WP 页面;这样一来 Write 的所有 Post,和 Comment 都会以 UTF-8 格式从浏览器发送给 Apache,再由 Apache 交给 PHP;
所以 WP 从所有的表单中得到的数据都是 utf-8 编码的;WP 不加转换的直接把这些数据发送给 MySQL;
MySQL 默认设置的 character_set_client 和 character_set_connection 都是 latin1,此时怪异的事情发生了,实际上是 utf-8 格式的数据,被“当作 latin1”转换成……居然还是转换成 latin1,然后再由这个 latin1 转换成 utf-8,这么两次转换,有一部分 utf-8 的字符就丢失了,变成 ??,最后输出的时候 character_set_results 默认是 latin1,也就输出为奇怪的东西了。
最神奇的还不是这个,如果 WordPress 中设置以 GB2312 格式阅读,那么 WP 发送给 MySQL 的 GB2312 编码的数据,被“当作 latin1”转换后,存进数据库的是一种奇怪的格式 (真的是奇怪的格式,mysqldump 出来就能发现,无论当作 utf-8 还是当作 gb2312 来读都是乱码),但如果这种格式以 latin1 输出出来,居然又能变回 GB2312!

这会导致什么现象呢?WP 如果使用 MySQL 4.1 数据库,把编码改用 GB2312 就正常了,可惜,这种正常只是貌似正常。

如何解决问题如果你已经不耐烦了 (几乎是肯定的),google 一下,会发现绝大部分的解答是,query 之前先执行一下:SET NAMES 'utf8',没错,这是解决方案,但本文的目的是说明,这为什么是解决方案。

要保证结果正确,必须保证数据表采用的格式是正确的,也就是说,至少能够存放所有的汉字,那么我们只有两种选择,gbk 或者 utf-8,下面讨论 utf-8 的情况。

因为配置文件设置的 default_character_set 是 utf8,数据表默认采用的就是 utf-8 建立的。这也应该是所有采用 MySQL 4.1 的主机提供商应该采用的配置。所以我们要保证的只是客户端与 MySQL 交互之间指定编码的正确。

这只有两种可能,客户端以 gb2312 格式发送数据,或者以 utf-8 格式发送数据。

如果以 gb2312 格式发送:

SET character_set_client='gb2312'
SET character_set_connection='utf8' 或者
SET character_set_connection='gb2312'

都是可以的,都能够保证数据在编码转换中不出现丢失,也就是保证存储入数据库的是正确的内容。

怎么保证取出的是正确的内容呢?考虑到绝大部分客户端 (包括 WP),发送数据的编码也就是它所希望收到数据的编码,所以:

SET character_set_results='gb2312'

可以保证取出给浏览器显示的格式就是 gb2312。

如果是第二种情况,客户端以 utf-8 格式发送 (WP 的默认情况),可以采用下述配置:

SET character_set_client='utf8'
SET character_set_connection='utf8'
SET character_set_results='utf8'

这个配置就等价于 SET NAMES 'utf8'。

WP 应该作什么修改还是那句话,客户端要发给数据库什么编码的数据,数据库是不可能确切知道的,只能让客户端自己说明白,所以,WP 是必须发送正确的 SET... 给 MySQL 的。怎么发送最合适呢?台湾的 pLog 同仁给出了一些建议:

首先,测试服务器是否 >= 4.1,编译时是否加入了 UTF-8 支持;是则继续
然后测试数据库以什么格式存储 ($dbEncoding);
SET NAMES $dbEncoding
对于第二点,WP 的情况是不同的,按照上面的典型配置,只要用 WP,肯定数据库是用 UTF-8 存储的,所以要根据用户设置的以 GB2312 还是 UTF-8 浏览来判断 (bloginfo('charset')),但这个值是要连接数据库以后才能得到的,所以效率最高的方式是连接数据库之后,根据这个配置设置一次 SET NAMES,而不必每次查询之前都设置一遍。

我的修改方式是这样的,在 wp_includes/wp-db.php 中增加:

function set_charset($charset)
{
// check mysql version first.
$serverVersion = mysql_get_server_info($this->dbh);
$version = explode('.', $serverVersion);
if ($version[0] < 4) return;

// check if utf8 support was compiled in
$result = mysql_query("SHOW CHARACTER SET like 'utf8'",
$this->dbh);
if (mysql_num_rows($result) < = 0) return;

if ($charset == 'utf-8' || $charset == 'UTF-8')
$charset = 'utf8';
@mysql_query("SET NAMES '$charset'", $this->dbh);
}

在 wp-settings.php 的 require (ABSPATH . WPINC . '/vars.php'); 后增加:

$wpdb->set_charset(get_bloginfo('charset'));

http://www.phpchina.cn/viewarticle.php?id=1584

当前1/2页 12下一页阅读全文

(0)

相关推荐

  • MySQL字符集 GBK、GB2312、UTF8区别 解决MYSQL中文乱码问题

    MySQL中涉及的几个字符集 character-set-server/default-character-set:服务器字符集,默认情况下所采用的. character-set-database:数据库字符集. character-set-table:数据库表字符集. 优先级依次增加.所以一般情况下只需要设置character-set-server,而在创建数据库和表时不特别指定字符集,这样统一采用character-set-server字符集. character-set-client:客户

  • 小结下MySQL中文乱码,phpmyadmin乱码,php乱码 产生原因及其解决方法第1/3页

    乱码产生原因 mysql字符编码是版本4.1引入的,支持多国语言,而且一些特性已经超过了其他的数据库系统. 我们可以在MySQL Command Line Client 下输入如下命令查看mysql的字符集 mysql> SHOW CHARACTER SET; +----------+-----------------------------+---------------------+--------+ | Charset  | Description                 | De

  • mysql 中文乱码 解决方法集锦

    第一个方法: MySQL 4.1 中文乱码的问题 最近要将 MySQL 4.0 升级到 MySQL 4.1 ,发现了中文乱码的问题,希望以下见解对大家有用. 1. MySQL 4.1 在文字上有很大改进,它有了 Character Set 与 Collation 的慨念. 2. 在 MySQL 4.0 ,一般的程式都会将文字以拉丁文 ( latin) 来储存,就算我们输入中文字,结果仍是放在以拉丁文设置的文字栏里头,这对 MySQL 4.0 与以 MySQL 4.0 为基楚的程式来说,并不会有问

  • jsp中文乱码 jsp mysql 乱码的解决方法

    jsp中文乱码 jsp mysql 乱码要servlet里面支持中文的方法: 在dopost或者doget的第一句加上: request.setCharacterEncoding("GB2312"); response.setCharacterEncoding("GB2312"); jsp乱码问题在jsp里面就把 <%@ page contentType="text/html; charset=gb2312" language="

  • Mysql 导入导出csv 中文乱码问题的解决方法

    导入csv: 复制代码 代码如下: load data infile '/test.csv' into table table_name fields terminated by ','  optionally enclosed by '"' escaped by '"' lines terminated by '\r\n' ignore 1 lines; 导csv: 复制代码 代码如下: SELECT * INTO OUTFILE '/test.csv'  FIELDS TERMIN

  • mysql导入导出数据中文乱码解决方法小结

    linux系统中 linux默认的是utf8编码,而windows是gbk编码,所以会出现上面的乱码问题. 解决mysql导入导出数据乱码问题 首先要做的是要确定你导出数据的编码格式,使用mysqldump的时候需要加上--default-character-set=utf8, 例如下面的代码: 复制代码 代码如下: mysqldump -uroot -p --default-character-set=utf8 dbname tablename > bak.sql 那么导入数据的时候也要使用-

  • JSP+ MySQL中文乱码问题post提交乱码解决方案

    写了两个jsp页面index.jsp和mysql_insert.jsp.数据处理流程为:在浏览器(chrome)上访问index.jsp后在其表单上输入数据,提交至mysql_insert.jsp,mysql_insert.jsp首先将接收到的数据按变量存入MySQL的html_db数据库的person_tb中(该表原有部分数据),然后mysql_insert.jsp再拿出该表中所有数据显示在mysql_insert.jsp页面上. 现在发现,当提交的数据中含有中文(比如变量姓名的值为中文)时,

  • 实战mysql导出中文乱码及phpmyadmin导入中文乱码的解决方法

    一直不用这个phpmyadmin,在本机也是用navicat,总感觉phpmyadmin速度较慢.这回不行了,没有独立主机,只好用人家给的phpmyadmin了. 第一步:本地数据导出sql文件.心想这对于navicat小事一桩.直接在数据库上右键"转储sql"(如图1),哗哗,十几秒的时间导出成功. (图1:navicat下对整个数据库转sql) 用记事本打开一看,傻眼了.中文全是乱码.咋回事呢?搜索了一下,改变什么连接属性啥的.不管用.试着在单张表上,转储sql,嘿,中文正常.但是

  • Mysql中文乱码以及导出为sql语句和Excel问题解决方法[图文]

    一.导出数据. 先说明一下自己的环境:Mac OS X 10.8.3, MySQL Community Server 5.6.10, MySQL Workbench 5.2.47. 我想把本机数据库内的数据迁移到另一台机器上,于是使用Workbench中自带的import/export功能,其实就是调用mysqldump.不幸的是,出现了版本不一致的错误. 错误没治了,最终找到解决方案,可以指定mysql的mysqldump,路径为:/usr/local/mysql/bin/mysqldump,

  • 常见php与mysql中文乱码问题解决办法

    乱码问题1:用PHPmyAdmin操作MySQL数据库汉字显示正常,但用PHP网页显示MySQL数据时所有汉字都变成了?号. 症状:用PHPmyAdmin输入汉字正常,但当PHP网页显示MySQL数据时汉字就变成了?号,并且有多少个汉字就有多少个?号. 原因:没有在PHP网页中用代码告诉MySQL该以什么字符集输出汉字. 解决方法: 1.网页文件head设置编码<meta http-equiv="Content-Type" content="text/html; cha

  • Mysql 下中文乱码的问题解决方法总结

    解决Mysql下中文乱码全是问号的问题 又是头疼的中文乱码问题,刚开始我一直用的本地数据库测,这没问题啊,一点问题都没,但我忘记了安卓和web用的是服务器上我搭的数据库,测了一下,果然乱码了. 试了网上不少方法,虽然不知道具体哪个方法给弄好了,就都说一下吧 第一种方法 刚开始先检查MySQL数据库,发现正如网上所说,部分编码是latin1, 是如下的样子: 果断改啊 set character_set_client=utf8; set character_set_connection=utf8;

随机推荐