Откуда получается тело PUT запроса с помощью file_get_contents?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отличный вопрос, который затрагивает ключевые аспекты работы с HTTP-запросами в PHP. Короткий ответ: тело (body) PUT-запроса получается из входного потока php://input, а file_get_contents('php://input') — это один из способов его чтения. Давайте разберем это подробно.
Основной механизм: php://input
В отличие от данных POST-запроса, которые часто автоматически парсятся в суперглобальные массивы $_POST и $_FILES (при использовании enctype="multipart/form-data"), тело HTTP-запросов других типов (PUT, PATCH, DELETE) не обрабатывается PHP автоматически. Оно доступно через специальный поток php://input.
php://input — это поток только для чтения, который позволяет получить "сырое" (raw) тело HTTP-запроса.
// Получение тела PUT-запроса
$putData = file_get_contents('php://input');
Важные особенности php://input:
- Это поток (stream), а не файл на диске.
- Доступен только один раз для чтения (после чтения он "опустошается").
- Недоступен для запросов с типом контента
multipart/form-data(обычные HTML-формы с файлами). В этом случае нужно использовать другие методы. - Содержит именно тело запроса, заголовки (headers) доступны отдельно через
getallheaders()или$_SERVER.
Практический пример обработки PUT-запроса
Наивная реализация для получения, например, JSON-данных из PUT-запроса выглядит так:
<?php
// Проверяем метод запроса
if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
// Читаем сырое тело запроса
$rawInput = file_get_contents('php://input');
// Пытаемся декодировать JSON (если ожидаем 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 json_encode(['success' => true, 'received' => $data]);
} else {
http_response_code(405); // Method Not Allowed
}
?>
Альтернативы и лучшие практики
1. Использование fopen() с потоком
Для больших объемов данных, где нежелательно загружать всё в память сразу, можно читать поток частями:
$handle = fopen('php://input', 'r');
while (!feof($handle)) {
$chunk = fread($handle, 8192); // Чтение по 8 КБ
// Обработка чанка
}
fclose($handle);
2. Современные фреймворки и PSR-7
В реальных проектах (Symfony, Laravel, Slim и др.) используется абстракция PSR-7 (HTTP Message Interface). Тело запроса там представлено объектом, реализующим интерфейс Psr\Http\Message\StreamInterface. Работа с ним гораздо удобнее и безопаснее.
Пример в Slim Framework:
$app->put('/resource/{id}', function (Request $request, Response $response, $args) {
// Фреймворк уже прочитал поток и предоставляет методы
$body = $request->getBody(); // Возвращает Psr\Http\Message\StreamInterface
$data = json_decode($body->getContents(), true);
// Или сразу получение парсированного тела
$data = $request->getParsedBody();
// ... обработка
return $response;
});
3. Массив $HTTP_RAW_POST_DATA (устаревший)
В старых версиях PHP (< 5.6) тело запроса также могло попадать в переменную $HTTP_RAW_POST_DATA, если в конфигурации php.ini была включена директива always_populate_raw_post_data. С PHP 7.0 эта переменная удалена, использовать её нельзя.
Ключевые моменты для запоминания:
- Источник данных: Тело PUT, PATCH, DELETE и "сырых" POST-запросов хранится в потоке
php://input. - Функция чтения:
file_get_contents('php://input')— простейший способ получить всё тело как строку. - Одноразовость: Поток
php://inputможно прочитать только один раз за время выполнения скрипта. Если нужно использовать данные несколько раз, сохраните их в переменную. - Мультипарт-формы: Для данных с
Content-Type: multipart/form-data(загрузка файлов)php://inputне работает. PUT-запросы редко используют этот тип, но если необходимо, придется парсить вручную или использовать фреймворк. - Контекст POST: Для обычных POST-запросов с
application/x-www-form-urlencodedданные удобнее брать из$_POST. Использованиеphp://inputдля них оправдано, только если нужны "сырые" данные до парсинга.
Таким образом, ответ на ваш вопрос лежит в понимании архитектуры ввода-вывода PHP: file_get_contents('php://input') читает данные из специального, одноразового входного потока, в который PHP помещает тело HTTP-запроса, когда оно не обрабатывается автоматически. В современной разработке эта низкоуровневая операция обычно скрыта за абстракциями фреймворков, соответствующих стандарту PSR-7.