一、遇到的问题

曾经被字符集间复杂的转换搞怕了,正好新项目要求国际化,需要能够显示多种语言,于是一开始就规定统统使用 UTF-8 编码。

  1. 所有代码文件使用 UTF-8 编码存盘
  2. MySQL数据库所有表,所有字段设置 Collation (中文翻译为“整理”?)属性为 “utf8_general_ci”
  3. 所有页面输出
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

即便是这样,PHP 从数据库中读取内容,显示到网页上,还是出现了乱码,英文没问题,中文统统都是?问号。这样也行?艰苦卓绝的 debug 开始了……

开始debug

二、调查原因

MySQL 的字符集以繁多而著名,而其默认又是 latin1 的瑞典语编码,数据导入导出的时候一不留神就乱码了。

参考以上链接的官方文档,总结之:MySQL 对于字符集的支持细化到四个层次:

  1. server 服务器级
  2. database 数据库级
  3. table 表级
  4. connection 连接级

确保每一个级别都是使用的 UTF-8 编码。检查了一下,貌似我没有设置 connection 连接级。前三种字符集级别只是规定了数据存储在 MySQL 中的编码格式,客户端读出数据后完全可以按照自己的意愿来解读数据。最后的 connection 连接级就是规定了客户端以什么编码来解析读取到的数据。也就是说,不论是 php 代码还是 DB 管理软件,在从 MySQL 读取数据之前都需要设定自己作为客户端的编码格式。

思考中

好吧,那么,在任何查询执行之前,先执行一句 set names utf-8。(使用框架进行开发的话,大多数框架应该会自动完成这一步,程序员一般只需要改配置文件)

$conn = mysql_connect($db_host, $db_user, $db_password);
if(!$conn)
    die("Could not connect to mysql.");
mysql_select_db($db_name);
mysql_query("set names 'utf-8'");

刷新页面,仍旧乱码。

泪流满面

三、解决

只好再继续调查。¥#$…&%=^*&+%-#!@_@ 苦逼地一天就这样过去了……

咦,等等,官方文档里写的是 set names utf8 哦,和 set names utf-8 有啥区别么?赶紧试一下。

刷新页面,我擦,正常了。

WTF!!

搜了一下,发现被坑的人还真不少。UTF-8应该是标准的写法,在大多数场合都是有中间那个横杠的,只是MySQL这里偏偏就非主流去掉了横杠使用UTF8。

遇到同样问题,而本文未能帮你解决的,这篇乱码总结可能会帮到你。