客户端POST提交JSON给PHP的问题

80 篇文章 6 订阅
6 篇文章 1 订阅

注:这是我去年写在知乎里的文章。后来要查阅,来CSDN博客里翻了底朝天都没找到,甚至一度怀疑CSDN丢文章。特此转发已备后用。另外发现在知乎的原文好像已经不能编辑了,而我又需要编辑它,这是转发至此的又一个理由。

原文

我前两天(当时时间是2017年1月)用易语言写一个(原以为很简单的)客户端软件,将JSON文本POST给PHP,Content-Typeapplication/json,内容就是JSON文本。结果PHP的同事把整个$_POST都输出看了,里面根本就没有数据。我郁闷了很久。后来各种尝试,最后把Content-Type改成application/x-www-form-urlencoded,把POST内容改为data=json形式,并且对json部分应用URL编码,才搞定了与PHP的通讯。但依然很迷惑。

后来我专程去查了$_POST的官方文档,人家说的很明白,只有Content-Typeapplication/x-www-form-urlencodedmultipart/form-data的情况下,$_POST里面才有值。在其他情况下,$_POST里面是没有值的。

对于客户端POST提交的 Content-Type: application/json 的情况,或其他未明确指定 Content-Type 的情况,PHP可以用 file_get_contents("php://input"); 读出POST进来的数据。(作者注:本文末尾有 php://input 的说明文档,带官方链接。)

现在总算明白了。


以下是 20180807 Liigo补记:

呵呵,有点尴尬呀。前面说“现在总算明白了”,事实证明还是有点不太明白。

后来又发现了奇怪的现象。客户端POST提交GB18030编码的带汉字的文本,PHP端用file_get_contents("php://input") 接收然后用 file_put_contents() 写出文件,用文本编辑器打开文件显示正常。而如果客户端POST提交UTF-8编码的相同内容的文本,PHP端用相同的方法接收和写出文件,用文本编辑器打开文件就是乱码。后来证明文本编辑器的编码识别没有问题,进而证明第二次写出的文件编码即不是UTF-8也不是GB18030。这就很奇怪。

我心中提出了几个问题:

  • file_get_contents("php://input") 视其输入数据为什么编码?其输出数据是什么编码?内部有没有进行过编码转换?
  • file_put_contents() 写出文件的过程中有没有编码转换?其输入和输出数据各是什么编码呢?
  • 前面提到的POST提交数据时没有明确指定Content-Type ,结果是否于此有关呢?
  • 第一次POST的编码是GB18030,写出的文件编码也是GB18030,这能说明什么呢?

多个问号有待解答。


最基础的测试代码

PHP端代码:

echo file_get_contents("php://input");

易语言端代码:

respone = 网页_访问_对象 (url, 1, "POST数据")
调试输出 (respone, 编码_Utf8到Ansi (respone), 到文本 (respone))

目前能确认的结论是:(在上述情况下)POST只能提交GB18030编码,不能提交UTF-8编码,否则得到的结果是乱码。

在提交GB18030编码的情况下(情况1),PHP网页返回的是UTF-8编码的Respone(估计是 echo 默认输出UTF-8),转换为GB18030后,还原为原始的数据,结果是正确的。在提交UTF-8编码的情况下(情况2),PHP网页返回的数据不知道是什么编码,既不是UTF-8也不是GB18030,怎么转换结果都不对。仔细校验后发现,情况2返回的respone数据是在UTF-8编码基础上再执行UTF-8编码的结果,由此可以断定,PHP是把客户端提交的UTF-8编码的数据当作GB18030编码处理了。

客户端POST提交数据时并没有明确指定数据编码,故PHP假定其为某个编码(此处为GB18030,估计跟PHP配置有关)也有其合理性。那么POST提交时能否指定编码呢?好像是有,Content-Type: application/json; charset=utf-8 。然而好像并不管用:

post = “A汉字Z”
post = 编码_gb2312到utf8 (post)
headers = “Content-Type: application/json; charset=utf-8”
respone = 网页_访问_对象 (“http://yishoudan.com/m/order/test”, 1, post, , , headers)
调试输出 (respone, 编码_Utf8到Ansi (respone), 到文本 (respone))

php://input

下面补充一些 php://input 的官方文档:

php://input is a read-only stream that allows you to read raw data from the request body. In the case of POST requests, it is preferable to use php://input instead of $HTTP_RAW_POST_DATA as it does not depend on special php.ini directives. Moreover, for those cases where $HTTP_RAW_POST_DATA is not populated by default, it is a potentially less memory intensive alternative to activating always_populate_raw_post_data. php://input is not available with enctype="multipart/form-data".

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值