提问者:小点点

UTF-8一路过关斩将


我正在设置一个新的服务器,并且希望在我的web应用程序中完全支持UTF-8。 我以前在现有的服务器上尝试过这一点,但似乎总是最终不得不退回到ISO-8859-1。

我需要在哪里设置编码/字符集? 我知道我需要配置Apache,MySQL和PHP来实现这一点--是否有一些标准的检查表可以遵循,或者可能是在不匹配的地方进行故障排除?

这是一个新的Linux服务器,运行MySQL5,PHP,5和Apache2。


共3个答案

匿名用户

数据存储:

>

  • 指定数据库中所有表和文本列的UTF8MB4字符集。 这使得MySQL物理地存储和检索UTF-8中本机编码的值。 请注意,如果指定了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_charsetPHP.ini选项,或者自己手动发出content-typeMIME头,这只是更多的工作,但具有相同的效果。

    当使用json_encode()编码输出时,添加json_unescaped_unicode作为第二个参数。

    输入:

    >

  • 不幸的是,在尝试存储或在任何地方使用它之前,您应该验证每个接收到的字符串是否是有效的UTF-8。 PHP的mb_check_encoding()完成了这一任务,但您必须严格使用它。 这确实是没有办法避免的,因为恶意客户机可以以他们想要的任何编码提交数据,而我还没有找到让PHP可靠地为您完成这一任务的诀窍。

    根据我对当前HTML规范的阅读,下面的子项目符号对于现代HTML来说不再是必要的,甚至不再是有效的。 我的理解是,浏览器将使用并提交为文档指定的字符集中的数据。 但是,如果您针对的是较旧版本的HTML(XHTML,HTML4等),以下几点可能仍然有用:

    • 仅适用于HTML5之前的HTML:您希望浏览器发送给您的所有数据都采用UTF-8格式。 不幸的是,如果您按此方法操作,唯一可靠的方法是将accept-charset属性添加到所有
      标记中:.
    • 仅适用于HTML5之前的HTML:请注意,W3C HTML规范规定,客户机“应该”默认将表单发送回服务器,使用服务器提供的任何字符集,但这显然只是一个建议,因此需要明确显示每个标记。

    其他代码注意事项:

    >

  • 显然,您将提供的所有文件(PHP,HTML,JavaScript等)都应该用有效的UTF-8编码。

    您需要确保每次处理UTF-8字符串时都是安全的。 不幸的是,这是最困难的部分。 您可能希望广泛使用PHP的MBString扩展。

    PHP的内置字符串操作在缺省情况下不是UTF-8安全的。 对于正常的PHP字符串操作(如连接),您可以安全地执行一些事情,但是对于大多数事情,您应该使用等效的mbstring函数。

    要知道你在做什么(不要搞砸),你真的需要知道UTF-8以及它是如何在最低级别上工作的。 查看utf8.com的任何链接,获取一些好的资源,以了解您需要了解的一切。

  • 匿名用户

    我想对查佐马蒂库斯的精彩回答补充一点:

    也不要忘记META标记(就像这样,或者它的HTML4或XHTML版本):

    <meta charset="utf-8">
    

    这看起来微不足道,但IE7以前也给我出过问题。

    我做的每件事都是对的; 数据库,数据库连接和内容类型HTTP头都被设置为UTF-8,并且它在所有其他浏览器中都能很好地工作,但是Internet Explorer仍然坚持使用“西欧”编码。

    结果发现页面丢失了META标记。 补充说这解决了问题。

    编辑:

    W3C实际上有一个相当大的部分专门用于i18n。 他们有许多与这个问题相关的文章-描述HTTP,(X)HTML和CSS方面的内容:

    • 常见问题:将(X)HTML页面编码更改为UTF-8
    • 在HTML中声明字符编码
    • 教程:字符集和; XHTML,HTML和CSS中的编码
    • 设置HTTP字符集参数

    他们建议同时使用HTTP头和HTML元标记(或者在XHTML作为XML的情况下使用XML声明)。

    匿名用户

    除了在php.ini中设置default_charset之外,还可以在任何输出之前,在代码内使用header()发送正确的字符集:

    header('Content-Type: text/html; charset=utf-8');
    

    在PHP中使用Unicode是很容易的,只要您认识到大多数字符串函数不使用Unicode,有些可能会完全破坏字符串。 PHP认为“字符”为1字节长。 有时这是可以的(例如,explode()只查找字节序列并将其用作分隔符--因此您查找的实际字符并不重要)。 但在其他时候,当函数被设计为处理字符时,PHP并不知道您的文本中有Unicode中的多字节字符。

    要签入的一个很好的库是phputf8。 这将重写所有“坏”函数,以便您可以安全地处理UTF8字符串。 也有像mbstring扩展这样的扩展试图为您实现这一点,但我更喜欢使用库,因为它更可移植(但我编写的是大众市场产品,所以这对我很重要)。 但无论如何,phputf8可以在幕后使用mbstring来提高性能。