Приём и обработка POST запросов на PHP: от базовых конструкций до защиты
Основные подходы к обработке POST запросов в PHP
При разработке веб-форм на PHP обработка POST запросов является одной из ключевых задач. Ниже приведены базовые и альтернативные методы, а также типичные проблемы и их решения.
Как проверить, что форма отправлена методом POST?
Самый распространённый способ - проверка суперглобального массива $_POST с помощью isset() или $_SERVER['REQUEST_METHOD'].
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Обработка данных
$name = $_POST['name'] ?? '';
echo "Привет, " . htmlspecialchars($name);
}
Php имя формы (атрибут name формы в php)
Этот код сначала убеждается, что запрос именно POST, затем извлекает поле name. Использование оператора ?? (null coalescing) предотвращает ошибку неопределённого индекса.
Как получить значение из текстового поля формы?
<form method="post" action="">
<input type="text" name="username">
<input type="submit" value="Отправить">
</form>
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
echo htmlspecialchars($username);
}
?>
Post php started (обработка post)
Типичная ошибка: Попытка обратиться к $_POST['username'] без проверки существования приводит к notice Undefined index. Решается использованием isset() или оператора ??.
Проблема: Если отправлены не все поля, скрипт может работать некорректно. Рекомендуется проверять каждое ожидаемое поле через filter_input().
Как обработать данные формы с использованием filter_input()?
Функция filter_input() позволяет получить и одновременно отфильтровать данные.
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if ($email === false) {
echo "Некорректный email";
} else {
echo "Email: " . htmlspecialchars($email);
}
Form method php (метод формы в php)
Этот пример проверяет, что поле email является валидным адресом. Если проверка не пройдена, возвращается false.
Как обработать несколько одноимённых полей (например, массив checkbox)?
В HTML имена полей должны заканчиваться на [], чтобы PHP воспринимал их как массив.
<input type="checkbox" name="interests[]" value="php"> PHP
<input type="checkbox" name="interests[]" value="javascript"> JavaScript
<?php
if (isset($_POST['interests'])) {
$interests = $_POST['interests']; // массив
foreach ($interests as $interest) {
echo htmlspecialchars($interest) . '<br>';
}
}
?>
Input name php (атрибут name в input php)
Ошибка: Если ни один чекбокс не отмечен, $_POST['interests'] не существует. При обращении без проверки - notice. Решение: проверять через isset().
Проблема безопасности: Внедрение XSS при выводе данных. Всегда используйте htmlspecialchars().
Как защитить форму от CSRF атак?
Для защиты от межсайтовой подделки запроса добавляют скрытое поле с токеном и проверяют его на сервере.
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('CSRF token mismatch');
}
// остальная обработка
}
// Генерация токена
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
?>
<form method="post">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
...
</form>
Ошибка: Забыть вызвать session_start() или не обновлять токен после каждого использования (для большей безопасности рекомендуется одноразовые токены).
Как обработать AJAX POST запрос?
При отправке данных через JavaScript (fetch или XMLHttpRequest) на сервер приходят те же самые POST данные, но часто в формате JSON. В таком случае нужно читать сырой поток.
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if ($data) {
$name = htmlspecialchars($data['name'] ?? '');
echo "JSON имя: $name";
}
Если данные переданы как обычная форма (application/x-www-form-urlencoded или multipart/form-data), то можно использовать $_POST как обычно.
Как провести валидацию и санитизацию нескольких полей?
Рекомендуется использовать фильтры PHP или библиотеки (например, Symfony Validator). Простой пример с filter_var_array():
$data = [
'name' => filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING),
'age' => filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]]),
'email' => filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL)
];
if ($data['name'] === false || $data['age'] === false || $data['email'] === false) {
echo "Одно из полей содержит некорректные данные.";
} else {
echo "Все данные валидны.";
}
Проблема: FILTER_SANITIZE_STRING удаляет теги, но не защищает от всех XSS. После фильтрации всё равно нужно использовать htmlspecialchars() при выводе.
Ошибка: Использование FILTER_VALIDATE_INT без указания опций может пропустить отрицательные числа, если это не предусмотрено.
Расширенные примеры обработки POST данных
Пример 1. Обработка формы регистрации с валидацией всех полей и сохранением ошибок
<?php
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if (strlen($username) < 3) {
$errors[] = 'Имя пользователя должно содержать минимум 3 символа.';
}
if (strlen($password) < 6) {
$errors[] = 'Пароль должен быть не менее 6 символов.';
}
if ($email === false) {
$errors[] = 'Некорректный email.';
}
if (empty($errors)) {
// Сохранение в БД (здесь пропущено)
echo "Регистрация успешна. Привет, " . htmlspecialchars($username);
} else {
foreach ($errors as $error) {
echo "<p class='error'>" . htmlspecialchars($error) . "</p>";
}
}
}
?>
<form method="post">
<input type="text" name="username" placeholder="Имя">
<input type="password" name="password" placeholder="Пароль">
<input type="email" name="email" placeholder="Email">
<input type="submit" value="Зарегистрироваться">
</form>
Пример 2. Загрузка файла через POST (multipart/form-data) с проверкой типа и размера
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
$maxSize = 2 * 1024 * 1024; // 2 MB
if (!in_array($file['type'], $allowedTypes)) {
echo "Недопустимый тип файла.";
} elseif ($file['size'] > $maxSize) {
echo "Файл слишком большой.";
} elseif ($file['error'] !== UPLOAD_ERR_OK) {
echo "Ошибка загрузки: код " . $file['error'];
} else {
$dest = 'uploads/' . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $dest)) {
echo "Файл успешно загружен: " . htmlspecialchars($file['name']);
} else {
echo "Не удалось переместить файл.";
}
}
}
Пример 3. Обработка вложенного массива полей (например, динамические строки в таблице)
<form method="post">
<input type="text" name="items[0][name]" value="Товар 1">
<input type="number" name="items[0][price]" value="100">
<input type="text" name="items[1][name]" value="Товар 2">
<input type="number" name="items[1][price]" value="200">
<input type="submit">
</form>
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['items'])) {
foreach ($_POST['items'] as $index => $item) {
$name = htmlspecialchars($item['name'] ?? '');
$price = filter_var($item['price'] ?? 0, FILTER_VALIDATE_INT);
echo "Товар $index: $name - $price руб.<br>";
}
}
?>
Пример 4. Обработка POST данных с использованием PDO для вставки в базу данных (с подготовленными запросами против SQL injection)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO users (username, email) VALUES (:username, :email)');
$stmt->execute([
':username' => $_POST['username'] ?? '',
':email' => filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL)
]);
echo "Пользователь добавлен, ID: " . $pdo->lastInsertId();
}
Пример 5. Работа с сырыми POST данными (JSON) при REST API
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE) {
$response = ['status' => 'ok', 'received' => $data];
header('Content-Type: application/json');
echo json_encode($response);
} else {
http_response_code(400);
echo json_encode(['error' => 'Invalid JSON']);
}
Пример 6. Обработка формы с множественными кнопками отправки (action)
<form method="post">
<input type="text" name="query">
<button type="submit" name="action" value="search">Поиск</button>
<button type="submit" name="action" value="save">Сохранить</button>
</form>
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
switch ($action) {
case 'search':
echo "Поиск: " . htmlspecialchars($_POST['query'] ?? '');
break;
case 'save':
echo "Сохранение...";
break;
default:
echo "Неизвестное действие.";
}
}
?>
Результат выполнения: В зависимости от нажатой кнопки выводится соответствующее сообщение.
Пример 7. Обработка POST с использованием библиотеки Symfony HttpFoundation (для современных проектов)
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
if ($request->isMethod('POST')) {
$name = $request->request->get('name', '');
echo "Привет, " . htmlspecialchars($name);
}
Этот подход абстрагирует работу с суперглобальными массивами и предоставляет удобные методы для фильтрации, сессий и т.д.