Это полезный вопрос для тех, кто хочет создавать RESTful API. Большинство не знает, как получить доступ к необработанным входным данным, представленным в их сценариях, поскольку они не доступны через $_POSTсуперглобальный объект. Это также (особенно) верно в случае запросов PUT, поскольку в PHP нет соответствующего суперглобального.
Стоит отметить, что имя $ _POST вводит в заблуждение, поскольку там не будут присутствовать данные любого типа из запроса POST, но только в том случае, если тип контента - application / x-www-form-urlencoded или multipart / form-data
Petruza
Ответы:
549
Чтобы получить доступ к телу объекта запроса POST или PUT (или любого другого метода HTTP):
$entityBody = file_get_contents('php://input');
Кроме того, STDINконстанта является уже открытым потоком php://input, так что вы можете сделать следующее:
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://tempпозволяет управлять потреблением памяти, поскольку оно прозрачно переключится на хранилище файловой системы после сохранения определенного объема данных (по умолчанию 2M). Этим размером можно манипулировать в файле php.ini или путем добавления /maxmemory:NN, где указан NNмаксимальный объем данных, сохраняемых в памяти перед использованием временного файла, в байтах.
Конечно, если у вас нет действительно веских причин для поиска во входном потоке, вам не понадобятся эти функции в веб-приложении. Как правило, достаточно прочитать тело сущности HTTP-запроса один раз - не заставляйте клиентов ждать весь день, пока ваше приложение выяснит, что делать.
Обратите внимание, что php: // input недоступен для запросов, указывающих Content-Type: multipart/form-dataзаголовок ( enctype="multipart/form-data"в HTML-формах). Это результат того, что PHP уже проанализировал данные формы в $_POSTсуперглобальном.
Обратите внимание, что на самом деле поток 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")будет.
В этом сценарии вам теперь нужно перебрать $dataассоциативный массив, чтобы проверить, закодировано ли каждое значение так, как вы хотите. Взгляд на поток с типом данных может быть упрощенным, но он может быть не таким эффективным, как работа с кодированием в «потоковой форме» с использованием потокового фильтра. Если вы не решаете проблемы с кодированием, а просто очищаете и проверяете, вы пропускаете шаг.
Энтони Ратледж,
13
Возможная причина пустого $_POSTзаключается в том, что запрос не является POST, или нет POSTбольше ... Возможно, он начинался как пост, но где-то встретил 301или 302перенаправил, который переключен на GET!
Осмотрите, $_SERVER['REQUEST_METHOD']чтобы проверить, так ли это.
Этот вопрос был задан в контексте разработки платформы REST API.
Итай Моав -Малимовка
Я не уверен, что ты имеешь в виду? REST API может также найти редиректы на своем пути, это проблема, с которой я столкнулся.
Леголас
Я имел в виду, когда я задавал вопрос, я не пытался устранить ошибку, а пытался выяснить, как ее развить.
Итай Моав -Малимовка
3
этот намек спас мой день. принимающий сервер был перенастроен для перенаправления на https, который сломал некоторые клиенты API.
DesertEagle
На самом деле моя просьба была, POSTно после проверки она показала, что это так GET. Как только я добавил /в конце своего URL, он начал показывать POST. Weird!
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 Preturn $_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 для полезных значений для проверки.
$_POST
суперглобальный объект. Это также (особенно) верно в случае запросов PUT, поскольку в PHP нет соответствующего суперглобального.Ответы:
Чтобы получить доступ к телу объекта запроса POST или PUT (или любого другого метода HTTP):
Кроме того,
STDIN
константа является уже открытым потокомphp://input
, так что вы можете сделать следующее:Из руководства по PHP для документации потоков ввода / вывода :
В частности, вы должны заметить, что
php://input
поток, независимо от того, как вы обращаетесь к нему в веб-SAPI, не доступен для поиска . Это означает, что его можно прочитать только один раз. Если вы работаете в среде, в которой регулярно загружаются большие объекты сущностей HTTP, вы можете сохранить входные данные в виде потока (вместо того, чтобы буферизовать их, как в первом примере выше).Для поддержки потокового ресурса может быть полезно что-то вроде этого:
php://temp
позволяет управлять потреблением памяти, поскольку оно прозрачно переключится на хранилище файловой системы после сохранения определенного объема данных (по умолчанию 2M). Этим размером можно манипулировать в файле php.ini или путем добавления/maxmemory:NN
, где указанNN
максимальный объем данных, сохраняемых в памяти перед использованием временного файла, в байтах.Конечно, если у вас нет действительно веских причин для поиска во входном потоке, вам не понадобятся эти функции в веб-приложении. Как правило, достаточно прочитать тело сущности HTTP-запроса один раз - не заставляйте клиентов ждать весь день, пока ваше приложение выяснит, что делать.
Обратите внимание, что php: // input недоступен для запросов, указывающих
Content-Type: multipart/form-data
заголовок (enctype="multipart/form-data"
в HTML-формах). Это результат того, что PHP уже проанализировал данные формы в$_POST
суперглобальном.источник
php://input
пусто дляapplication/x-www-form-urlencoded
типа контента (кромеmultipart/form-data
)php://input
есть. Так что пока (быстро) конфигурации CGIstream_get_contents(STDIN)
не будут работать,file_get_contents("php://input")
будет.возвращаемое значение в массиве
источник
$data
ассоциативный массив, чтобы проверить, закодировано ли каждое значение так, как вы хотите. Взгляд на поток с типом данных может быть упрощенным, но он может быть не таким эффективным, как работа с кодированием в «потоковой форме» с использованием потокового фильтра. Если вы не решаете проблемы с кодированием, а просто очищаете и проверяете, вы пропускаете шаг.Возможная причина пустого
$_POST
заключается в том, что запрос не являетсяPOST
, или нетPOST
больше ... Возможно, он начинался как пост, но где-то встретил301
или302
перенаправил, который переключен наGET
!Осмотрите,
$_SERVER['REQUEST_METHOD']
чтобы проверить, так ли это.См. Https://stackoverflow.com/a/19422232/109787 для хорошего обсуждения того, почему это не должно происходить, но все же происходит.
источник
POST
но после проверки она показала, что это такGET
. Как только я добавил/
в конце своего URL, он начал показывать POST. Weird!Проверьте
$HTTP_RAW_POST_DATA
переменнуюисточник
php://input
.$HTTP_RAW_POST_DATA
недоступно сenctype="multipart/form-data"
.Если вы установили расширение HTTP PECL, вы можете использовать
http_get_request_body()
функцию для получения данных тела в виде строки.источник
Если у вас установлено расширение pecl / http , вы также можете использовать это:
источник
источник
json_last_error() == JSON_ERROR_NONE
естьfalse
, что пустой массив должен быть возвращен. Что если кто-то отправил XML или YAML? Добавьте тест для Content-Type и перейдите оттуда.$_SERVER
superglobal для полезных значений для проверки.http_get_request_body()
был явно сделан для получения телаPUT
иPOST
запросов согласно документации http://php.net/manual/fa/function.http-get-request-body.phpисточник