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

注:这是我去年写在知乎里的文章。后来要查阅,来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也不是GB8030。这就很奇怪。

我心中提出了几个问题:

  • 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编码的情况下,PHP网页返回的是UTF-8编码的Respone,转换为GB18030后,还原为原始的数据,结果是正确的。在提交UTF-8编码的情况下,PHP网页返回的数据不知道是什么编码,即不是UTF-8也不是GB18030,怎么转换结果都不对。

大写的问号。


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".

猜你喜欢

转载自blog.csdn.net/liigo/article/details/81485282