我正在搭建一台新的服务器,希望我的Web应用程序完全支持UTF-8编码。我曾在现有的服务器上尝试过这种设置,但似乎总是不得不退回到ISO-8859-1编码。
我需要在哪些地方设置编码/字符集呢?我知道需要配置Apache、MySQL和PHP来实现这个功能——是否有一份标准的清单可以供我遵循,或者可以通过排除错误的方式找到问题出现的地方呢?
这是一个运行MySQL 5、PHP 5和Apache 2的新Linux服务器。
数据存储:
在数据库中的所有表和文本列上指定utf8mb4
字符集。这使得MySQL可以原生地存储和检索以UTF-8编码的值。请注意,如果指定了utf8mb4_*
排序规则(没有任何显式字符集),MySQL将隐式使用utf8mb4
编码。
在旧版本的MySQL(< 5.5.3)中,你只能使用仅支持Unicode字符子集的utf8
,这是不幸的事实。我希望我是在开玩笑。
数据访问:
In your application code (e.g. PHP), in whatever DB access method you use, you'll need to set the connection charset to utf8mb4
. This way, MySQL does no conversion from its native UTF-8 when it hands data off to your application and vice versa.
Some drivers provide their own mechanism for configuring the connection character set, which both updates its own internal state and informs MySQL of the encoding to be used on the connection—this is usually the preferred approach. In PHP:
If you're using the PDO abstraction layer with PHP ≥ 5.3.6, you can specify charset
in the DSN:
$dbh = new PDO('mysql:charset=utf8mb4');
If you're using mysqli, you can call set_charset()
:
$mysqli->set_charset('utf8mb4'); // object oriented style
mysqli_set_charset($link, 'utf8mb4'); // procedural style
If you're stuck with plain mysql but happen to be running PHP ≥ 5.2.3, you can call mysql_set_charset
.
If the driver does not provide its own mechanism for setting the connection character set, you may have to issue a query to tell MySQL how your application expects data on the connection to be encoded: SET NAMES 'utf8mb4'
.
The same consideration regarding utf8mb4
/utf8
applies as above.
输出:
Content-Type: text/html; charset=utf-8
。您可以通过在php.ini中设置default_charset
(首选)或手动使用header()
函数来实现。json_encode()
进行输出编码时,将JSON_UNESCAPED_UNICODE
作为第二个参数添加。输入:
mb_check_encoding()
可以完成这项工作,但您必须坚持使用它。恶意客户端可以以任何编码方式提交数据,因此确实没有绕过此问题的方法,我还没有找到一个可靠的方法让PHP为您完成这项工作。其他代码注意事项:
我想在chazomaticus的优秀回答中补充一点内容:
不要忘记META标签(像这样,或者它的HTML4或XHTML版本):
<meta charset="utf-8">
看起来很琐碎,但IE7以前曾给我带来过问题。
我做了所有正确的事情:数据库、数据库连接和Content-Type HTTP标头都设置为UTF-8,在所有其他浏览器中都正常工作,但Internet Explorer仍然坚持使用“西欧”编码。
原来页面缺少META标签。添加后问题得到解决。
编辑:
实际上,W3C有一个相当大的I18N部分。他们有许多与此问题相关的文章 - 描述了HTTP、(X)HTML和CSS方面的内容:
他们建议同时使用HTTP标头和HTML元标签(在作为XML提供的XHTML的情况下使用XML声明)。
除了在php.ini中设置default_charset
外,您还可以在代码中使用header()
在任何输出之前发送正确的字符集:
header('Content-Type: text/html; charset=utf-8');
警告:本回答仅适用于PHP 5.3.5及以下版本。请勿在PHP版本5.3.6(于2011年3月发布)或更高版本中使用。
我发现有人在使用PDO时出现了问题,解决方法是使用以下PDO连接字符串:
$pdo = new PDO(
'mysql:host=mysql.example.com;dbname=example_db',
"username",
"password",
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$dbh->exec("set names utf8");
;我更喜欢这里介绍的方法)。顺便说一下,在PHP手册中也有类似的注释:http://php.net/manual/en/pdo.construct.php#96325。 - Marten Koetsier mb_split
函数,它使用正则表达式。因此,我还需要手动确保正则表达式的编码是UTF-8,通过执行 mb_regex_encoding('UTF-8')
来实现。 mb_internal_encoding()
,内部编码不是UTF-8,所以我通过运行 mb_internal_encoding("UTF-8")
进行更改。首先,如果你使用的是 PHP 版本 5.3 之前的话,那就不行。你需要处理大量的问题。
我惊讶地发现没有人提到 intl 库,这个库对于 Unicode、图形字符、字符串操作、本地化 等拥有良好的支持,详情请参见下文。
我将引用 Elizabeth Smith 在 PHPBenelux'14 上的演讲幻灯片中关于 PHP 的 Unicode 支持的一些信息。
优点:
缺点:
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd
选项编译 php,则可以使用 mysqlnd 驱动程序。 - Alexander Yancharuk除了这些精彩的回答,我想强调一下保存文件时需要采用UTF-8编码,因为我发现浏览器接受该属性优于设置UTF-8作为代码编码。任何一个体面的文本编辑器都会显示这个。例如,Notepad++ 有一个文件编码的菜单选项,它会显示当前编码并允许您更改它。对于我所有的PHP文件,我都使用不带BOM的UTF-8。
以前,有人请我为某人设计的PHP和MySQL应用程序添加UTF-8支持。我发现所有文件都是用ANSI编码的,所以我必须使用iconv转换所有文件,将数据库表更改为使用UTF-8字符集和utf8_general_ci校对,连接后在数据库抽象层中添加'SET NAMES utf8'(如果使用5.3.6或更早版本。否则,您必须在连接字符串中使用charset=utf8),并更改字符串函数以使用PHP多字节字符串功能的等效方式。
我最近发现使用strtolower()
可能会导致数据在特殊字符后被截断。
解决方案是使用
mb_strtolower($string, 'UTF-8');
mb_ 使用 MultiByte。它支持更多的字符,但一般来说速度稍慢。
我刚刚遇到了同样的问题,并在PHP手册中找到了一个好的解决方案。
我将所有文件的编码都改为UTF8,然后将连接的默认编码也改为UTF8。这解决了所有问题。
if (!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
printf("Current character set: %s\n", $mysqli->character_set_name());
}
set_charset('utf8mb4')
没有起作用,但是 set_charset("utf8")
起了作用,而其他答案中实际上没有显示这一点。 - Funk Forty Ninerset_charset("utf8")
可能会起作用,但行为会有所不同(请参阅有关 utf8
和 utf8mb4
之间差异以及 mysql 版本历史的说明)。仅在您知道自己在做什么时使用 utf8
! - Martin Hennings
utf-8
- MySQL 5、PHP 5 或 Apache 2。 - Manish Shrivastavaset time_zone='+0:00'
)作为服务器默认值。 - dolmen