Как в PHP получить тело (body) PUT-запроса с помощью file_get_contents?

Ответ

В PHP для чтения "сырых" данных тела HTTP-запроса (для методов POST, PUT, PATCH, DELETE) используется поток php://input. Это предпочтительный способ, так как $_POST работает только для данных с content-type application/x-www-form-urlencoded или multipart/form-data.

Базовый пример чтения тела PUT-запроса:

if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    // Получаем необработанное тело запроса как строку
    $rawInput = file_get_contents('php://input');

    // Далее парсим в зависимости от формата
    // 1. Если ожидается JSON:
    $data = json_decode($rawInput, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(400); // Bad Request
        echo json_encode(['error' => 'Invalid JSON']);
        exit;
    }
    // Теперь $data — ассоциативный массив с данными
    // echo $data['name'];
}

Важные нюансы работы с php://input:

  • Доступен только один раз: Поток php://input не буферизуется. После чтения file_get_contents('php://input') он становится пустым. Если нужно использовать данные несколько раз, сохраните их в переменную.
  • Не работает с multipart/form-data: Для загрузки файлов через PUT (что редкость) стандартно используется POST. php://input не будет содержать загруженные файлы в таком случае.
  • Для больших данных: Используйте чтение чанками, чтобы не загружать всё в память.
    $putData = '';
    $handle = fopen('php://input', 'r');
    while (!feof($handle)) {
        $putData .= fread($handle, 8192);
    }
    fclose($handle);
  • Определение типа контента: Всегда проверяйте заголовок Content-Type ($_SERVER['CONTENT_TYPE']), чтобы понять, как парсить данные (JSON, XML, plain text).

Альтернативный подход с parse_str (для form-encoded данных):

if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    $input = file_get_contents('php://input');
    parse_str($input, $parsedData); // Преобразует строку 'name=John&age=30' в массив
    // $parsedData['name'] будет 'John'
}

Ответ 18+ 🔞

А, ну это же классика, ёпта! Сидишь такой, пишешь свой API, и тут бац — нужно данные из PUT-запроса вытащить. А $_POST нихуя не работает, пустой как твои карманы после зарплаты. Вот тут-то и вспоминаешь про php://input, старину проверенного.

Смотри, в чём прикол. Этот php://input — это как читать мысли запроса напрямую, в обход всех этих дурацких формальностей. $_POST — он только для двух конкретных типов контента работает: application/x-www-form-urlencoded (обычная форма) и multipart/form-data (когда файлы шлёшь). А если тебе JSON прилетел, или XML, или просто текст — то $_POST будет пустым, и ты охуеешь, думая, что данные не дошли.

Вот самый простой способ, как с этим потоком работать. Допустим, ловишь PUT-запрос:

if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    // Берёшь и просто выгребаешь всё, что в теле запроса лежит
    $rawInput = file_get_contents('php://input');

    // А дальше уже думаешь, что с этим делать. Если JSON пришёл:
    $data = json_decode($rawInput, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(400); // Клиент — пидарас шерстяной, прислал херню
        echo json_encode(['error' => 'Invalid JSON']);
        exit;
    }
    // Всё, $data теперь твой массив, работай с ним.
    // echo $data['name'];
}

Но, чувак, есть важные нюансы, про которые забывать нельзя, а то будет тебе хиросима и нигерсраки.

  • Прочитал один раз — и всё. Этот поток php://input — не буферизованный. Прочитал его через file_get_contents() — и он опустел, как бутылка после хорошей пятницы. Хочешь использовать данные в нескольких местах? Сохраняй в переменную, не будь распиздяем.
  • С файлами через PUT — нихуя не выйдет. Если кто-то взбредёт в голову слать файлы через PUT с multipart/form-data (что само по себе — мудя редкостная), то php://input тебе нихуя не покажет. Для файлов — это POST-метод царь и бог.
  • Если данных овердохуища. Читай чанками, а то оперативку всю сожрёшь.
    $putData = '';
    $handle = fopen('php://input', 'r');
    while (!feof($handle)) {
        $putData .= fread($handle, 8192);
    }
    fclose($handle);
  • Всегда смотри, что тебе шлют. Проверяй заголовок Content-Type ($_SERVER['CONTENT_TYPE']), чтобы понять, JSON это, XML или ещё какая-нибудь пиздопроебибна. Парси соответственно.

Ну и есть ещё один способ, если тебе старый-добрый URL-encoded формат прилетел (типа name=John&age=30). Можно parse_str использовать:

if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    $input = file_get_contents('php://input');
    parse_str($input, $parsedData); // Магия! Строка превращается в массив.
    // $parsedData['name'] будет 'John'
}

Вот и вся наука. Главное — помни про поток, и доверия к $_POST в таких случаях — ебать ноль.