【问题标题】:How does PHP determine the character encoding in browser POST request data?PHP如何确定浏览器POST请求数据中的字符编码?
【发布时间】:2016-09-08 01:16:02
【问题描述】:

当浏览器在 POST 请求的正文中发送数据(即来自表单元素的 name=value 对)时,PHP 如何确定字符编码以便它可以正确地将位流解码为字符以供其内部使用?
我可以理解一些 PHP 不需要解码的任务,例如对于 SQL INSERT 查询,它可以简单地将数据/字符串传递给 DBMS,无需额外处理。
但是对于文本处理/正则表达式操作,我想 PHP 需要将比特流解码为字符,然后才能对其执行测试、模式匹配等。
此外,似乎因为编码是由浏览器决定的,PHP 将需要浏览器提供有关它用于对 POST 数据进行编码的字符集的指导。
期望此指导将出现在请求标头中,我设置了一个文本表单

<meta charset="utf-8">

在包含表单的网页的头部,然后在输入一些值并提交表单后,请求头中没有包含关于它如何编码 POST 数据的明显信息

POST /experiments/foo.php HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 57
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://localhost/experiments/how_does_php_encode_data_it_receives_from_browser.php
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

还是有其他事情发生?例如浏览器是否希望将字符编码为某些预先确定的标准?
PHP 如何知道如何解码从浏览器 POST 请求接收到的数据?

【问题讨论】:

  • 密钥是Content-Type: application/x-www-form-urlencoded 见:w3.org/TR/html401/interact/forms.html#h-17.13.4
  • PHP 不会从网络请求中解码任何内容。网络服务器通常apache 处理请求并在需要时调用 PHP 解释器。浏览器告诉网络服务器它是如何对数据进行编码的,然后圆圈就开始了……
  • 基本上你应该已经知道预期的字符编码是什么,并配置 PHP 以接受该编码。

标签: php encoding


【解决方案1】:

关于 GET 数据,W3C standard states

注意。 “get”方法将表单数据集的值限制为 ASCII 字符。
只有“post”方法(使用 enctype="multipart/form-data")被指定覆盖整个 [ISO10646] 字符集。

因此,使用 GET 浏览器似乎被锁定为 ASCII,如果表单元素具有属性 enctype="multipart/form-data",则标准似乎支持更大的字符集 [ISO10646]
而且我猜是因为它更接近于纯比特流,application/x-www-form-url-encoded 的默认Content-type 支持所有字符编码。特别是这篇文章指出:
http://www.herongyang.com/PHP/Non-ASCII-Form-Basic-Rules.html

URL 编码将所有非 ASCII 字节转换成“%xx”的形式,“xx”是字节的 HEX 值。

所以这似乎解释了浏览器可能发送的字符集,而不是它如何指示 PHP 发送的实际字符集。 (除了 GET,PHP 知道它只能是 ASCII)。 ○ 其他方面,据我所知,浏览器基本上没有直接指导它发送的表单数据的字符编码。
不过我可能是错的,并且会对这个理论的任何反馈/替代方案感兴趣。
否则,据我所知,该方案的完整性基本上依赖于服务器简单地“记住”什么

<meta charset="utf-8">

<form ... accept-charset="utf-8">

它发送给用户的值(并希望用户没有通过浏览器“设置”更改字符编码)并期望浏览器忠实地以该字符集发送后续请求。
所以换句话说,如果你的团队中有一个网页设计师负责 HTML,他们设置了 HTML 元标记&lt;meta charset="utf-8"&gt;,他们需要通知数据库管理员,嘿,你需要设置你的数据库模式,表等需要 UTF-8 编码
这是因为服务器端开发人员/DBA 将无法动态检查编码(例如,如果表单提交来自不同国家/地区的用户,其浏览器可能设置为不同的字符集)。
并可能拒绝或记录警告等...
基本上,开发人员似乎需要为每个包含表单的 HTML 页面显式设置字符集,例如使用&lt;meta charset="utf-8"&gt;,然后只相信浏览器会以与包含表单的 HTML 编码相同的字符集发送 POST 数据。

进一步阅读

【讨论】:

  • 的值如果存在 content-type: text/html 则被忽略; charset=... HTTP 标头
【解决方案2】:

来自 PHP.net - 核心 php.ini 指令的描述:

default_charset字符串

从 PHP 5.6 开始,“UTF-8”是默认值,如果省略 encoding 参数,则其值用作 htmlentities()、html_entity_decode() 和 htmlspecialchars() 的默认字符编码。如果未设置 iconv.input_encoding、iconv.output_encoding 和 iconv.internal_encoding 配置选项,default_charset 的值也将用于设置 iconv 函数的默认字符集,如果 mbstring.http_input mbstring.http_output mbstring.internal_encoding 配置选项,则使用 mbstring 函数设置默认字符集配置选项未设置。

如果标头未被调用 header() 覆盖,所有版本的 PHP 都将使用此值作为 PHP 发送的默认 Content-Type 标头中的字符集。

例子:

Content-Type: text/html; charset=UTF-8

标记仅对没有此标头的响应有用。但是因为 content-type 标头的优先级高于 meta 标签,而且 PHP 总是添加这个标头,所以 mega 标签 charset 属性的值被忽略了。

当您使用 method=POST(或 GET)提交表单时,它的 URL 会在声明的字符集中对名称-值对进行编码,并将它们添加到 POST 请求的正文中。然后 PHP 再次解码它们并将它们添加到仍然在声明的字符集中的 $_POST 数组中。 (通常这将是 UTF-8。)

PHP 的内部函数基于 php.ini 中的设置工作。例如,如果 default_charset 设置为 UTF-8,则 htmlspecialchars 之类的函数在传递包含任何无效 UTF-8 字节序列的字符串时将返回一个空字符串。来自 PHP.net:

Return Values

转换后的字符串

如果输入字符串在给定编码中包含无效的代码单元序列,则将返回空字符串,除非设置了 ENT_IGNORE 或 ENT_SUBSTITUTE 标志。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    相关资源
    最近更新 更多