如何在PHP中正确处理UTF-8


How to properly handle UTF-8 in PHP?

我试图让我们的聊天系统支持UTF-8,但我失败了。如果在客户端,我通过encodeURIComponent:发送以下消息

  • îûó

把这个放在PHP端:

error_log(print_r(array(
    $_POST['message'],
    urldecode($_POST['message']),
    rawurldecode($_POST['message']),
    utf8_decode($_POST['message']),
    utf8_decode(urldecode($_POST['message'])),
    utf8_decode(rawurldecode($_POST['message']))
), true));

这是我的错误日志中的输出:

Array
(
    [0] => %C3%AE%C3%BB%C3%B4%C3%B3
    [1] => îûôó
    [2] => îûôó
    [3] => %C3%AE%C3%BB%C3%B4%C3%B3
    [4] => îûôó
    [5] => îûôó
)

所以一切都很好。然而,如果我使用这些,都是从维基百科(分别是俄语和日语页面(复制的:

  • 日本語

一切都见鬼去吧!

Array
(
    [0] => %D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%20%D1%8F%D0%B7%D1%8B%D0%BA
    [1] => руÑÑкий Ñзык
    [2] => руÑÑкий Ñзык
    [3] => %D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%20%D1%8F%D0%B7%D1%8B%D0%BA
    [4] => ??????? ????
    [5] => ??????? ????
)
Array
(
    [0] => %E6%97%A5%E6%9C%AC%E8%AA%9E
    [1] => 日本語
    [2] => 日本語
    [3] => %E6%97%A5%E6%9C%AC%E8%AA%9E
    [4] => ???
    [5] => ???
)

我需要做些什么才能让它发挥作用?

$_POST['message'], => [0] => %C3%AE%C3%BB%C3%B4%C3%B3

您对输入进行了URL编码。GET/POST/REQUEST超级全局变量已经在必要时负责对输入字符串进行URL解码,您不需要手动对其进行URL解码。

查看导致此请求的原因(XMLHttpRequest?(,并删除对encodeURIComponent()的多余调用。例如,如果您使用jQuery ajax()并将POST数据作为对象传入,那么jQuery将为您调用encodeURIComponent(),您也不需要自己调用。

urldecode($_POST['message']), => îûôó

这是UTF-8,被误解为Windows代码页1252(西欧,类似于ISO-8859-1(。

很可能您已经成功地将UTF-8字节保存到日志文件中,但无论您在其中读取日志文件,都没有意识到它应该呈现为UTF-8。

utf8_decode(urldecode($_POST['message'])), => îûôó

这只是因为你用来测试它的字符也存在于代码页1252中。CCD_ 5命名错误;它实际做的是将UTF-8字节序列转换为表示相同字符串的ISO-8859-1字节序列。您通常希望使用UTF-8而不是ISO-8859-1,因此通常应该避免使用utf8_decode。

русский язык => ??????? ????

可以理解:代码页1252中不存在西里尔字母。

假设您正在将error_log输出发送到一个文件,并尝试读取该文件,请坚持使用纯UTF-8字节,并在一个体面的文本编辑器中读取日志,该编辑器可以让您查看和选择编码;理想情况下是一个默认为UTF-8的现代版本。或者,您可以通过保存为UTF-16或UTF-8并在开始时包含字节顺序标记来说服Notepad读取Unicode文件。(在UTF-8文件中包含BOM有点错误,但微软世界中的许多工具都这样做。(

在整个堆栈中使用UTF8:

  • 数据库表
  • 数据库连接
  • PHP默认字符集设置
  • 字符串函数

数据库表:

将数据库排序规则设置为utf8_unicode_ci
将所有text/varchar字段设置为utf8_unicode_ci
通过执行以下查询将数据库连接设置为UTF-8:

SET NAMES 'utf8'

PHP字符集

用途:

ini_set('default_charset', 'utf-8'); 

PHP字符串函数

有些PHP字符串函数不是二进制安全的,因此您需要使用等效的mb_*。

例如mb_strlen而不是strlen

HTML:

使用元标记设置字符集:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">