PHP“php://输入”与 $_POST
在与 JQuery 的 Ajax 请求交互时,我被指示使用 php://input
方法而不是 $_POST
。我不明白的是使用此方法与 $_POST
或 $_GET
的全局方法相比有何好处。
I have been directed to use the method php://input
instead of $_POST
when interacting with Ajax requests from JQuery. What I do not understand is the benefits of using this vs the global method of $_POST
or $_GET
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
原因是
php://input
返回请求的 HTTP 标头之后的所有原始数据,无论内容类型如何。PHP 超全局
$_POST
,只有应该包装application/x-www-form-urlencoded
的数据(标准内容类型simple form-posts) 或multipart/form-data
(主要用于文件上传)这是因为这些是必须由用户代理支持。因此,服务器和 PHP 传统上不期望接收任何其他内容类型(这并不意味着它们不能)。
因此,如果您只是 POST 一个旧的 HTML
form
,请求看起来像这样:但是如果您经常使用 Ajax,这个可能还包括与类型(string、int)交换更复杂的数据,bool)和结构体(数组,对象),所以在大多数情况下 JSON 是最好的选择。但是带有 JSON 负载的请求看起来像这样:
内容现在是
application/json
(或者至少不是上面提到的),所以 PHP 的$_POST
-wrapper 还不知道如何处理这个问题。数据仍然存在,只是无法通过包装器访问它。因此,您需要使用
file_get_contents('php://input')
以原始格式自行获取它 (只要它不是multipart/form-data
编码)。这也是您访问 XML 数据或任何其他非标准内容类型的方式。
The reason is that
php://input
returns all the raw data after the HTTP-headers of the request, regardless of the content type.The PHP superglobal
$_POST
, only is supposed to wrap data that is eitherapplication/x-www-form-urlencoded
(standard content type for simple form-posts) ormultipart/form-data
(mostly used for file uploads)This is because these are the only content types that must be supported by user agents. So the server and PHP traditionally don't expect to receive any other content type (which doesn't mean they couldn't).
So, if you simply POST a good old HTML
form
, the request looks something like this:But if you are working with Ajax a lot, this probaby also includes exchanging more complex data with types (string, int, bool) and structures (arrays, objects), so in most cases JSON is the best choice. But a request with a JSON-payload would look something like this:
The content would now be
application/json
(or at least none of the above mentioned), so PHP's$_POST
-wrapper doesn't know how to handle that (yet).The data is still there, you just can't access it through the wrapper. So you need to fetch it yourself in raw format with
file_get_contents('php://input')
(as long as it's notmultipart/form-data
-encoded).This is also how you would access XML-data or any other non-standard content type.
首先,了解有关 PHP 的基本事实。
PHP 的设计初衷并不是明确为您提供一个纯 REST(GET、POST、PUT、PATCH、DELETE)之类的接口来处理 HTTP 请求。
但是,
$_SERVER
、$_COOKIE
、$_POST
、$_GET
和$_FILES< /code> superglobals 和函数
filter_input_array()
非常有用满足普通人/外行的需求。$_POST
(和$_GET
)的第一个隐藏优势是您的输入数据由 PHP 自动进行 URL 解码。您甚至从未想过必须这样做,特别是对于标准GET
请求中的查询字符串参数,或通过POST
请求提交的 HTTP 正文数据。其他 HTTP 请求方法
研究 HTTP 底层协议及其各种请求方法的人都知道,HTTP 请求方法有很多种,包括经常引用的
PUT
、PATCH
(未使用过)在 Google 的 Apigee 中),以及DELETE
。在 PHP 中,当不使用
POST
时,没有超全局变量或输入过滤器函数用于获取 HTTP 请求正文数据。罗伊·菲尔丁的弟子们要做什么? ;-)但是,然后您会了解更多...
话虽这么说,当您提高 PHP 编程知识并想要使用 JavaScript 的
XmlHttpRequest
对象(对于某些人来说是 jQuery)时,您会看到局限性该计划的。$_POST
限制您在 HTTPContent-Type
标头中使用两种媒体类型:application/x-www-form-urlencoded
,和multipart/form-data
因此,如果您想将数据值发送到服务器上的 PHP,并让它显示在
$_POST
超级全局中,那么你必须urlencode 在客户端进行编码,并将所述数据作为键/值对发送 - 这是一个不方便的步骤对于新手(尤其是当试图弄清楚 URL 的不同部分是否需要不同形式的 urlencoding 时:正常、原始等)。对于所有 jQuery 用户来说,
$.ajax()
方法会将 JSON 转换为 URL 编码的键/值对,然后再将其传输到服务器。您可以通过设置processData: false
来覆盖此行为。只需阅读 $.ajax() 文档,并且不要忘记发送正确的媒体输入 Content-Type 标头。php://input,但是...
即使您使用
php://input
而不是$_POST
您的 HTTPPOST
请求正文数据,它不会 使用multipart/form-data
的 HTTPContent-Type
这是当您想要允许文件上传时在 HTML 表单上使用的内容类型!因此,在传统 PHP 中,要处理来自 HTTP
POST
请求的多种内容类型,您将学习使用$_POST
或filter_input_array(POST)< /code>、
$_FILES
和php://input
。在 PHP 中,无法仅使用一个通用输入源来处理 HTTPPOST
请求。无法通过
$_POST
、filter_input_array(POST)
、php://input
获取文件,也无法获取JSON/XML/YAML在filter_input_array(POST)
或$_POST
中。PHP 手册:php://input
PHP 框架来拯救?
像 Codeigniter 4 和 Laravel 这样的 PHP 框架使用 Facade 来为上述内容提供更清晰的接口(
IncomingRequest
或Request
对象)。这就是专业 PHP 开发人员使用框架而不是原始 PHP 的原因。当然,如果您喜欢编程,您可以设计自己的外观对象来提供框架的功能。正是因为我花了时间研究这个问题,所以我才能写下这个答案。
网址编码?到底什么啊!???
通常,如果您使用 HTML 表单执行正常的同步(当整个页面重绘时)HTTP 请求,用户代理(Web 浏览器)将为您对表单数据进行 urlencode。如果您想使用
XmlHttpRequest
对象执行异步 HTTP 请求,那么您必须创建一个 urlencoded 字符串并发送它,如果您希望该数据显示在$_POST 中
超全局。您对 JavaScript 的了解程度如何? :-)
从 JavaScript 数组或对象转换为 urlencoded 字符串困扰了许多开发人员(即使使用像 表单数据)。他们更愿意能够发送 JSON,并且客户端代码这样做会更高效。
请记住(眨眼,眨眼),普通 Web 开发人员不会像你我一样学习直接使用
XmlHttpRequest
对象、全局函数、字符串函数、数组函数和正则表达式;-)。 Urlencoding 对他们来说是一场噩梦。 ;-)PHP,给出了什么?
PHP 缺乏直观的 XML 和 JSON 处理,这让很多人望而却步。您可能会认为它现在已经成为 PHP 的一部分了(叹气)。
如此多的媒体类型(过去的 MIME 类型)
XML、JSON 和 YAML 都具有可以放入 HTTP
Content-Type
标头中的媒体类型。看看有多少 媒体类型(以前称为 MIME 类型)由 IANA 定义。
查看有多少个 HTTP 标头。
php://input 或
使用
php://input
流允许您绕过 PHP 强加给世界的“保姆/手持”抽象级别。 :-) 能力越大,责任越大!
现在,在处理通过
php://input
传输的数据值之前,您应该/必须做一些事情。PUT、PATCH、DELETE...)
类型。
等等。
目的。
那么字符编码呢?
啊,哈!是的,您可能希望发送到应用程序的数据流采用 UTF-8 编码,但您如何知道它是否是 UTF-8 编码?
两个关键问题。
php://input
传入。您是否打算在不知道流数据有多少的情况下尝试处理流数据? 这是一个糟糕的主意。您不能完全依赖 HTTP
Content-Length
标头来获取流输入大小的指导,因为它可能会被欺骗。您将需要:
您是否打算在不知道流的当前编码的情况下尝试将流数据转换为 UTF-8?如何? iconv 流过滤器 (iconv 流过滤器示例)似乎想要一个开始和结束编码,就像这样。
因此,如果你有良心,你将需要:
(更新:
'convert.iconv.UTF-8/UTF-8'
将强制所有内容为 UTF-8,但您仍然需要考虑 iconv 库中的字符换句话说,您必须定义当无法翻译字符时要采取的操作:1)插入虚拟字符,2)失败/抛出和异常)。您不能完全依赖 HTTP
Content-Encoding
标头,因为这可能表示类似压缩的内容,如下所示。这不是您想要对 iconv 做出决定的原因。因此,一般步骤可能是...
第一部分:HTTP 请求相关
PUT、PATCH、DELETE...)
类型。
第二部分:流数据相关
编码(UTF-8)。
第三部分:相关数据类型
等等
(请记住,数据仍然可以是 URL 编码的字符串,然后您必须对其进行解析和 URL 解码)。
目的。
第四部分:数据值相关
过滤输入数据。
验证输入数据。
现在你明白了吗?
$_POST
超全局以及用于限制输入的 php.ini 设置对于外行来说更简单。然而,使用流时处理字符编码更加直观和高效,因为不需要循环遍历超全局(或通常是数组)来检查输入值是否正确编码。First, a basic truth about PHP.
PHP was not designed to explicitly give you a pure REST (GET, POST, PUT, PATCH, DELETE) like interface for handling HTTP requests.
However, the
$_SERVER
,$_COOKIE
,$_POST
,$_GET
, and$_FILES
superglobals, and the functionfilter_input_array()
are very useful for the average person's / layman's needs.The number one hidden advantage of
$_POST
(and$_GET
) is that your input data is url-decoded automatically by PHP. You never even think about having to do it, especially for query string parameters within a standardGET
request, or HTTP body data submitted with aPOST
request.Other HTTP Request Methods
Those studying the underlying HTTP protocol and its various request methods come to understand that there are many HTTP request methods, including the often referenced
PUT
,PATCH
(not used in Google's Apigee), andDELETE
.In PHP, there are no superglobals or input filter functions for getting HTTP request body data when
POST
is not used. What are disciples of Roy Fielding to do? ;-)However, then you learn more ...
That being said, as you advance in your PHP programming knowledge and want to use JavaScript's
XmlHttpRequest
object (jQuery for some), you come to see the limitation of this scheme.$_POST
limits you to the use of two media types in the HTTPContent-Type
header:application/x-www-form-urlencoded
, andmultipart/form-data
Thus, if you want to send data values to PHP on the server, and have it show up in the
$_POST
superglobal, then you must urlencode it on the client-side and send said data as key/value pairs--an inconvenient step for novices (especially when trying to figure out if different parts of the URL require different forms of urlencoding: normal, raw, etc..).For all you jQuery users, the
$.ajax()
method is converting your JSON to URL encoded key/value pairs before transmitting them to the server. You can override this behavior by settingprocessData: false
. Just read the $.ajax() documentation, and don't forget to send the correct media type in the Content-Type header.php://input, but ...
Even if you use
php://input
instead of$_POST
for your HTTPPOST
request body data, it will not work with an HTTPContent-Type
ofmultipart/form-data
This is the content type that you use on an HTML form when you want to allow file uploads!Therefore, in traditional PHP, to deal with a diversity of content types from an HTTP
POST
request, you will learn to use$_POST
orfilter_input_array(POST)
,$_FILES
, andphp://input
. There is no way to just use one, universal input source for HTTPPOST
requests in PHP.You cannot get files through
$_POST
,filter_input_array(POST)
, orphp://input
, and you cannot get JSON/XML/YAML in eitherfilter_input_array(POST)
or$_POST
.PHP Manual: php://input
PHP Frameworks to the rescue?
PHP frameworks like Codeigniter 4 and Laravel use a facade to provide a cleaner interface (
IncomingRequest
orRequest
objects) to the above. This is why professional PHP developers use frameworks instead of raw PHP.Of course, if you like to program, you can devise your own facade object to provide what frameworks do. It is because I have taken time to investigate this issue that I am able to write this answer.
URL encoding? What the heck!!!???
Typically, if you are doing a normal, synchronous (when the entire page redraws) HTTP requests with an HTML form, the user-agent (web browser) will urlencode your form data for you. If you want to do an asynchronous HTTP requests using the
XmlHttpRequest
object, then you must fashion a urlencoded string and send it, if you want that data to show up in the$_POST
superglobal.How in touch are you with JavaScript? :-)
Converting from a JavaScript array or object to a urlencoded string bothers many developers (even with new APIs like Form Data). They would much rather just be able to send JSON, and it would be more efficient for the client code to do so.
Remember (wink, wink), the average web developer does not learn to use the
XmlHttpRequest
object directly, global functions, string functions, array functions, and regular expressions like you and I ;-). Urlencoding for them is a nightmare. ;-)PHP, what gives?
PHP's lack of intuitive XML and JSON handling turns many people off. You would think it would be part of PHP by now (sigh).
So many media types (MIME types in the past)
XML, JSON, and YAML all have media types that can be put into an HTTP
Content-Type
header.Look how many media-types (formerly, MIME types) are defined by IANA.
Look how many HTTP headers there are.
php://input or bust
Using the
php://input
stream allows you to circumvent the baby-sitting / hand holding level of abstraction that PHP has forced on the world. :-) With great power comes great responsibility!Now, before you deal with data values streamed through
php://input
, you should / must do a few things.PUT, PATCH, DELETE, ...)
type.
etc.
object.
What about the character encoding?
AH, HA! Yes, you might want the data stream being sent into your application to be UTF-8 encoded, but how can you know if it is or not?
Two critical problems.
php://input
.Are you going to attempt to handle stream data without knowing how much is there first? That is a terrible idea. You cannot rely exclusively on the HTTP
Content-Length
header for guidance on the size of streamed input because it can be spoofed.You are going to need a:
Are you going to attempt to convert stream data to UTF-8 without knowing the current encoding of the stream? How? The iconv stream filter (iconv stream filter example) seems to want a starting and ending encoding, like this.
Thus, if you are conscientious, you will need:
(Update:
'convert.iconv.UTF-8/UTF-8'
will force everything to UTF-8, but you still have to account for characters that the iconv library might not know how to translate. In other words, you have to some how define what action to take when a character cannot be translated: 1) Insert a dummy character, 2) Fail / throw and exception).You cannot rely exclusively on the HTTP
Content-Encoding
header, as this might indicate something like compression as in the following. This is not what you want to make a decision off of in regards to iconv.Therefore, the general steps might be ...
Part I: HTTP Request Related
PUT, PATCH, DELETE, ...)
type.
Part II: Stream Data Related
encoding (UTF-8).
Part III: Data Type Related
etc.
(Remember, the data can still be a URL encoded string which you must then parse and URL decode).
object.
Part IV: Data Value Related
Filter input data.
Validate input data.
Now do you see?
The
$_POST
superglobal, along with php.ini settings for limits on input, are simpler for the layman. However, dealing with character encoding is much more intuitive and efficient when using streams because there is no need to loop through superglobals (or arrays, generally) to check input values for the proper encoding.php://input
可以为您提供数据的原始字节。如果 POST 数据是 JSON 编码结构(AJAX POST 请求经常出现这种情况),则这非常有用。这里有一个函数可以做到这一点:
当您处理由传统 POST 提交的表单中的键值数据时,
$_POST
数组更有用。仅当 POSTed 数据采用可识别格式时才有效,通常是application/x-www-form-urlencoded
(请参阅 http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 了解详细信息)。php://input
can give you the raw bytes of the data. This is useful if the POSTed data is a JSON encoded structure, which is often the case for an AJAX POST request.Here's a function to do just that:
The
$_POST
array is more useful when you're handling key-value data from a form, submitted by a traditional POST. This only works if the POSTed data is in a recognised format, usuallyapplication/x-www-form-urlencoded
(see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 for details).如果发布数据格式错误,$_POST 将不包含任何内容。然而, php://input 将具有格式错误的字符串。
例如,有一些ajax应用程序,没有形成正确的post键值序列来上传文件,并且只是将所有文件转储为post数据,没有变量名称或任何内容。
$_POST 将为空,$_FILES 也为空,并且 php://input 将包含精确的文件,以字符串形式写入。
If post data is malformed, $_POST will not contain anything. Yet, php://input will have the malformed string.
For example there is some ajax applications, that do not form correct post key-value sequence for uploading a file, and just dump all the file as post data, without variable names or anything.
$_POST will be empty, $_FILES empty also, and php://input will contain exact file, written as a string.
如何使用它的简单示例
Simple example of how to use it