#5 php форма с методом POST: массив $_POST и отличия от GET

В уроке про форму с GET браузер складывал числа прямо в адрес страницы. Но передавать так можно не всё: пароли, длинные тексты, файлы — для них у протокола HTTP есть второй главный метод — POST. Изменим в нашей форме одно слово и посмотрим, что изменится.

Немного теории

У HTTP есть несколько методов запроса; мы уже работали с GET, теперь познакомимся с POST. Главное отличие: данные отправляются не в адресе, а в теле запроса — отдельным «пакетом» после заголовков. Как PHP принимает данные формы, показано в учебнике: отображение данных формы.

Код страницы

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Сравнение чисел: POST</title>
</head>
<body>
  <h1>Сравнение чисел</h1>
  <form action="" method="post">
    <p>Число A: <input type="text" name="a"></p>
    <p>Число B: <input type="text" name="b"></p>
    <p><button type="submit">Сравнить</button></p>
  </form>
<?php
if (isset($_POST['a'], $_POST['b'])
    && $_POST['a'] !== '' && $_POST['b'] !== '') {
    $a = $_POST['a'];
    $b = $_POST['b'];
    if ($a > $b) {
        echo '<p>' . $a . ' больше ' . $b . '</p>';
    } elseif ($a < $b) {
        echo '<p>' . $a . ' меньше ' . $b . '</p>';
    } else {
        echo '<p>' . $a . ' равно ' . $b . '</p>';
    }
}
?>
</body>
</html>

Отличий от GET-версии ровно два: в форме написано method="post", а в PHP — $_POST вместо $_GET. PHP раскладывает данные из адреса и из тела запроса в разные массивы, чтобы код точно знал, откуда пришло значение.

Кстати, почему action="": пустой атрибут означает «отправить данные на эту же страницу» — форма лежит и обрабатывается в одном файле, нам не нужен второй. То же самое произошло бы, если бы атрибута action не было вовсе. Альтернатива — указать в action адрес отдельного файла-обработчика (например, action="compare.php"): тогда форму и код её обработки разносят по разным файлам, и данные уедут уже на другую страницу.

Отправляем и сравниваем с GET

Введите 5 и 7, нажмите «Сравнить» — ответ тот же: «5 меньше 7». А теперь посмотрите в адресную строку: параметров там нет. Данные уехали в теле запроса, адрес остался чистым.

Итоговое сравнение методов:

  • где данные: у GET — в адресе (строкой запроса), у POST — в теле запроса;
  • закладки и «поделиться ссылкой»: у GET результат можно сохранить в закладки (все параметры в адресе), у POST — нет;
  • объём: адрес имеет ограничение на длину, тело запроса — практически нет;
  • обновление страницы: GET браузер просто повторяет, а перед повторной отправкой POST-формы (например, по F5) переспросит вас — ведь данные отправятся заново;
  • когда что использовать: GET — «попросить» (поиск, фильтры, страницы), POST — «отправить/изменить» (логин, регистрация, комментарии, оплата).

Что произошло на самом деле

Браузер отправил на ту же страницу POST-запрос: адрес — как при обычном заходе, но после заголовков идёт тело с парами a=5&b=7. PHP разобрал тело и собрал пары в массив $_POST — и только потом запустил наш скрипт. Заметьте: если теперь вы захотите «поделиться ссылкой» на результат — не выйдет: в адресе-то ничего нет.

Попробуйте сами

  • отправьте форму и нажмите F5 — увидите предупреждение браузера о повторной отправке (в GET-версии его не было);
  • откройте DevTools (F12, вкладка Network), отправьте форму ещё раз и кликните по запросу в списке: среди его деталей видно метод POST и отправленные поля;
  • поменяйте в коде method обратно на get (и $_POST на $_GET) — и убедитесь, что адрес снова наполняется параметрами.

Итоги

  • POST отправляет данные формы в теле запроса — адрес страницы остаётся чистым;
  • в PHP эти данные приходят в массив $_POST;
  • GET подходит для «вопросов» (можно заклацать/поделиться адресом), POST — для «отправки» данных на сервер;
  • повторную отправку POST-формы браузер всегда переспрашивает.

В следующем уроке сделаем обработку формы «по-взрослому»: научимся различать простой заход на страницу и отправку формы, а поля после отправки не будут очищаться.