POST запросы форм в PHP: полное руководство с примерами

Раздел: Веб-разработка на PHP -> Работа с HTML формами

Основной подход: обработка POST запроса с валидацией и безопасностью

Наиболее эффективное решение заключается в использовании суперглобального массива $_POST вместе со встроенными функциями фильтрации и проверки. Рассмотрим пошаговый пример.

Пример формы

<form method='post' action='handler.php'>
    <label>Имя: <input type='text' name='name' required></label><br>
    <label>Email: <input type='email' name='email' required></label><br>
    <input type='hidden' name='csrf_token' value='<?= $csrfToken ?>'>
    <button type='submit'>Отправить</button>
</form>

Обработчик handler.php

<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Метод не разрешен');
}
$token = $_POST['csrf_token'] ?? '';
if (!hash_equals($_SESSION['csrf_token'], $token)) {
    die('Неверный токен');
}
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if (!$name || !$email) {
    header('Location: form.php?error=1');
    exit;
}
// сохранение данных в БД через PDO...
$_SESSION['success'] = 'Данные сохранены';
header('Location: success.php');
exit;
?>

Пояснение шагов:

  1. Проверка метода запроса (только POST).
  2. Валидация CSRF токена для защиты от межсайтовой подделки.
  3. Фильтрация входных данных: удаление нежелательных символов и проверка формата.
  4. Если данные корректны, выполняется сохранение и редирект.

Типичные проблемы и их решение:

  • Проблема: данные не приходят, пустой $_POST - чаще всего из-за неправильного атрибута action или использования GET. Решение - проверить атрибуты формы и метод.
  • Проблема: XSS и SQL инъекции - использовать функции фильтрации и подготовленные запросы.
  • Проблема: дублирование отправки при обновлении страницы - использовать редирект после POST (PRG-шаблон).

Как валидировать несколько полей одной функцией?

Вместо вызова filter_input для каждого поля можно использовать filter_input_array с массивом правил.

$filters = [
    'name' => FILTER_SANITIZE_STRING,
    'email' => FILTER_VALIDATE_EMAIL,
    'age' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 120]]
];
$inputs = filter_input_array(INPUT_POST, $filters);

Цель:

упростить код и повысить читаемость. Случаи использования: формы с большим количеством полей.

Проблема:

filter_input_array возвращает null или false при ошибке; типы значений могут отличаться. Необходима дополнительная проверка каждого элемента массива.

Как отправить форму без перезагрузки страницы?

Используем JavaScript fetch API для асинхронной отправки. PHP обрабатывает данные и возвращает JSON.

// Фрагмент JS
const form = document.getElementById('myForm');
form.addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(form);
    const response = await fetch('handler.php', { method: 'POST', body: formData });
    const result = await response.json();
    if (result.success) {
        alert('Успешно');
    } else {
        alert('Ошибка: ' + result.error);
    }
});
// PHP (handler.php)
<?php
header('Content-Type: application/json');
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
if (!$name) {
    echo json_encode(['success' => false, 'error' => 'Имя обязательно']);
    exit;
}
// сохранение...
echo json_encode(['success' => true]);
?>

Цель:

улучшение пользовательского опыта, отсутствие полной перезагрузки. Случаи: формы обратной связи, регистрация.

Проблемы:

необходимо правильно обрабатывать ошибки на клиенте, а также настройки CORS при разделении фронтенда и бэкенда.

Как безопасно сохранять данные из формы в базу данных?

Используем PDO с подготовленными выражениями для защиты от SQL инъекций.

$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute([':name' => $name, ':email' => $email]);

Цель:

надёжная защита от инъекций, совместимость с разными СУБД. Случаи: любые формы, сохраняющие данные в БД.

Проблема:

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

Как защитить форму от CSRF атак?

Генерируем уникальный токен в сессии и включаем его в форму в скрытом поле. При обработке проверяем совпадение.

