Глиф Учебники

Урок 6. Формы: $_GET, $_POST и htmlspecialchars

Курс «PHP» · урок 6 из 10 · 4 минуты чтения

Форма — главный способ, которым посетитель передаёт сайту данные: поиск, вход, заказ, отзыв. Браузер отправляет заполненные поля на сервер, а PHP получает их в готовых массивах $_GET и $_POST. Файлы урока открывайте через встроенный сервер: php -S localhost:8000.

GET и POST

У формы есть атрибут method:

Ключи в массивах — это значения атрибутов name у полей формы: поле <input name="q"> попадёт в $_GET['q'] или $_POST['q'].

GET данные — в адресе name="q" кот search.php?q=кот адрес тела у запроса нет тело $_GET['q'] → "кот" POST данные — в теле запроса name="name" Анна feedback.php адрес name=Анна тело $_POST['name'] → "Анна"
При GET поле name="q" со словом «кот» уходит в адресе search.php?q=кот и попадает в $_GET под ключом q, при POST поле name="name" идёт в теле запроса и попадает в $_POST под ключом name.

Поиск: форма GET

Файл search.php:

PHP
<?php
$q = trim($_GET['q'] ?? '');
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Поиск</title>
</head>
<body>
<form method="get">
    <input type="text" name="q" value="<?= htmlspecialchars($q) ?>">
    <button>Найти</button>
</form>
<?php if ($q !== ''): ?>
    <p>Вы искали: <?= htmlspecialchars($q) ?></p>
<?php endif; ?>
</body>
</html>

Откройте http://localhost:8000/search.php, введите слово и нажмите «Найти»: адрес станет search.php?q=…, а на странице появится введённый текст.

Что здесь важно:

Зачем htmlspecialchars

Посетитель может ввести не слово, а кусок HTML или JavaScript. Если вывести его как есть, браузер выполнит этот код. Такой взлом называется XSS (межсайтовый скриптинг): чужой скрипт на вашей странице может украсть вход посетителя или подменить содержимое.

htmlspecialchars заменяет опасные знаки (<, >, &, кавычки) на безопасные HTML-записи — браузер покажет их как текст:

PHP
<?php
$input = '<script>alert("Взлом")</script>';
echo htmlspecialchars($input) . "\n";
Вывод
&lt;script&gt;alert(&quot;Взлом&quot;)&lt;/script&gt;
Ввёл посетитель: <script>alert("Взлом")</script> Вывести как есть браузер выполнит скрипт <script>alert("Взлом")</script> Взлом OK Через htmlspecialchars браузер покажет текст &lt;script&gt; alert(&quot;Взлом&quot;) &lt;/script&gt; <script>alert("Взлом")</script>
Выведенный как есть, ввод <script>alert("Взлом")</script> браузер выполняет как скрипт, а после htmlspecialchars знаки < > и кавычки становятся &lt; &gt; &quot; и видны как текст.

Любые данные от посетителя — поля формы, адрес, cookie, даже имя загруженного файла — выводите на страницу только через htmlspecialchars. Одно забытое место — и сайт уязвим для XSS.

Чтобы не писать длинное имя каждый раз, заведите короткую функцию и подключайте её на всех страницах:

PHP
<?php
function e(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

Флаг ENT_QUOTES заменяет и двойные, и одинарные кавычки — тогда значение безопасно и внутри атрибута value='…'. С PHP 8.1 так и задано по умолчанию, но явная запись не повредит.

Обратная связь: форма POST с проверкой

Файл feedback.php показывает форму, проверяет поля и при ошибках показывает форму снова, с уже введёнными значениями:

PHP
<?php
$errors = [];
$name = '';
$email = '';
$sent = false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = trim($_POST['name'] ?? '');
    $email = trim($_POST['email'] ?? '');

    if ($name === '') {
        $errors[] = 'Введите имя';
    } elseif (mb_strlen($name) > 50) {
        $errors[] = 'Имя длиннее 50 знаков';
    }
    if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
        $errors[] = 'Почта указана неверно';
    }

    if (!$errors) {
        // Здесь данные сохраняют в базу или отправляют письмом.
        $sent = true;
    }
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Обратная связь</title>
</head>
<body>
<?php if ($sent): ?>
    <p>Спасибо, <?= htmlspecialchars($name) ?>! Сообщение принято.</p>
<?php else: ?>
    <?php foreach ($errors as $error): ?>
        <p style="color: red"><?= htmlspecialchars($error) ?></p>
    <?php endforeach; ?>
    <form method="post">
        <p><label>Имя: <input type="text" name="name" value="<?= htmlspecialchars($name) ?>"></label></p>
        <p><label>Почта: <input type="email" name="email" value="<?= htmlspecialchars($email) ?>"></label></p>
        <button>Отправить</button>
    </form>
<?php endif; ?>
</body>
</html>

Как это работает:

  1. При первом открытии страницы запрос — GET, блок if пропускается, и показывается пустая форма.
  2. После нажатия «Отправить» тот же файл получает запрос POST. $_SERVER['REQUEST_METHOD'] — способ запроса.
  3. Поля проверяются, ошибки собираются в массив $errors. Пустой массив в условии — false, поэтому !$errors означает «ошибок нет».
  4. filter_var с FILTER_VALIDATE_EMAIL возвращает адрес, если он похож на почту, и false, если нет.
Запрос GET первое открытие Пустая форма блок if пропущен Оба запроса обрабатывает один файл feedback.php Запрос POST после «Отправить» есть ошибки? нет «Спасибо…» $sent = true да Форма снова ошибки и введённое исправить и отправить
Файл feedback.php при первом открытии (GET) показывает пустую форму, а после «Отправить» (POST) проверяет поля: с ошибками — форма снова с введённым, без ошибок — «Спасибо».

Атрибуты required и type="email" в HTML помогают посетителю, но не защищают: запрос можно отправить в обход браузера. Поэтому проверка на сервере обязательна всегда.

Повторная отправка

Если после отправки POST обновить страницу (F5), браузер предложит отправить форму ещё раз — и сообщение придёт дважды. Поэтому после успешной обработки обычно делают перенаправление на страницу «Спасибо». Как это устроено — в справках Как отправить форму на ту же страницу и Как сделать редирект.

Флажки, списки и несколько значений

Массив $_REQUEST объединяет GET, POST и cookie. Им лучше не пользоваться: непонятно, откуда пришло значение.

Частые ошибки

Коротко

Проверьте себя

1. Когда для формы выбирают метод POST?
2. Зачем выводить введённый текст через htmlspecialchars?
3. В форме поле <input name="city"> и method="post". Где PHP найдёт значение?
4. Достаточно ли атрибута required в HTML, чтобы поле точно пришло заполненным?