如何在 php 中获取 POST 的正文?
Posted
技术标签:
【中文标题】如何在 php 中获取 POST 的正文?【英文标题】:How to get body of a POST in php? 【发布时间】:2012-02-15 06:46:31 【问题描述】:我将以下内容作为 POST 提交到 php 页面:
a:1
这是请求的主体(POST 请求)。 在 php 中,我该怎么做才能提取该值?
var_dump($_POST);
不是解决方案,不起作用。
【问题讨论】:
对于希望创建 RESTful API 的人来说,这是一个很有帮助的问题。大多数人不知道如何访问提交给他们的脚本的原始输入数据,因为它不能通过$_POST
超级全局获得。在 PUT 请求的情况下也是如此(尤其是),因为 PHP 没有相应的超全局。
How to get request content (body) in PHP?的可能重复
值得注意的是,名称 $_POST 具有误导性,因为 POST 请求中不会有任何类型的数据,但只有在内容类型为 时才会出现application/x-www-form-urlencoded 或 multipart/form-data
【参考方案1】:
访问 POST 或 PUT 请求(或任何其他 HTTP 方法)的实体主体:
$entityBody = file_get_contents('php://input');
另外,STDIN
常量是 php://input
的已打开流,因此您也可以这样做:
$entityBody = stream_get_contents(STDIN);
来自PHP manual entry on I/O streamsdocs:
php://input 是一个只读流,允许您读取原始数据 从请求正文。在 POST 请求的情况下,最好 使用 php://input 而不是
$HTTP_RAW_POST_DATA
,因为它没有 依赖于特殊的 php.ini 指令。此外,对于那些情况$HTTP_RAW_POST_DATA
默认不填充,它可能是 激活时内存占用较少的替代方案 always_populate_raw_post_data。 php://input 不适用于 enctype="multipart/form-data"。
您需要特别注意php://input
流,无论您如何在 Web SAPI 中访问它,都是不可搜索的。这意味着它只能被读取一次。如果您在经常上传大型 HTTP 实体主体的环境中工作,您可能希望以流形式维护输入(而不是像上面的第一个示例那样缓冲它)。
为了维护流资源,这样的事情可能会有所帮助:
<?php
function detectRequestBody()
$rawInput = fopen('php://input', 'r');
$tempStream = fopen('php://temp', 'r+');
stream_copy_to_stream($rawInput, $tempStream);
rewind($tempStream);
return $tempStream;
php://temp
允许您管理内存消耗,因为它会在存储一定数量的数据(默认为 2M)后透明地切换到文件系统存储。可以在 php.ini 文件中或通过附加 /maxmemory:NN
来操作此大小,其中 NN
是在使用临时文件之前要保留在内存中的最大数据量,以字节为单位。
当然,除非您有充分的理由在输入流上进行搜索,否则您不应该在 Web 应用程序中需要此功能。读取一次 HTTP 请求实体正文通常就足够了——不要让客户端整天等待,而您的应用正在弄清楚该做什么。
请注意,php://input 不适用于指定Content-Type: multipart/form-data
标头(html 表单中的enctype="multipart/form-data"
)的请求。这是因为 PHP 已经将表单数据解析为 $_POST
超全局变量。
【讨论】:
请注意,afaics,STDIN 流在使用 CGI 运行 PHP 的系统上不可用,即通过 mod_fcgid 或 mod_fastcgi 等。 但是,我将变量(作为表单数据)与请求一起传递,我如何访问指定的值,我将 grant_type=password&username=user&password=pass 作为表单数据正文与请求一起传递,我将如何从“$entityBody”获取grant_type 根据我的测试,这个php://input
对于application/x-www-form-urlencoded
内容类型也是空的(除了multipart/form-data
)
扩展@scy 的回复:STDIN 不可用,但php://input
可用。因此,在(快速)CGI 配置 stream_get_contents(STDIN)
不起作用时,file_get_contents("php://input")
会。【参考方案2】:
返回数组中的值
$data = json_decode(file_get_contents('php://input'), true);
【讨论】:
在这种情况下,您现在必须遍历$data
关联数组来检查每个值是否按照您希望的方式进行编码。看待事物的“流到数据类型”的方式可能很简单,但它可能不如使用流过滤器处理“流形式”的编码那么有效。如果您不处理编码问题而只是清理和验证,那么您就错过了一个步骤。
在 php mvc 中从 body 发布数据是一种非常好的方式。【参考方案3】:
空$_POST
的一个可能原因是请求不再是POST
,或者不再是POST
...它可能以帖子开始,但遇到301
或302
重定向某处,切换到GET
!
检查$_SERVER['REQUEST_METHOD']
以检查是否是这种情况。
请参阅https://***.com/a/19422232/109787,详细讨论为什么这不应该发生但仍然会发生。
【讨论】:
这个问题是在开发 REST api 平台的背景下提出的。 我不确定你的意思? REST api 也可以在其路径中找到重定向,这就是我遇到的问题。 我的意思是当我问这个问题时,我并没有试图解决一个错误,而是试图弄清楚如何开发它。 这个提示拯救了我的一天。接收服务器已重新配置为重定向到 https,这破坏了一些 API 客户端。 @zackygaurav 可能是从不带 / 的网址重定向到带 / 的网址?【参考方案4】:function getPost()
if(!empty($_POST))
// when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
// NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
return $_POST;
// when using application/json as the HTTP Content-Type in the request
$post = json_decode(file_get_contents('php://input'), true);
if(json_last_error() == JSON_ERROR_NONE)
return $post;
return [];
print_r(getPost());
【讨论】:
这部分逻辑缺少的是对 Content-Type 标头中的值的测试。不能仅仅因为 $_POST 为空就必须提交 JSON,或者如果json_last_error() == JSON_ERROR_NONE
是 false
,则应该返回一个空数组。如果有人提交了 XML 或 YAML 怎么办?为 Content-Type 添加一个测试并从那里开始。
此外,HTTP 请求方法可以决定您是否要接受输入数据。请参阅$_SERVER
超全局以检查有用的值。【参考方案5】:
这是一个如何使用file_get_contents("php://input")
创建php api 并在javascript
中使用ajax
和XMLHttpRequest
的示例。
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function ()
if (this.readyState == 4 && this.status == 200)
console.log("done");
;
xhttp.open("POST", "http://127.0.0.1:8000/api.php", true);
xhttp.send(JSON.stringify(
username: $(this).val(),
email:email,
password:password
));
$data = json_decode(file_get_contents("php://input"));
$username = $data->username;
$email = $data->email;
$password = $data->password;
【讨论】:
【参考方案6】:如果你已经安装了 HTTP PECL 扩展,你可以使用http_get_request_body()
函数来获取字符串形式的正文数据。
【讨论】:
函数不存在。【参考方案7】:查看$HTTP_RAW_POST_DATA
variable
【讨论】:
访问原始 POST 数据的首选方法是php://input
。 $HTTP_RAW_POST_DATA
不适用于 enctype="multipart/form-data"
。
此功能在 PHP 5.6.0 中已弃用,并在 PHP 7.0.0 中删除。
答案没有上面评论那么多的赞成票:)【参考方案8】:
如果你安装了pecl/http 扩展,你也可以使用这个:
$request = new http\Env\Request();
$request->getBody();
【讨论】:
【参考方案9】:http_get_request_body()
明确用于根据文档 http://php.net/manual/fa/function.http-get-request-body.php 获取 PUT
和 POST
请求的主体
【讨论】:
(PECL pecl_http >= 0.10.0)以上是关于如何在 php 中获取 POST 的正文?的主要内容,如果未能解决你的问题,请参考以下文章
无论 Content-Type 标头如何,在 Python Flask 中获取原始 POST 正文
如何使用 C# 在 POST 请求中发送 json 请求正文数据