我正在设置一个新服务器,并希望在我的 Web 应用程序中完全支持 UTF-8。我过去曾在现有的服务器上尝试过此操作,但最终似乎不得不回归 ISO-8859-1。
我在哪里需要设置编码 / 字符集?我知道我需要配置 Apache,MySQL 和 PHP 来执行此操作 - 是否有一些我可以遵循的标准清单,或者可能是在出现不匹配的地方进行故障排除?
这适用于运行 MySQL 5,PHP,5 和 Apache 2 的新 Linux 服务器。
数据存储 :
在数据库的所有表和文本列上指定utf8mb4
字符集。这使得 MySQL 物理存储和检索以 UTF-8 本地编码的值。请注意,如果指定了utf8mb4_*
排序utf8mb4
,MySQL 将隐式使用utf8mb4
编码(没有任何显式字符集)。
在旧版本的 MySQL(<5.5.3)中,遗憾的是,您只能使用utf8
,它只支持 Unicode 字符的子集。我希望我在开玩笑。
数据访问 :
在您的应用程序代码(例如 PHP)中,无论您使用何种 DB 访问方法,都需要将连接字符集设置为utf8mb4
。这样,当 MySQL 将数据移交给您的应用程序时,MySQL 不会从其原生 UTF-8 进行转换,反之亦然。
一些驱动程序提供了自己的配置连接字符集的机制,它们都更新了自己的内部状态,并通知 MySQL 要在连接上使用的编码 - 这通常是首选方法。在 PHP 中:
如果您使用PHP≥5.3.6 的 PDO抽象层,则可以在DSN 中指定charset
:
$dbh = new PDO('mysql:charset=utf8mb4');
如果您使用的是mysqli ,则可以调用set_charset()
:
$mysqli->set_charset('utf8mb4'); // object oriented style
mysqli_set_charset($link, 'utf8mb4'); // procedural style
如果您遇到普通的mysql但碰巧运行 PHP≥5.2.3,则可以调用mysql_set_charset
。
如果驱动程序没有提供自己的设置连接字符集的机制,则可能必须发出一个查询来告诉 MySQL 应用程序如何期望连接上的数据被编码: SET NAMES 'utf8mb4'
。
关于utf8mb4
/ utf8
的相同考虑如上所述。
输出 :
如果您的应用程序将文本传输到其他系统,则还需要告知它们字符编码。对于 Web 应用程序,必须通知浏览器发送数据的编码(通过 HTTP 响应头或HTML 元数据 )。
在 PHP 中,您可以使用default_charset
php.ini 选项,或者自己手动发出Content-Type
MIME 标头,这只是更多工作但具有相同的效果。
输入 :
不幸的是,在尝试存储或在任何地方使用它之前,您应该将每个收到的字符串验证为有效的 UTF-8。 PHP 的mb_check_encoding()
可以解决问题,但你必须虔诚地使用它。真的没办法解决这个问题,因为恶意客户端可以用他们想要的任何编码提交数据,而且我还没有找到让 PHP 可靠地为你做这件事的技巧。
从我对当前HTML 规范的阅读中,对于现代HTML ,以下子项目不再是必需的,甚至不再有效。我的理解是浏览器将使用为文档指定的字符集中的数据并提交数据。但是,如果您要定位旧版本的 HTML(XHTML,HTML4 等),这些点可能仍然有用:
accept-charset
属性添加到你的所有<form>
标签: <form ... accept-charset="UTF-8">
。 <form>
标签。 其他代码注意事项 :
显然,你要服务的所有文件(PHP,HTML,JavaScript 等)都应该用有效的 UTF-8 编码。
您需要确保每次处理 UTF-8 字符串时都安全地执行此操作。不幸的是,这是困难的部分。您可能希望广泛使用 PHP 的mbstring
扩展。
PHP 的内置字符串操作默认情况下不是 UTF-8 安全的。对于普通的 PHP 字符串操作(如串联),您可以安全地执行某些操作,但对于大多数情况,您应该使用等效的mbstring
函数。
要知道你在做什么(阅读:不要搞砸了),你真的需要知道 UTF-8 以及它如何在尽可能低的水平上运行。查看来自utf8.com 的任何链接,获取一些很好的资源,以了解您需要了解的所有信息。
我想在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 元标记(或者在 XHTML 作为 XML 的情况下使用 XML 声明)。
除了在 php.ini 中设置default_charset
之外,您还可以在任何输出之前使用代码中的header()
发送正确的字符集:
header('Content-Type: text/html; charset=utf-8');
只要您意识到大多数字符串函数不能与 Unicode 一起使用,并且有些函数可能会完全破坏字符串 ,那么在 PHP 中使用 Unicode 很容易。 PHP 认为 “字符” 长度为 1 个字节。有时这是可以的(例如, explode()
只查找一个字节序列并将其用作分隔符 - 所以你寻找的实际字符并不重要)。但有时候,当函数实际设计用于处理字符时 ,PHP 不知道你的文本有多字节字符,可以用 Unicode 找到。
一个很好的图书馆是phputf8 。这会重写所有 “坏” 函数,以便您可以安全地处理 UTF8 字符串。有像 mbstring 扩展这样的扩展试图为你做这个,但我更喜欢使用库,因为它更便携(但我写大众市场的产品,所以这对我很重要)。但是,无论如何,phputf8 可以在幕后使用 mbstring 来提高性能。