Як отримати тіло POST у php?


273

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

{a:1}

Це тіло запиту (POST-запит).
У PHP, що мені потрібно зробити, щоб отримати це значення?

var_dump($_POST); 

не рішення, не працює.


23
Це корисне питання для людей, які хочуть створити API RESTful. Більшість не знає, як отримати доступ до необроблених вхідних даних, що надходять до їх сценаріїв, оскільки вони недоступні через $_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: // вхід - це потік лише для читання, який дозволяє читати необроблені дані з тіла запиту. У випадку запитів POST бажано використовувати php: // input, а не $HTTP_RAW_POST_DATAоскільки це не залежить від спеціальних директив php.ini. Більше того, для тих випадків, коли $HTTP_RAW_POST_DATAне заповнено за замовчуванням, це потенційно менш об'ємна пам'ять, альтернатива активації завжди_populate_raw_post_data. php: // введення недоступне з enctype = "багаточастинні / форми-дані".

Зокрема, ви хочете зауважити, що 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дозволяє керувати витратою пам’яті, оскільки вона прозоро перейде на зберігання файлової системи після збереження певного обсягу даних (за замовчуванням 2М). Цей розмір можна маніпулювати у файлі php.ini або додаючи /maxmemory:NN, де NNмаксимальний обсяг даних, що зберігається в пам'яті перед тимчасовим файлом, у байтах.

Звичайно, якщо у вас немає поважних причин шукати вхідний потік, вам не потрібна ця функціональність у веб-програмі. Ознайомлення з органом запиту HTTP одного разу, як правило, достатньо - не змушуйте клієнтів чекати цілий день, поки ваша програма розбирається, що робити.

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


17
Зауважте, що afaics, потік STDIN недоступний у системах, що працюють з PHP, використовуючи CGI, тобто через mod_fcgid або mod_fastcgi тощо.
scy

але я передаю змінну (як дані форми) із запитом, як я можу отримати доступ до вказаного значення, я передаю grant_type = пароль і ім’я користувача = користувач & пароль = передаю як орган даних форми із запитом, як я отримаю grant_type від "$ entBody "
Анвар 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.
Itay Moav -Malimovka

Я не впевнений, що ти маєш на увазі? АРІЙТЕ api може так само добре знайти переспрямування на його шляху, це питання, яке у мене виникло.
Леголас

Я мав на увазі, коли я задавав питання, я не намагався вирішити помилку, а скоріше намагався розібратися, як її розвинути.
Itay Moav -Malimovka

3
цей натяк врятував мені день. сервер отримання був налаштований для переадресації на https, який зламав деякі клієнти API.
DesertEagle

Насправді мій запит був, POSTале після огляду він показав, що це було GET. Після того, як я додав a /в кінці своєї URL-адреси, він почав показувати POST. Дивно!
zackygaurav



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 може визначати, чи потрібно приймати вхідні дані. Перевірте $_SERVERкорисні значення для суперглобалу.
Ентоні

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.