// Генерация токена
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// В форме: <input type='hidden' name='csrf_token' value='<?= $_SESSION['csrf_token'] ?>'>
// Проверка в обработчике
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
    die('CSRF detected');
}

Цель:

предотвращение выполнения нежелательных действий от имени аутентифицированного пользователя. Обязательно для форм, изменяющих данные.

Проблема:

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

Расширенные примеры обработки POST запросов

Пример 1: обработка формы с массивом (чекбоксы)

Пример
<form method='post' action='handler.php'>
    <input type='checkbox' name='interests[]' value='php'> PHP
    <input type='checkbox' name='interests[]' value='js'> JavaScript
    <input type='checkbox' name='interests[]' value='python'> Python
    <button type='submit'>Отправить</button>
</form>
// Обработчик
$interests = $_POST['interests'] ?? [];
if (is_array($interests)) {
    $clean = array_map('htmlspecialchars', $interests);
    echo 'Выбранные интересы: ' . implode(', ', $clean);
}
Выбранные интересы: PHP, JavaScript

Пример 2: обработка формы с загрузкой файла

Пример
<form method='post' enctype='multipart/form-data'>
    <input type='file' name='avatar' accept='image/*'>
    <button type='submit'>Загрузить</button>
</form>
// PHP
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['avatar'])) {
    $tmp = $_FILES['avatar']['tmp_name'];
    $name = basename($_FILES['avatar']['name']);
    $allowed = ['image/jpeg', 'image/png'];
    if (!in_array(mime_content_type($tmp), $allowed)) {
        die('Недопустимый тип файла');
    }
    move_uploaded_file($tmp, 'uploads/' . $name);
    echo 'Файл загружен: ' . $name;
}
Файл загружен: photo.jpg

Пример 3: использование filter_input_array с кастомными проверками

Пример
$filters = [
    'username' => [
        'filter' => FILTER_VALIDATE_REGEXP,
        'options' => ['regexp' => '/^[a-zA-Z0-9_]{3,20}$/']
    ],
    'website' => FILTER_VALIDATE_URL,
    'agree'   => ['filter' => FILTER_VALIDATE_BOOLEAN, 'flags' => FILTER_NULL_ON_FAILURE]
];
$result = filter_input_array(INPUT_POST, $filters);
if ($result['username'] === false || !$result['website'] || $result['agree'] === null) {
    echo 'Ошибка валидации';
} else {
    echo 'Данные прошли проверку';
}
Данные прошли проверку

Пример 4: работа с подготовленными запросами PDO и транзакциями

Пример
try {
    $pdo->beginTransaction();
    $stmt = $pdo->prepare('INSERT INTO orders (user_id, total) VALUES (?, ?)');
    $stmt->execute([$userId, $total]);
    $orderId = $pdo->lastInsertId();
    foreach ($items as $item) {
        $stmt2 = $pdo->prepare('INSERT INTO order_items (order_id, product_id, quantity) VALUES (?, ?, ?)');
        $stmt2->execute([$orderId, $item['id'], $item['qty']]);
    }
    $pdo->commit();
    echo 'Заказ успешно оформлен';
} catch (Exception $e) {
    $pdo->rollBack();
    echo 'Ошибка: ' . $e->getMessage();
}
Заказ успешно оформлен

Пример 5: обработка AJAX с возвратом JSON и обработкой ошибок

Пример
// PHP
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
    http_response_code(400);
    echo json_encode(['error' => 'Некорректный JSON']);
    exit;
}
$name = $input['name'] ?? '';
if (!$name) {
    echo json_encode(['error' => 'Имя не может быть пустым']);
    exit;
}
// обработка...
echo json_encode(['success' => true, 'message' => 'Привет, ' . htmlspecialchars($name)]);
// JS fetch
fetch('ajax.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: 'Алекс'})
}).then(r => r.json()).then(data => console.log(data));
{success: true, message: 'Привет, Алекс'}

Отправка формы методом POST в PHP - comments

En
Php form post (php)