Avatar ·

Как определить тип HTTP-запроса (GET, POST, PUT, DELETE) в PHP?

Всем привет! Я новичок в PHP и пишу простой REST API для учебного проекта. Мне нужно, чтобы скрипт обрабатывал разные типы запросов: GET для получения данных, POST для создания, PUT для обновления и DELETE для удаления. Проблема в том, что я не могу понять, как правильно определить, какой именно метод HTTP используется в текущем запросе. В интернете видел много разных примеров, но они все противоречат друг другу. Кто-то использует `$_SERVER['REQUEST_METHOD']`, кто-то предлагает проверять `$_POST` или `$_GET`, а кто-то вообще говорит про какие-то скрытые поля в формах. Вот мой текущий код, который не работает как надо: ```php ``` Проблемы: 1. Когда я отправляю PUT-запрос через Postman, он попадает в блок `else`. 2. DELETE-запросы тоже не определяются. 3. Иногда даже POST-запросы без параметров не распознаются. Подскажите, пожалуйста, как правильно и надёжно определять тип HTTP-запроса в PHP? Нужно ли обрабатывать все четыре основных метода? И как быть с данными, которые приходят в PUT и DELETE запросах — они ведь не попадают в `$_POST`? Буду благодарен за подробный пример с пояснениями. <<>>

Правильный способ определения HTTP-метода в PHP

Для надёжного определения типа запроса используйте суперглобальный массив $_SERVER['REQUEST_METHOD']. Он всегда содержит реальный HTTP-метод, переданный клиентом, в отличие от проверок $_POST или $_GET, которые зависят от наличия данных.

<?php
// Получаем метод запроса
$method = $_SERVER['REQUEST_METHOD'];

// Обрабатываем каждый метод
switch ($method) {
    case 'GET':
        // Обработка GET-запроса
        $data = $_GET;
        echo "Получен GET-запрос с параметрами: " . print_r($data, true);
        break;

    case 'POST':
        // Обработка POST-запроса
        $data = $_POST;
        echo "Получен POST-запрос с данными: " . print_r($data, true);
        break;

    case 'PUT':
        // Обработка PUT-запроса
        $input = file_get_contents('php://input');
        parse_str($input, $data);
        echo "Получен PUT-запрос с данными: " . print_r($data, true);
        break;

    case 'DELETE':
        // Обработка DELETE-запроса
        $input = file_get_contents('php://input');
        parse_str($input, $data);
        echo "Получен DELETE-запрос с данными: " . print_r($data, true);
        break;

    default:
        // Неподдерживаемый метод
        http_response_code(405);
        echo "Метод $method не поддерживается";
        break;
}
?>

Ключевые моменты

  • $_SERVER['REQUEST_METHOD'] — единственный надёжный способ определить метод. Он возвращает строку: 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS' и т.д.
  • Проблема с PUT и DELETE: PHP не заполняет $_POST для этих методов. Данные нужно читать из потока php://input с помощью file_get_contents().
  • Парсинг данных: Для PUT и DELETE используйте parse_str(), чтобы преобразовать строку запроса в массив, аналогичный $_POST.
  • JSON-данные: Если API принимает JSON (например, Content-Type: application/json), обрабатывайте так:
case 'PUT':
    $input = file_get_contents('php://input');
    $data = json_decode($input, true); // true — как ассоциативный массив
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(400);
        echo "Некорректный JSON";
        exit;
    }
    echo "Получен PUT-запрос с JSON: " . print_r($data, true);
    break;

Полный пример REST-роутера

<?php
// Определяем метод
$method = $_SERVER['REQUEST_METHOD'];

// Определяем путь (например, /api/users/123)
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$pathParts = explode('/', trim($path, '/'));

// Получаем данные запроса
$data = [];
switch ($method) {
    case 'GET':
        $data = $_GET;
        break;
    case 'POST':
        $data = $_POST;
        break;
    case 'PUT':
    case 'DELETE':
    case 'PATCH':
        $input = file_get_contents('php://input');
        // Определяем формат данных
        $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
        if (strpos($contentType, 'application/json') !== false) {
            $data = json_decode($input, true);
        } else {
            parse_str($input, $data);
        }
        break;
}

// Пример маршрутизации
if ($path === '/api/users' && $method === 'GET') {
    // Получить всех пользователей
} elseif ($path === '/api/users' && $method === 'POST') {
    // Создать пользователя
} elseif (preg_match('#^/api/users/(\d+)$#', $path, $matches) && $method === 'GET') {
    // Получить пользователя по ID: $matches[1]
} elseif (preg_match('#^/api/users/(\d+)$#', $path, $matches) && $method === 'PUT') {
    // Обновить пользователя с ID: $matches[1]
} elseif (preg_match('#^/api/users/(\d+)$#', $path, $matches) && $method === 'DELETE') {
    // Удалить пользователя с ID: $matches[1]
} else {
    http_response_code(404);
    echo "Маршрут не найден";
}
?>

Дополнительные советы

  • Всегда проверяйте метод в начале скрипта — это повышает безопасность.
  • Для сложных API используйте готовые микрофреймворки: Slim, Laravel (через routes), Symfony.
  • Не забывайте про http_response_code() для правильных HTTP-статусов.
  • При работе с формами HTML (которые поддерживают только GET и POST) можно эмулировать PUT/DELETE через скрытое поле _method:
<form method="POST" action="/users/123">
    <input type="hidden" name="_method" value="PUT">
    <!-- остальные поля -->
</form>

// В PHP:
if ($_POST['_method'] ?? null) {
    $method = strtoupper($_POST['_method']);
}

Этот подход часто используется в фреймворках для обратной совместимости с HTML-формами.

<<>>

Альтернативный подход с использованием фильтрации и безопасности

Если вы пишете небольшое приложение и хотите добавить дополнительную защиту, можно использовать комбинацию $_SERVER['REQUEST_METHOD'] с проверкой на разрешённые методы и фильтрацией входных данных.

<?php
// Разрешённые методы
$allowedMethods = ['GET', 'POST', 'PUT', 'DELETE'];
$method = $_SERVER['REQUEST_METHOD'];

// Проверка, что метод разрешён
if (!in_array($method, $allowedMethods)) {
    http_response_code(405);
    header('Allow: ' . implode(', ', $allowedMethods));
    die("Метод $method не поддерживается");
}

// Получаем данные в зависимости от метода
function getRequestData($method) {
    switch ($method) {
        case 'GET':
            return $_GET;
        case 'POST':
            return $_POST;
        case 'PUT':
        case 'DELETE':
            $input = file_get_contents('php://input');
            // Пробуем распарсить как JSON, иначе как URL-encoded
            $data = json_decode($input, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                parse_str($input, $data);
            }
            return $data;
        default:
            return [];
    }
}

$data = getRequestData($method);

// Пример безопасной обработки
$id = isset($data['id']) ? (int)$data['id'] : null;
$name = isset($data['name']) ? htmlspecialchars($data['name'], ENT_QUOTES, 'UTF-8') : '';

echo "Метод: $method, ID: $id, Имя: $name";
?>

Почему этот подход хорош?

  • Явно проверяет, что метод входит в белый список.
  • Автоматически обрабатывает и JSON, и URL-encoded данные.
  • Фильтрует входные данные (приведение к int, экранирование HTML).
  • Возвращает правильный HTTP-статус 405 для неподдерживаемых методов.

Этот вариант идеально подходит для небольших API, где не хочется подключать тяжёлые фреймворки, но нужна минимальная защита от некорректных запросов.