Как получить тело POST в php?


273

Я отправляю как POST на страницу php следующее:

{a:1}

Это тело запроса (запрос POST).
В php, что мне нужно сделать, чтобы извлечь это значение?

var_dump($_POST); 

это не решение, не работает.


23
Это полезный вопрос для тех, кто хочет создавать RESTful API. Большинство не знает, как получить доступ к необработанным входным данным, представленным в их сценариях, поскольку они не доступны через $_POSTсуперглобальный объект. Это также (особенно) верно в случае запросов PUT, поскольку в PHP нет соответствующего суперглобального.
— rdlowrey


1
Стоит отметить, что имя $ _POST вводит в заблуждение, поскольку там не будут присутствовать данные любого типа из запроса POST, но только в том случае, если тип контента - application / x-www-form-urlencoded или multipart / form-data
— Petruza

Ответы:


549

Чтобы получить доступ к телу объекта запроса POST или PUT (или любого другого метода HTTP):

$entityBody = file_get_contents('php://input');

Кроме того, STDINконстанта является уже открытым потоком php://input, так что вы можете сделать следующее:

$entityBody = stream_get_contents(STDIN);

Из руководства по PHP для документации потоков ввода / вывода :

php: // input - это поток только для чтения, который позволяет вам читать необработанные данные из тела запроса. В случае запросов POST предпочтительно использовать ввод php: // вместо того, $HTTP_RAW_POST_DATAчтобы не зависеть от специальных директив php.ini. Более того, для тех случаев, когда $HTTP_RAW_POST_DATAпо умолчанию не заполняется, это потенциально менее ресурсоемкая альтернатива активации always_populate_raw_post_data. php: // ввод недоступен с enctype = "multipart / form-data".

В частности, вы должны заметить, что php://inputпоток, независимо от того, как вы обращаетесь к нему в веб-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максимальный объем данных, сохраняемых в памяти перед использованием временного файла, в байтах.

Конечно, если у вас нет действительно веских причин для поиска во входном потоке, вам не понадобятся эти функции в веб-приложении. Как правило, достаточно прочитать тело сущности HTTP-запроса один раз - не заставляйте клиентов ждать весь день, пока ваше приложение выяснит, что делать.

Обратите внимание, что php: // input недоступен для запросов, указывающих Content-Type: multipart/form-dataзаголовок ( enctype="multipart/form-data"в HTML-формах). Это результат того, что PHP уже проанализировал данные формы в $_POSTсуперглобальном.


17
Обратите внимание, что на самом деле поток STDIN недоступен в системах, использующих PHP с использованием CGI, т.е. через mod_fcgid или mod_fastcgi и т. Д.
— scy

но, я передаю переменную (как данные формы) с запросом, как я могу получить доступ к указанному значению, я передаю grant_type = пароль и имя пользователя = user & пароль = передать как тело формы данных с запросом, как я получу grant_type из "$ entityBody "
— Anvar Pk

согласно моему тесту, это также php://inputпусто для application/x-www-form-urlencodedтипа контента (кроме multipart/form-data)
— YakovL

6
Чтобы расширить ответ @ scy: STDIN не доступен, но php://inputесть. Так что пока (быстро) конфигурации CGI stream_get_contents(STDIN)не будут работать, file_get_contents("php://input")будет.
— Синус Макковаты

16

возвращаемое значение в массиве

 $data = json_decode(file_get_contents('php://input'), true);

В этом сценарии вам теперь нужно перебрать $dataассоциативный массив, чтобы проверить, закодировано ли каждое значение так, как вы хотите. Взгляд на поток с типом данных может быть упрощенным, но он может быть не таким эффективным, как работа с кодированием в «потоковой форме» с использованием потокового фильтра. Если вы не решаете проблемы с кодированием, а просто очищаете и проверяете, вы пропускаете шаг.
— Энтони Ратледж,

13

Возможная причина пустого $_POSTзаключается в том, что запрос не является POST, или нет POSTбольше ... Возможно, он начинался как пост, но где-то встретил 301или 302перенаправил, который переключен на GET!

Осмотрите, $_SERVER['REQUEST_METHOD']чтобы проверить, так ли это.

См. Https://stackoverflow.com/a/19422232/109787 для хорошего обсуждения того, почему это не должно происходить, но все же происходит.


1
Этот вопрос был задан в контексте разработки платформы REST API.
— Итай Моав -Малимовка

Я не уверен, что ты имеешь в виду? REST API может также найти редиректы на своем пути, это проблема, с которой я столкнулся.
— Леголас

Я имел в виду, когда я задавал вопрос, я не пытался устранить ошибку, а пытался выяснить, как ее развить.
— Итай Моав -Малимовка

3
этот намек спас мой день. принимающий сервер был перенастроен для перенаправления на https, который сломал некоторые клиенты API.
— DesertEagle

На самом деле моя просьба была, POSTно после проверки она показала, что это так GET. Как только я добавил /в конце своего URL, он начал показывать POST. Weird!
— Закигаурав



2

Если у вас установлено расширение pecl / http , вы также можете использовать это:

$request = new http\Env\Request();
$request->getBody();

2
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-запроса может учитывать, хотите ли вы принять входные данные. Смотрите $_SERVERsuperglobal для полезных значений для проверки.
— Энтони Ратледж

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.