如何在 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-urlencodedmultipart/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...它可能以帖子开始,但遇到301302 重定向某处,切换到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_NONEfalse,则应该返回一个空数组。如果有人提交了 XML 或 YAML 怎么办?为 Content-Type 添加一个测试并从那里开始。 此外,HTTP 请求方法可以决定您是否要接受输入数据。请参阅$_SERVER 超全局以检查有用的值。【参考方案5】:

这是一个如何使用file_get_contents("php://input") 创建php api 并在javascript 中使用ajaxXMLHttpRequest 的示例。

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 获取 PUTPOST 请求的主体

【讨论】:

(PECL pecl_http >= 0.10.0)

以上是关于如何在 php 中获取 POST 的正文?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 AWS ELB 日志中获取完整的 POST 正文?

无论 Content-Type 标头如何,在 Python Flask 中获取原始 POST 正文

如何使用 C# 在 POST 请求中发送 json 请求正文数据

无法在 php if 语句中处理 axios.post vuejs 正文数据

如何在 Zuul 后置过滤器中获取响应正文?

带有 JSON 正文的 POST 请求