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

时间:2011-11-01 17:11:04

标签: php javascript encoding utf-8 encodeuricomponent

我正在努力让我们的聊天系统支持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] => ???
)

我需要做些什么来完成这项工作?

2 个答案:

答案 0 :(得分:2)

在整个堆栈中使用UTF8:

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

数据库表:

将db collat​​ion设置为utf8_unicode_ci 将所有text / varchar字段设置为utf8_unicode_ci 通过执行以下查询将数据库连接设置为UTF-8:

SET NAMES 'utf8'

PHP Charset

使用:

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

PHP字符串函数

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

e.g。 mb_strlen代替strlen

HTML:

使用元标记设置字符集:

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

答案 1 :(得分:2)

$_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中。utf8_decode被误导地命名;它实际上做的是将UTF-8字节序列转换为表示相同字符串的ISO-8859-1字节序列。您通常希望使用UTF-8而不是ISO-8859-1,因此通常应避免使用utf8_decode。

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

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

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