PHP如何确定浏览器POST请求数据中的字符编码?

时间:2016-09-08 01:16:02

标签: php encoding

当浏览器在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请求中收到的数据?

2 个答案:

答案 0 :(得分:0)

关于GET数据,W3C standard states

  

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

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

  

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

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

<meta charset="utf-8">

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

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

进一步阅读

答案 1 :(得分:0)

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

default_charset字符串

在PHP 5.6及更高版本中,“ UTF-8”是默认值,如果省略了编码参数,则将其值用作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未被设置,则default_charset的值也将用于mbstring函数。配置选项未设置。

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

示例:

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

标记仅对没有此标头的响应有用。但是,因为content-type标头的优先级高于meta标签,并且PHP始终添加此标头,所以将忽略mega tag 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标志。