PHP“php://input”与$_POST
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8893574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP "php://input" vs $_POST
提问by Lee
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
.
我被指示在与来自 JQuery 的 Ajax 请求交互时使用该方法php://input
而不是$_POST
。我不明白的是使用 this 与全局方法$_POST
or的好处$_GET
。
回答by Quasdunk
The reason is that php://input
returns all the raw data after the HTTP-headers of the request, regardless of the content type.
原因是php://input
无论内容类型如何,都会在请求的 HTTP 标头之后返回所有原始数据。
The PHP superglobal $_POST
, only is supposed towrap data that is either
PHP superglobal $_POST
,只应该包装数据
application/x-www-form-urlencoded
(standard content type for simple form-posts) ormultipart/form-data
(mostly used for file uploads)
application/x-www-form-urlencoded
(简单表单帖子的标准内容类型)或multipart/form-data
(主要用于文件上传)
This is because these are the only content types that mustbe 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).
这是因为这些是用户代理必须支持的唯一内容类型。因此,服务器和 PHP 传统上不希望接收任何其他内容类型(这并不意味着它们不能)。
So, if you simply POST a good old HTML form
, the request looks something like this:
所以,如果你只是 POST 一个好的旧 HTML form
,请求看起来像这样:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
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:
但是如果你经常使用 Ajax,这个问题还包括用类型(字符串、整数、布尔)和结构(数组、对象)交换更复杂的数据,所以在大多数情况下 JSON 是最好的选择。但是带有 JSON-payload 的请求看起来像这样:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
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).
内容现在将是application/json
(或至少没有上面提到的),所以 PHP 的$_POST
-wrapper 不知道如何处理它(还)。
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 not multipart/form-data
-encoded).
数据仍然存在,只是无法通过包装器访问它。因此,您需要使用file_get_contents('php://input')
(只要它不是multipart/form-data
-encoded)以原始格式自己获取它。
This is also how you would access XML-data or any other non-standard content type.
这也是您访问 XML 数据或任何其他非标准内容类型的方式。
回答by Rob Agar
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.
php://input
可以为您提供数据的原始字节。如果 POSTed 数据是 JSON 编码结构,这很有用,这通常是 AJAX POST 请求的情况。
Here's a function to do just that:
这是一个可以做到这一点的函数:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
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, usually application/x-www-form-urlencoded
(see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4for details).
$_POST
当您处理由传统 POST 提交的表单中的键值数据时,该数组更有用。这仅在 POSTed 数据采用可识别的格式时才有效,通常application/x-www-form-urlencoded
(有关详细信息,请参阅http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4)。
回答by Nameless
If post data is malformed, $_POST will not contain anything. Yet, php://input will have the malformed string.
如果发布数据格式错误,$_POST 将不包含任何内容。然而, php://input 会有格式错误的字符串。
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.
例如,有一些ajax应用程序,在上传文件时没有形成正确的post键值序列,只是将所有文件转储为post数据,没有变量名或任何东西。$_POST 将为空, $_FILES 也为空, php://input 将包含精确的文件,写为字符串。
回答by Anthony Rutledge
First, a basic truth about PHP.
首先,关于 PHP 的一个基本事实。
PHP was not designed to explicitly give you a pure REST (GET, POST, PUT, PATCH, DELETE) like interface for handling HTTP requests.
PHP 的设计目的不是明确地为您提供一个纯 REST(GET、POST、PUT、PATCH、DELETE)之类的接口来处理 HTTP 请求。
However, the $_POST
, $_GET
, and $_FILES
superglobals, and the function filter_input_array()
are very useful for the average person's / layman's needs.
但是,$_POST
、$_GET
、 和$_FILES
superglobals以及函数filter_input_array()
对于普通人/外行的需求非常有用。
The number one hidden advantage of $_POST
(and $_GET
) is that your input data is urldecoded automatically by PHP. You never even think about having to do it, especially for query string parameters within a standard GET request.
$_POST
(and $_GET
)的第一个隐藏优势是您的输入数据由 PHP 自动进行 urldecode。您甚至从未想过必须这样做,尤其是对于标准 GET 请求中的查询字符串参数。
However, then you learn more ...
然而,然后你会学到更多......
That being said, as you advance in your programming knowledge and want to use JavaScript's XmlHttpRequest
object (jQuery for some), you come to see the limitation of this scheme.
话虽如此,随着您的编程知识的进步并希望使用 JavaScript 的XmlHttpRequest
对象(对于某些人为 jQuery),您会看到此方案的局限性。
$_POST
limits you to the use of two media types in the HTTP Content-Type
header:
$_POST
限制您在 HTTPContent-Type
标头中使用两种媒体类型:
application/x-www-form-urlencoded
, andmultipart/form-data
application/x-www-form-urlencoded
, 和multipart/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 urlencodeit 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..).
因此,如果您想将数据值发送到服务器上的 PHP,并将其显示在$_POST
superglobal 中,那么您必须在客户端对其进行urlencode并将所述数据作为键/值对发送——这对新手来说是一个不方便的步骤(尤其是在尝试确定 URL 的不同部分是否需要不同形式的 urlencoding:正常、原始等时......)。
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 setting processData: false
. Just read the $.ajax() documentation, and don't forget to send the correct media type in the Content-Type header.
对于所有 jQuery 用户,该$.ajax()
方法是将您的 JSON 转换为 URL 编码的键/值对,然后再将它们传输到服务器。您可以通过设置覆盖此行为processData: false
。只需阅读$.ajax() 文档,不要忘记在 Content-Type 标头中发送正确的媒体类型。
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.
通常,如果您使用 HTML 表单执行正常的同步(当整个页面重绘时)HTTP 请求,则用户代理(Web 浏览器)将为您对表单数据进行 urlencode。如果您想使用该XmlHttpRequest
对象执行异步 HTTP 请求,那么您必须构造一个 urlencoded 字符串并发送它,如果您希望该数据显示在$_POST
superglobal 中。
How in touch are you with JavaScript? :-)
你对 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 efficientfor the client code to do so.
从 JavaScript 数组或对象转换为 urlencoded 字符串困扰着许多开发人员(即使使用新的 API,如Form Data)。他们更希望能够发送 JSON,并且客户端代码这样做会更有效率。
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. ;-)
请记住(眨眼,眨眼),一般的 Web 开发人员不会XmlHttpRequest
像您和我一样学习直接使用对象、全局函数、字符串函数、数组函数和正则表达式 ;-)。Urlencoding 对他们来说是一场噩梦。;-)
PHP, what gives?
PHP,什么给?
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).
PHP 缺乏直观的 XML 和 JSON 处理让很多人望而却步。你会认为它现在是 PHP 的一部分(叹气)。
So many media types (MIME types in the past)
这么多媒体类型(过去的 MIME 类型)
XML, JSON, and YAML all have media types that can be put into an HTTP Content-Type
header.
XML、JSON 和 YAML 都有可以放入 HTTPContent-Type
标头的媒体类型。
- application/xml
- applicaiton/json
- application/yaml (although IANA has no official designation listed)
- 应用程序/xml
- 应用程序/json
- application/yaml(虽然 IANA 没有列出官方名称)
Look how many media-types(formerly, MIME types) are defined by IANA.
看看IANA 定义了多少媒体类型(以前称为 MIME 类型)。
Look how many HTTP headersthere are.
看看有多少HTTP 标头。
php://input or bust
php://input 或 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!
使用php://input
流允许您绕过 PHP 强加给世界的婴儿看护/手持抽象级别。:-) 拥有权利的同时也被赋予了重大的责任!
Now, before you deal with data values streamed through php://input
, you should / must do a few things.
现在,在处理通过 流式传输的数据值之前php://input
,您应该/必须做一些事情。
- Determine if the correct HTTP methodhas been indicated (GET, POST, PUT, PATCH, DELETE, ...)
- Determine if the HTTP Content-Typeheader has been transmitted.
- Determine if the valuefor the Content-Type is the desired media type.
- Determine if the data sent is well formedXML / JSON / YMAL / etc.
- If necessary, convert the datato a PHP datatype: array or object.
- If any of these basic checks or conversions fails, throw an exception!
- 确定是否已指示正确的HTTP 方法(GET、POST、PUT、PATCH、DELETE 等)
- 确定 HTTP Content-Type标头是否已传输。
- 确定Content-Type的值是否是所需的媒体类型。
- 确定发送的数据是否是格式良好的XML / JSON / YMAL / 等。
- 如有必要,将数据转换为 PHP 数据类型:数组或对象。
- 如果这些基本检查或转换中的任何一个失败,则抛出异常!
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?
啊,哈!是的,您可能希望发送到您的应用程序的数据流是 UTF-8 编码的,但是您怎么知道它是否是这样?
Two critical problems.
两个关键问题。
- You do not know how much data is coming through
php://input
. - You do not know for certain the current encoding of the data stream.
- 您不知道有多少数据正在通过
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.
您是否打算在不知道流数据的情况下尝试处理流数据?这是一个可怕的想法。您不能完全依赖 HTTPContent-Length
标头来指导流输入的大小,因为它可能被欺骗。
You are going to need a:
你将需要一个:
- Stream size detection algorithm.
- Application defined stream size limits (Apache / Nginx / PHP limits may be too broad).
- 流大小检测算法。
- 应用程序定义的流大小限制(Apache / Nginx / PHP 限制可能太宽泛)。
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.
您是否打算在不知道流的当前编码的情况下尝试将流数据转换为 UTF-8?如何?iconv 流过滤器(iconv 流过滤器示例)似乎想要一个开始和结束的编码,就像这样。
'convert.iconv.ISO-8859-1/UTF-8'
Thus, if you are conscientious, you will need:
因此,如果您有良心,您将需要:
- Stream encoding detection algorithm.
- Dynamic / runtime stream filter definition algorithm (because you cannot know the starting encoding a priori).
- 流编码检测算法。
- 动态/运行时流过滤器定义算法(因为您无法先验地知道起始编码)。
(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).
(更新:'convert.iconv.UTF-8/UTF-8'
将强制所有内容为 UTF-8,但您仍然必须考虑 iconv 库可能不知道如何翻译的字符。换句话说,您必须如何定义当一个字符无法翻译时要采取的操作: 1) 插入一个虚拟字符,2) 失败/抛出和异常)。
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.
您不能完全依赖 HTTPContent-Encoding
标头,因为这可能表示如下所示的压缩。这不是您想要就 iconv 做出决定的原因。
Content-Encoding: gzip
Therefore, the general steps might be ...
因此,一般步骤可能是...
Part I: HTTP Request Related
第一部分:HTTP 请求相关
- Determine if the correct HTTP methodhas been indicated (GET, POST, PUT, PATCH, DELETE, ...)
- Determine if the HTTP Content-Typeheader has been transmitted.
- Determine if the valuefor the Content-Type is the desired media type.
- 确定是否已指示正确的HTTP 方法(GET、POST、PUT、PATCH、DELETE 等)
- 确定 HTTP Content-Type标头是否已传输。
- 确定Content-Type的值是否是所需的媒体类型。
Part II: Stream Data Related
第二部分:流数据相关
- Determine the size of the input stream (optional, but recommended).
- Determine the encoding of the input stream.
- If necessary, convert the input stream to the desired character encoding (UTF-8).
- If necessary, reverse any application level compression or encryption, and then repeat steps 4, 5, and 6.
- 确定输入流的大小(可选,但推荐)。
- 确定输入流的编码。
- 如有必要,将输入流转换为所需的字符编码 (UTF-8)。
- 如有必要,反转任何应用程序级别的压缩或加密,然后重复步骤 4、5 和 6。
Part III: Data Type Related
第三部分:数据类型相关
- Determine if the data sent is well formedXML / JSON / YMAL / etc.
- 确定发送的数据是否是格式良好的XML / JSON / YMAL / 等。
(Remember, the data can still be a URL encoded string which you must then parse and URL decode).
(请记住,数据仍然可以是 URL 编码的字符串,然后您必须对其进行解析和 URL 解码)。
- If necessary, convert the datato a PHP datatype: array or object.
- 如有必要,将数据转换为 PHP 数据类型:数组或对象。
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.
该$_POST
超全局,与输入范围的php.ini设置一起,是外行简单。然而,在使用流时处理字符编码更加直观和高效,因为不需要循环遍历超全局变量(或数组,通常)来检查输入值是否正确编码。
回答by Ifeanyi Amadi
So I wrote a function that would get the POST data from the php://input stream.
所以我写了一个函数来从php://input 流中获取 POST 数据。
So the challenge here was switching to PUT, DELETE OR PATCH request method, and still obtain the post data that was sent with that request.
所以这里的挑战是切换到 PUT、DELETE 或 PATCH 请求方法,并仍然获取随该请求发送的 post 数据。
I'm sharing this maybe for someone with a similar challenge. The function below is what I came up with and it works. I hope it helps!
我可能会为有类似挑战的人分享这个。下面的函数是我想出来的,它有效。我希望它有帮助!
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/
function getPostData() : array
{
// @var string $input
$input = file_get_contents('php://input');
// continue if $_POST is empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);
// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);
// let's get the keys
if (count($matches) > 0 && count($matches[0]) > 0)
{
$keys = $matches[2];
foreach ($keys as $index => $key) :
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index] = $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);
// now let's get key value
$inputArr = explode($postsize, $input);
// @var array $values
$values = [];
foreach ($inputArr as $index => $val) :
$val = preg_replace('/[\n]/','',$val);
if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);
endforeach;
// now combine the key to the values
$post = [];
// @var array $value
$value = [];
// update value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';
if (is_array($post)) :
$newPost = [];
foreach ($post as $key => $val) :
if (preg_match('/[\[]/', $key)) :
$k = substr($key, 0, strpos($key, '['));
$child = substr($key, strpos($key, '['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child] = $val;
else:
$newPost[$key] = $val;
endif;
endforeach;
$_POST = count($newPost) > 0 ? $newPost : $post;
endif;
}
endif;
// return post array
return $_POST;
}
回答by Dostonbek Oripjonov
Simple example of how to use it
如何使用它的简单示例
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>