Обработка форм в PHP. Как это делать правильно в 2020 году
Это достаточно «классическая» задача в PHP — приём и отправка обычной формы. Давным-давно, ещё во времена PHP 4, в книгах приводился пример того как это делать. Это всегда был один php-файл, где размещался и обработчик формы, и html-код вывода формы, и вывод ошибок. Понятно, что на заре рождения PHP, говорить о каком-то разделении кода или даже о культуре программирования не приходится. Но, недавно я случайно наткнулся на книгу о PHP 7 2018 года выпуска, где рассказывается об основах языка, классах, есть даже глава о PostgreSQL и даже описано несколько ООП-шаблонов проектирования.
Я с удивлением обнаружил, что до сих пор приводится код из PHP 4, как будто бы последних 20 лет развития PHP-программирования и не было. Сами посмотрите: это я сохранил скриншот. То есть вместо того, чтобы учить студентов нормальным практикам, до сих пор предлагается код 20-летней давности.
Чтобы продолжить, давайте определимся что именно неверно в таком подходе.
Код в одном файле — это хорошо или плохо? Хорошо, что это один файл, то есть перенос его будет немного проще. С другой стороны, часто ли вообще требуется куда-то его перемещать? Вряд ли.
Дальше. В файле смесь HTML и PHP. Если вынести код обработчика отдельно, то это уже упростит дальнейшую поддержку. Кстати о поддержке кода.
Поддержка кода — это такая его организация, которая позволит без мата и полной переделки доработать его в любой момент — через месяц или год, любым другим php-программистом. Сюда включается форматирование, а также логическая организация файлов. Форма, конечно, очень простой пример, но он всё равно должен быть сделан по правилам.
Идём дальше. В обработчике формы вроде как есть код отлова ошибок, и если их нет, то выводится какой-то результат. Обратите внимание на exit() , которая принудительно завершает выполнение скрипта. Это значит, что завершающая часть HTML-код не будет выведена — html-код окажется некорректным.
То есть на лицо ещё одна проблема — неверная логика работы скрипта. Даже в моих первых книгах вводились более сложные if/else условия, чтобы корректно завершить вывод html-кода.
Всё, хватит лирики, покажу как это нужно делать правильно в 2020 году. 🙂
Базовое правило — логика должна быть разделена на файлы. При отправке формы есть два базовых состояния: вывод самой формы и приём post-данных от формы. HTML-вывод, в свою очередь должен делиться на:
Здесь мы определяем константу BASE_DIR , которая нужна для формирования полных путей к подключаемым файлам, которые будут размещаться в разных подкаталогах. Алгоритм простой: если есть POST-данные, то подсоединяем файл action/post.php , где будем обрабатывать входящие данные и action/show.php , который служит для простого вывода формы. Рассмотрим action/show.php :
Форма собирается из нескольких файлов. Каталог layout хранит именно html-вывод. То есть, когда станет задача доработать дизайн формы, достаточно будет поправить какой-то один простой layout-файл. Файл layout/start.php содержит начальную часть html-страницы:
Здесь я подключил css-файл от Berry CSS, который размещается в каталоге assets . Это «типовой» каталог для всех «оформительских» файлов: css/sass, js, fonts и images. Также обратите внимание, что путь задан относительный. Если нужно указывать полный url, то в контролёре следует определить ещё одну константу, например BASE_URL , которую и использовать для формирования начальной части URL. Файл end.php просто корректно закрывает HTML:
Form demo
Это очень простой вариант с тремя полями: email, password и info. Обратите внимание, что у формы не указан параметр action , это означает, что post-данные формы будут отправлены по текущему URL-адресу.
В Сети полно примеров, когда action указывает на другой php-файл. Такая практика также изредка используется. В отличие от моего примера, такой модуль будет иметь два контролёра, а не один: в нашем случае мы определяем действие по переменой $_POST , а во втором случае — форма сама отправит запрос на «post-файл».
- Запускается index.php .
- В нём смотрится наличие post-данных.
- Если нет, то подключаем action/show.php .
- В нём подключаются layout-файлы для вывода формы.
else < require BASE_DIR . 'layout/error.php'; >require BASE_DIR . 'layout/end.php'; # end of file
Все данные мы формируем в массив $data (о нём чуть ниже). Первая проверка — просто на наличие необходимых данных от формы. То есть ниже по коду мы будем точно знать, что есть $data[‘password’] , даже если поле не было заполнено пользователем. После этого идёт валидация данных. Я её cделал примитивной (пример-то учебный), но смысл её в том, что формируется второй массив $error , который содержит список всех ошибок. Дальше нужно вывести результат. Поскольку начальный и конечный файлы HTML одинаковы, то мы их выносим за пределы if-условия. А дальше просто: если есть ошибки, то подключаем layout/error.php , если нет, то layout/result.php . Здесь важно то, что есть логика выполнения, но нет непосредственного html-вывода: мы разделяем html-вёрстку от php-кода. Файл result.php выводит список отправленных данных.
Обратите внимание, что здесь мы уже выводим $error . Вы можете скачать готовый пример. Такой подход к построению php-модуля (или приложения) наиболее правильный. Если есть возможность, то разделяйте php и html-код по разным файлам. Это особенно актуально для проектов с более сложной логикой.
Пара слов о $data
Часто стоит задача передать в layout-файл какие-то данные. Например название формы, или уже введенные данные, чтобы пользователь их заново не вводил, а только поправил. Лучший способ это сделать — именно через массив. Причём такой, где заранее оговариваются обязательные ключи. Это позволяет избежать дополнительных isset-проверок при их выводе.
// action «post» $data[‘title’] = ‘Заголовок формы’; // layout
Аля-MVC
Нетрудно заменить, что по своей сути код соответствует концепции MVC. Контролёр выполняет основную логику модуля. В нашем случае он совпал с фронт-контроллером, но обычно фронт-контролёр — это уровень приложения, а просто контролёр — это уровень модуля. Дальше контролёр дёргает определенную модель — в нашем случае это action-файлы. В модели происходит работа с данными и дальше модель передаёт управление в представление (view) — у нас это layout-файлы. То есть у нас управление передаётся по цепочке: controller → model → view. Есть ещё один вариант, когда контролёр передаёт данные в модель, модель возвращает результат обратно, а потом контролёр их передаёт уже в представление. То есть вариант MVC будет определяться уже задачей или архитектурой приложения.
Валидация данных
И в заключение небольшой момент о валидации данных. Очень часто валидация — чуть ли не половина кода модели (action-файла), поэтому часто её также выносят в отдельный файл.
Обработка форм сайта с помощью PHP
Формы используют для отправки какой-либо информации на сервер, которую необходимо как-то обработать.
Места использования форм:
- Создание регистрации и авторизации
- Создание блока комментариев
- Создание обращения в техническую поддержку (тикеты)
Создаём форму на HTML
Код формы необходимо помещать в HTML документа.
Здесь должна быть ваша форма.
Я пропущу скелет документа дальше, чтобы было более понятно.
Введите логин:
Введите пароль:
В атрибут action нужно указать обработчик формы (PHP-скрипт). Если поле пусто, значит, обработку формы выполнил тот скрипт, в котором расположена сама форма. В атрибут method нужно указать метод отправки формы (post или get). У каждого свои плюсы и минусы. Вкратце: post отправляет данные так, что пользователь не может их увидеть, а get — так, что они видны в URL-строке браузера.
Наглядный пример post:
Немного по PHP:
При отправке формы методом POST данные записываются в суперглобальный массив $_POST.
При отправке формы методом GET данные записываются в суперглобальный массив $_GET.
К суперглобальным массивам $_POST и $_GET нужно обращаться обычным способом (как вы делаете это и с обычными ассоциативными массивами) $массив[‘ключ’].
В форме мы сделали 3 . Первые два — поле ввода логина и пароля. Третий — кнопка отправки формы.
Тег имеет атрибут type=»». Для каждого случая указывают свой тип ввода. Допустим, text устанавливают для текста, submit — для отправки формы по атрибуту (action), а password — для пароля (чтобы он отображался звёздочками *).
Кроме того, тег имеет атрибут name=»» и атрибут value=»». Value — стандартное значение элемента, name — предназначено для того, чтобы обработчик формы мог его идентифицировать.
Создаём обработчика формы
Мы перешли к самому интересному моменту статьи. Если мы обрабатываем форму на другой странице (action=»example.php»), то после нажатия кнопки подтверждения вас перекинет на указанную страницу.
Если action пуст, то страница с формой перезагрузится.
В самом верху скелета документа (перед ) открываем теги PHP и обрабатываем форму:
// Если кнопка нажата, то выполняет тело условия if (isset($_POST['done'])) < echo 'кнопка обработчика была нажата!
'; // Если логин и пароль не пуст(есть значение), а также пароль не 123 if (!empty($_POST['login']) && $_POST['pass'] != 123 && !empty($_POST['pass'])) < echo "Всё хорошо, все поля пройдены. "; echo "Здесь должна быть ваша обработка формы. "; echo "Занесение в базу данных, отправка сообщения и т.п."; >// Если логин пуст, тогда выводит сообщение if ($_POST['login'] == '') < echo 'Логин пуст!
'; > // Если пароль популярный ||(или) пуст, тогда выводит сообщение if ($_POST['pass'] == '123' || empty($_POST['pass'])) < echo "Нельзя использовать популярные пароли. Придумайте свой!
"; > > ?>
Теперь если форма не прошла проверку, то все данные стираются, и нужно их вводить заново.
Давайте доработаем форму, чтобы исправить это, а также изменим место вывода ошибок.
В самом верху PHP-тега заводим 2 новые переменные, которые по стандарту пусты:
В проверке на пароль:
$error_pas .= "Нельзя использовать популярные пароли. Придумайте свой!
";
В проверке на логин:
.= означает то, что мы берём прошлую строку (пусто) и прибавляем к этому наше сообщение.
В форме HTML:
Добавляем после тега вставку PHP (в данном случае ), так как мы только выводим переменную. Суть проста: если ошибки в логине нет, тогда $error_login пуст, а следственно, ничего не выводится, иначе выводим там ошибку.
Введите логин:
Введите пароль:
Теперь доработаем форму, чтобы она сохраняла значения полей.
В самом начале добавляем 2 переменные:
В начало проверки на ‘нажата ли кнопка отправки’ добавляем:
$input_login = $_POST['login']; $input_pass = $_POST['pass'];
То есть мы заносим в переменные значения из суперглобального массива $_POST.
И немного изменяем нашу HTML-форму:
Введите логин: ">
Введите пароль: ">
Добавляем тег value, чтобы указать стандартное значение поля. Теперь если выдаётся ошибка, то значения полей сохраняются, и пользователю нужно не заново их вводить, а только исправить ошибку.
Заключение
Как видите, создать хорошую форму на PHP не так уж и сложно. Проверки, которые я показал в этой статье, не обязательно должны быть. Вы можете придумывать свои (любые) проверки на поля ввода, используя PHP. Надеюсь, что вам понравилась моя статья, и вы выучили что-то новое.
Итоговый код страницы с формой + обработчика: