Способы доступа к данным запроса в PHP

Раздел: Разработка на PHP -> HTTP запросы

Получение данных HTTP-запроса в PHP

Как безопасно извлечь данные запроса с фильтрацией и валидацией?

Наиболее эффективный подход - использование функций filter_input и filter_var. Они позволяют получить значение из указанного источника (GET, POST, SERVER и т.д.) и одновременно применить фильтр очистки или валидации. Это снижает риск XSS-атак и инъекций.

<?php
// Получаем параметр 'name' из GET-строки, удаляем теги
$name = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_STRING);

// Получаем email из POST, проверяем корректность формата
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);

if ($email === false) {
    echo 'Некорректный email';
} else {
    echo "Привет, $name! Твой email: $email";
}
?>

Пояснение: filter_input первым аргументом принимает тип входа (INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV). Второй - имя ключа. Третий - константа фильтра. Если значение отсутствует, функция возвращает null; если не проходит валидацию - false. Это позволяет сразу обработать ошибочные ситуации.

Типичные проблемы: Фильтр FILTER_SANITIZE_STRING объявлен устаревшим в PHP 8.1+. Рекомендуется использовать FILTER_UNSAFE_RAW с последующей обработкой через htmlspecialchars при выводе. Также легко забыть указать фильтр, что сводит защиту к нулю. Решение: всегда задавать явный фильтр или комбинировать с filter_var после получения сырых данных.

Цель и случаи использования: Подходит для любых сценариев, где требуется первичная очистка входных данных - обработка форм, параметров URL, кук. Особенно рекомендуется в проектах без фреймворка для быстрой и безопасной работы.

Как получить параметры из строки запроса или тела формы напрямую?

Прямое обращение к суперглобальным массивам $_GET и $_POST - самый простой способ.

<?php
$id = $_GET['id'] ?? null;
$password = $_POST['password'] ?? '';
?>

Пояснение: Массивы заполняются автоматически: $_GET - параметры из URL (после ?), $_POST - данные из тела запроса с Content-Type: application/x-www-form-urlencoded или multipart/form-data. Оператор ?? задаёт значение по умолчанию, если ключ отсутствует, предотвращая Notice.

Типичные ошибки: Если не использовать ??, при отсутствии ключа возникнет Notice: Undefined index. Кроме того, данные никак не фильтруются - их вывод без экранирования ведёт к XSS. Решение: всегда экранировать через htmlspecialchars при выводе в HTML.

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

Как получить данные, отправленные в формате JSON или XML?

Когда клиент отправляет данные с Content-Type: application/json (например, из JavaScript fetch или SPA), суперглобальный $_POST не заполняется. Используется поток php://input.

<?php
$raw = file_get_contents('php://input');
$data = json_decode($raw, true); // true для ассоциативного массива

if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
    http_response_code(400);
    echo 'Ошибка разбора JSON';
    exit;
}

$name = $data['name'] ?? 'Гость';
echo "Привет, $name";
?>

Пояснение: php://input возвращает сырое тело запроса, доступен только для POST, PUT, PATCH, DELETE. Для форм multipart/form-data он недоступен. После получения сырых данных их нужно декодировать в зависимости от типа контента. json_decode с флагом true преобразует в массив.

Типичные проблемы: Если данные не являются корректным JSON, json_decode вернёт null, а json_last_error укажет на ошибку. Необходимо проверять результат. Также php://input можно прочитать только один раз - при повторном вызове вернёт пустую строку. Решение: сохранить результат в переменную.

Цель и случаи использования: Используется в REST API, вебхуках, одностраничных приложениях (SPA), где данные передаются в формате JSON или XML.

Как получить данные без указания источника (GET, POST, COOKIE)?

Суперглобальный массив $_REQUEST объединяет $_GET, $_POST и $_COOKIE (порядок определяется директивой request_order).

<?php
$action = $_REQUEST['action'] ?? 'default';
?>

Пояснение: Удобно, когда не важно, откуда пришёл параметр. Однако из-за возможного переопределения (GET может перезаписать POST, если стоит первым в порядке) это снижает безопасность.

Типичная проблема: Злоумышленник может передать параметр через URL, который перезапишет значение из POST, что может нарушить логику. Решение: избегать $_REQUEST в критических операциях (авторизация, платежи).

Цель и случаи использования: Подходит для простых скриптов, где источник не важен, например, для поиска или фильтрации.

Как получить заголовки HTTP-запроса, например Authorization или User-Agent?

Заголовки запроса можно получить через функцию getallheaders() или через $_SERVER с префиксом HTTP_.

<?php
// Способ 1: getallheaders()
$headers = getallheaders();
$auth = $headers['Authorization'] ?? '';

// Способ 2: $_SERVER
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'Неизвестно';
?>

Пояснение: getallheaders() возвращает ассоциативный массив всех заголовков (ключи в том же регистре, что и в запросе). $_SERVER['HTTP_*'] содержит заголовки, преобразованные в верхний регистр и с заменой дефисов на подчёркивания. Например, User-Agent становится HTTP_USER_AGENT.

Типичные ошибки: getallheaders() работает только в окружении, где поддерживается SAPI (не во всех CGI-режимах). В таких случаях используют $_SERVER. Также не все заголовки попадают в $_SERVER (например, Authorization может быть недоступен при аутентификации через Basic). Решение: комбинировать оба метода или использовать PSR-7.

Цель и случаи использования: Аутентификация (Bearer токены), проверка User-Agent, работа с CORS, получение реферера.

Как получить данные запроса в объектно-ориентированном стиле с использованием PSR-7?

Для современных приложений, особенно построенных на фреймворках, рекомендуется использовать реализацию PSR-7, например laminas/laminas-diactoros или nyholm/psr7. Библиотека создаёт объект ServerRequestInterface из глобальных переменных.

<?php
require 'vendor/autoload.php';

use Laminas\Diactoros\ServerRequestFactory;

$request = ServerRequestFactory::fromGlobals();

$queryParams = $request->getQueryParams();
$parsedBody  = $request->getParsedBody();
$headers     = $request->getHeaders();
$method      = $request->getMethod();

$name = $queryParams['name'] ?? $parsedBody['name'] ?? 'Гость';
echo "Метод: $method, имя: $name";
?>

Пояснение: fromGlobals() автоматически заполняет объект данными из $_GET, $_POST, $_FILES, $_COOKIE, $_SERVER и php://input. После этого доступ к параметрам становится единообразным через методы интерфейса.

Типичные проблемы: Требуется установка сторонней библиотеки через Composer, что излишне для очень простых скриптов. Также может возникнуть путаница с обработкой multipart-форм - данные не попадают в getParsedBody(), а лежат в getUploadedFiles(). Решение: всегда проверять наличие соответствующих методов.

Цель и случаи использования: Крупные проекты, микросервисы, приложения, следующие стандартам PHP-FIG. Упрощает тестирование и замену компонентов.

Расширенные примеры получения данных в PHP

Пример 1: Получение JSON из POST-запроса с валидацией и обработкой ошибок

Пример
<?php
// Получаем сырые данные
$raw = file_get_contents('php://input');
if (empty($raw)) {
    http_response_code(400);
    exit('Пустое тело запроса');
}

// Декодируем JSON
$data = json_decode($raw, true);
$jsonError = json_last_error();
if ($jsonError !== JSON_ERROR_NONE) {
    http_response_code(400);
    echo 'Ошибка JSON: ' . json_last_error_msg();
    exit;
}

// Проверяем обязательные поля
if (!isset($data['email']) || !isset($data['password'])) {
    http_response_code(422);
    echo 'Требуются поля email и password';
    exit;
}

// Валидация email
$email = filter_var($data['email'], FILTER_VALIDATE_EMAIL);
if ($email === false) {
    http_response_code(422);
    echo 'Некорректный email';
    exit;
}

echo "Email: $email, пароль получен";
?>
При отправке POST /api/login с телом {"email":"user@test.com","password":"123"}
Вывод: Email: user@test.com, пароль получен

При отправке с невалидным JSON: Ошибка JSON: Syntax error

Пример 2: Получение данных из PUT/PATCH запроса через php://input

Пример
<?php
$method = $_SERVER['REQUEST_METHOD'];
if ($method !== 'PUT' && $method !== 'PATCH') {
    http_response_code(405);
    exit('Допустимы только PUT и PATCH');
}

parse_str(file_get_contents('php://input'), $putData);
// $putData теперь содержит параметры из тела запроса в виде application/x-www-form-urlencoded
$name = $putData['name'] ?? '';
echo "Обновляем имя: $name";
?>
curl -X PUT -d "name=НовоеИмя" http://example.com/user/1
Вывод: Обновляем имя: НовоеИмя

Обратите внимание: для JSON используйте json_decode, а не parse_str.

Пример 3: Использование filter_input с пользовательским callback-фильтром

Пример
<?php
// Определяем кастомный фильтр: удаляем лишние пробелы и приводим к нижнему регистру
$sanitizeName = function($value) {
    return strtolower(trim(strip_tags($value)));
};

$name = filter_input(INPUT_POST, 'username', FILTER_CALLBACK, ['options' => $sanitizeName]);
if ($name === null) {
    echo 'Параметр username не передан';
} else {
    echo "Отфильтрованное имя: $name";
}
?>
POST username=  <b>John</b>  
Вывод: Отфильтрованное имя: john

Пример 4: Получение загруженных файлов через $_FILES с проверкой типа

Пример
<?php
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit('Только POST');
}

$file = $_FILES['avatar'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
    http_response_code(400);
    exit('Ошибка загрузки файла');
}

$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$detectedType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);

if (!in_array($detectedType, $allowedTypes)) {
    http_response_code(415);
    exit('Неподдерживаемый тип файла');
}

$dest = __DIR__ . '/uploads/' . basename($file['name']);
move_uploaded_file($file['tmp_name'], $dest);
echo "Файл сохранён: $dest";
?>
Форма: <input type="file" name="avatar">
Загрузка JPEG-файла: Файл сохранён: /var/www/uploads/photo.jpg

Пример 5: Комбинирование GET, POST и заголовков в одном запросе

Пример
<?php
// Получаем токен авторизации из заголовка
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (!preg_match('/^Bearer\s+(\S+)$/', $authHeader, $matches)) {
    http_response_code(401);
    exit('Требуется Bearer токен');
}
$token = $matches[1];

// Получаем ID из GET
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$id) {
    http_response_code(400);
    exit('Неверный ID');
}

// Получаем новые данные из POST (JSON)
$input = json_decode(file_get_contents('php://input'), true);
$newName = $input['name'] ?? '';

echo "Пользователь $id будет обновлён. Токен: ...$token..., новое имя: $newName";
?>
curl -X PATCH \
  -H "Authorization: Bearer secret123" \
  -H "Content-Type: application/json" \
  -d '{"name":"Новое имя"}' \
  'http://example.com/api/user?id=5'
Вывод: Пользователь 5 будет обновлён. Токен: ...secret123..., новое имя: Новое имя

Пример 6: Получение информации о запросе через $_SERVER (метод, IP, URI)

Пример
<?php
$method = $_SERVER['REQUEST_METHOD'];
$uri    = $_SERVER['REQUEST_URI'];
$ip     = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
$port   = $_SERVER['REMOTE_PORT'] ?? 0;
$agent  = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';

header('Content-Type: text/plain');
echo "Метод: $method\nURI: $uri\nIP: $ip\nПорт: $port\nUser-Agent: $agent";
?>
Пример вывода:
Метод: GET
URI: /test?foo=bar
IP: 192.168.1.1
Порт: 54321
User-Agent: Mozilla/5.0 ...

Пример 7: Парсинг строки запроса с parse_str для нестандартных случаев

Пример
<?php
$queryString = 'key=value&arr[]=a&arr[]=b&special=%26%3D';
parse_str($queryString, $output);
print_r($output);
// Эквивалентно разбору $_SERVER['QUERY_STRING']
?>
Array
(
    [key] => value
    [arr] => Array
        (
            [0] => a
            [1] => b
        )
    [special] => &=
)

Пример 8: Использование библиотеки guzzlehttp/psr7 для создания серверного запроса

Пример
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Psr7\ServerRequest;

$request = ServerRequest::fromGlobals();

// Получаем все параметры запроса
$params = $request->getQueryParams() + (array)$request->getParsedBody();
$method = $request->getMethod();
$header = $request->getHeaderLine('Content-Type');

echo "Метод: $method\n";
echo "Content-Type: $header\n";
echo "Параметры: ";
print_r($params);
?>
Пример вывода при POST с form-data:
Метод: POST
Content-Type: multipart/form-data; boundary=...
Параметры: Array ( [name] => Иван )
- Urls php (обработка url в php)
- Php redirect (редирект в php)
- Forms form php (обработка форм в php)
- Php title (php title (установка заголовка страницы))
- Php запросы (php запросы (sql/http))
- Php получить (получение данных в php)
- Php url http (php работа с url и http)
- Request php (обработка http запросов в php)
- Php get request (get запрос в php)
- Php post json (php: отправка post-запроса с json)
- Php post request (post запрос в php)
- Php запрос страницы (запрос страницы в php)
- Fetch php (fetch-запрос в php (curl или file_get_contents))
- Php content json (php: установка content-type: application/json)
- Http content php (отправка контента по http в php)
- Https client php (http клиент на php)
- Curl php (curl в php)
- Php server request (обработка запросов php сервера)
- Php get (обработка get запросов в php)
- Php https post (отправка https post запросов в php)
- Php id 1 (передача параметра id в php)
- Php file http (работа с файлами по http в php)

Получение данных в PHP - comments

En
Php получить (php)