在与来自JQuery的Ajax请求交互时,我被指示使用方法php://input
而不是$_POST
。我不明白的是使用此方法与$_POST
或$_GET
的全局方法相比的好处。
答案 0 :(得分:393)
原因是php://input
返回请求的HTTP标头之后的所有原始数据,而不管内容类型如何。
PHP超全局$_POST
,只有应该包装
application/x-www-form-urlencoded
(简单表单帖子的标准内容类型)或multipart/form-data-encoded
(主要用于文件上传)这是因为这些是must be supported by user agents唯一的内容类型。所以服务器和PHP传统上不希望接收任何其他内容类型(这并不意味着他们不能)。
因此,如果您只是发布一个好的旧HTML form
,请求看起来像这样:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
但是如果你正在使用Ajax,这个probaby还包括用类型(string,int,bool)和结构(数组,对象)交换更复杂的数据,所以在大多数情况下JSON是最好的选择。但是具有JSON-payload的请求看起来像这样:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
内容现在是application/json
(或至少没有上述内容),因此PHP的$_POST
- 包装器不知道如何处理(尚未)。
数据仍然存在,您无法通过包装器访问它。因此,您需要使用file_get_contents('php://input')
(as long as it's not multipart/form-data
-encoded)以原始格式自行获取。
这也是您访问XML数据或任何其他非标准内容类型的方式。
答案 1 :(得分:43)
php://input
可以为您提供数据的原始字节。如果POSTed数据是JSON编码结构,这通常适用于AJAX POST请求,这非常有用。
这是一个可以做到这一点的功能:
/**
* 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);
}
当您处理传统POST提交的表单中的键值数据时,$_POST
数组更有用。这仅适用于POSTed数据采用可识别格式的情况,通常为application/x-www-form-urlencoded
(有关详细信息,请参阅http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4)。
答案 2 :(得分:24)
如果发布数据格式错误,$ _POST将不包含任何内容。然而,php://输入将具有格式错误的字符串。
例如,有一些ajax应用程序,它们不能形成正确的上传文件的后键值序列,只是将所有文件作为发布数据转储,没有变量名称或任何东西。 $ _POST将为空,$ _FILES也为空,并且php://输入将包含精确文件,写为字符串。
答案 3 :(得分:4)
PHP并非旨在显式地为您提供纯REST(GET,POST,PUT,PATCH,DELETE)之类的用于处理HTTP请求的接口。。
但是,$_POST
,$_GET
和$_FILES
superglobals以及功能filter_input_array()
对于普通人/外行的需求非常有用。 / p>
$_POST
(和$_GET
)的第一大隐藏优势是您的输入数据被PHP自动
话虽如此,随着您对编程知识的了解不断提高,并想使用JavaScript的XmlHttpRequest
对象(某些情况下为jQuery),您会发现这种方案的局限性。
$_POST
限制您在HTTP Content-Type
标头中使用两种媒体类型:
application/x-www-form-urlencoded
和multipart/form-data
因此,如果要将数据值发送到服务器上的PHP,并使其显示在$_POST
超全局变量中,则必须urlencode在客户端并以键/值对的形式发送所述数据,这对新手来说是一个不方便的步骤(特别是在尝试确定URL的不同部分是否需要不同形式的urlencoding:常规,原始等)时。
对于您所有的jQuery用户,$.ajax()
方法都将JSON转换为URL编码的键/值对,然后再将它们传输到服务器。您可以通过设置processData: false
来覆盖此行为。只需阅读$.ajax() documentation,别忘了在Content-Type标头中发送正确的媒体类型。
通常,如果您正在执行带有HTML表单的正常,同步(重新绘制整个页面时)的HTTP请求,则用户代理(网络浏览器)将为您urlencode您的表单数据。如果您想使用XmlHttpRequest
对象进行异步HTTP请求,那么您必须生成一个urlencoded字符串并发送它,如果您希望该数据显示在$_POST
超全局变量中。
从JavaScript数组或对象转换为超文本编码的字符串困扰着许多开发人员(即使使用Form Data之类的新API)。他们宁愿只能够发送JSON,并且使客户端代码
请记住(眨眼,眨眼),普通的Web开发人员不会学会直接使用XmlHttpRequest
对象,全局函数,字符串函数,数组函数和正则表达式,例如您和I ;-)。对他们进行Urlencoding是一场噩梦。 ;-)
PHP缺乏直观的XML和JSON处理功能,这使许多人感到失望。您可能会认为(现在)它已经成为PHP的一部分。
XML,JSON和YAML都具有可以放入HTTP Content-Type
标头中的媒体类型。
看看IANA定义了多少media-types(以前是MIME类型)。
看看有多少HTTP headers。
使用php://input
流使您可以绕开PHP强制世界上的保姆/手持式抽象级别。 :-)强大的力量带来巨大的责任!
现在,在处理通过php://input
流传输的数据值之前,您应该/必须做一些事情。
啊,哈!是的,您可能希望发送到应用程序中的数据流是UTF-8编码的,但是如何知道它是否是这样?
php://input
。您是否要先处理流数据而不先知道有多少? 那是一个可怕的主意。您不能仅依靠HTTP Content-Length
标头来指导流输入的大小,因为它可以被欺骗。
您将需要一个:
您是否要在不知道流的当前编码的情况下尝试将流数据转换为UTF-8?怎么样? iconv流过滤器(iconv stream filter example)似乎需要这样的开始和结束编码。
'convert.iconv.ISO-8859-1/UTF-8'
因此,如果您认真负责,则需要:
(更新:'convert.iconv.UTF-8/UTF-8'
会将所有内容强制为UTF-8,但是您仍然必须考虑iconv库可能不知道如何翻译的字符。换句话说,您必须定义一些在无法翻译字符时应采取的措施:1)插入一个虚拟字符,2)失败/抛出和异常)。
您不能仅依靠HTTP Content-Encoding
标头,因为这可能表示类似压缩的内容,如下所示。这不是您要就iconv做出决定的原因。
Content-Encoding: gzip
第一部分:与HTTP请求相关
第二部分:与流数据相关
第三部分:与数据类型相关
(请记住,数据仍然可以是URL编码的字符串,然后必须对其进行解析和URL解码)。
第四部分:与数据值相关
过滤输入数据。
验证输入数据。
$_POST
超全局性以及用于限制输入的php.ini设置对于外行来说更简单。但是,使用流时处理字符编码更加直观和有效,因为不需要遍历超全局变量(通常是数组)来检查输入值是否正确。
答案 4 :(得分:0)
因此,我编写了一个函数,该函数将从 php:// input流获取POST数据。
因此,这里的挑战是切换到PUT,DELETE或PATCH请求方法,并仍然获取随该请求发送的帖子数据。
我可能是为面临类似挑战的人分享的。下面的功能是我想出的,它可以正常工作。希望对您有所帮助!
/**
* @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;
}
答案 5 :(得分:-2)
使用方法的简单示例
<?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; }
?>