• Шаблоны для вашего сайта
  • Сделать сайт
  • Реклама
  • Berry CSS
  • Albireo Framework
  • Бесплатный HTML-курс
  • Telegram-канал
  • Обратная связь
MaxSite.org
О создании сайтов и не только
Создание сайтов под ключ (Украина) →
Вход
×
или зарегистрироваться

Обработка форм в PHP. Как это делать правильно в 2020 году

PHPПросмотров: 9372Комментарии: 38 июня 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-вывод, в свою очередь должен делиться на:

  • вывод самой формы
  • вывод положительного результата
  • и вывод ошибок

Поскольку нам нужен корректный HTML, то нужно вынести ещё и начальную часть html (секция HEAD) и конечную (BODY, HTML).

Основной (запускающийся) php-файл обычно называется фронт-контроллер (front controller). Да, этот термин больше из ООП, но в подавляющем большинстве php-модулей (и приложений), всегда есть точка входа, которая дальше уже подсоединяет все остальные файлы. Это функция контролёра, которая содержит основную логику модуля/приложения.

В нашем случае пусть это будет index.php:

<?php 
// Controller
 
define('BASE_DIR', __DIR__ . DIRECTORY_SEPARATOR);
 
if ($_POST) {
	require 'action/post.php';
} else {    
    require 'action/show.php';
}
 
# end of file

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

Алгоритм простой: если есть POST-данные, то подсоединяем файл action/post.php, где будем обрабатывать входящие данные и action/show.php, который служит для простого вывода формы.

Рассмотрим action/show.php:

<?php 
// action «show»
 
require BASE_DIR . 'layout/start.php';
require BASE_DIR . 'layout/form.php';
require BASE_DIR . 'layout/end.php';
 
# end of file

Форма собирается из нескольких файлов. Каталог layout хранит именно html-вывод. То есть, когда станет задача доработать дизайн формы, достаточно будет поправить какой-то один простой layout-файл.

Файл layout/start.php содержит начальную часть html-страницы:

<!doctype html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Form demo</title>
   <link href="assets/css/berry-normalize.min.css" rel="stylesheet">
</head>
<body>

Здесь я подключил css-файл от Berry CSS, который размещается в каталоге assets. Это «типовой» каталог для всех «оформительских» файлов: css/sass, js, fonts и images. Также обратите внимание, что путь задан относительный. Если нужно указывать полный url, то в контролёре следует определить ещё одну константу, например BASE_URL, которую и использовать для формирования начальной части URL.

Файл end.php просто корректно закрывает HTML:

</body>
</html>

Файл form.php содержит форму:

<div class="mar30-tb b-center w500px pad30-rl pad10-tb bordered rounded">
    <h1>Form demo</h1>
 
    <form method="POST">
        <div class="mar10-b">Email</div>
        <input class="w100" type="email" name="email" value="">
         
        <div class="mar10-b mar20-t">Password</div>
        <input class="w100" type="password" name="password" value="">
        
        <div class="mar10-b mar20-t">Info</div>
        <input class="w100" type="text" name="info" value="">
         
        <div><button class="mar20-tb" type="submit">Submit</button></div>
    </form>
</div>  

Это очень простой вариант с тремя полями: email, password и info. Обратите внимание, что у формы не указан параметр action, это означает, что post-данные формы будут отправлены по текущему URL-адресу.

В Сети полно примеров, когда action указывает на другой php-файл. Такая практика также изредка используется. В отличие от моего примера, такой модуль будет иметь два контролёра, а не один: в нашем случае мы определяем действие по переменой $_POST, а во втором случае — форма сама отправит запрос на «post-файл».

Рассмотрим цепочку выполнения данного участка кода.

  • Запускается index.php.
  • В нём смотрится наличие post-данных.
  • Если нет, то подключаем action/show.php.
  • В нём подключаются layout-файлы для вывода формы.

Если форма была отправлена, то происходит подключение action/post.php — это и есть обработчик формы.

<?php 
// action «post»
 
$data['email'] = $_POST['email'] ?? '';
$data['password'] = $_POST['password'] ?? '';
$data['info'] = $_POST['info'] ?? '';
 
if (!$data['info']) $data['info'] = 'No info';
 
$error = [];
 
if (!$data['email']) $error[] = 'Invalid email';
if (!$data['password']) $error[] = 'Invalid password';
 
require BASE_DIR . 'layout/start.php';
 
if (!$error) {
    require BASE_DIR . 'layout/result.php';
} 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 выводит список отправленных данных.

<div class="mar30-tb b-center w500px pad30-rl pad10-tb bordered rounded">
    <h1>Form result</h1>
    <ul><li><?= implode('<li>', $data) ?></ul>
</div>

А файл error.php выводит список ошибок.

<div class="mar30-tb b-center w500px pad30-rl pad10-tb bordered rounded">
    <h1>Form error</h1>
    <ul><li><?= implode('<li>', $error) ?></ul>
</div>  

Обратите внимание, что здесь мы уже выводим $error.

Вы можете скачать готовый пример.

Такой подход к построению php-модуля (или приложения) наиболее правильный. Если есть возможность, то разделяйте php и html-код по разным файлам. Это особенно актуально для проектов с более сложной логикой.

Пара слов о $data

Часто стоит задача передать в layout-файл какие-то данные. Например название формы, или уже введенные данные, чтобы пользователь их заново не вводил, а только поправил. Лучший способ это сделать — именно через массив. Причём такой, где заранее оговариваются обязательные ключи. Это позволяет избежать дополнительных isset-проверок при их выводе.

// action «post»
$data['title'] = 'Заголовок формы';
 
// layout
<h1><?= $data['title'] ?></h1>

Также распространён и другой приём — extract($data), для того, чтобы получить готовые переменные:

// layout
<?php extract($data) ?>
 
<h1><?= $title ?></h1>

Это достаточно простой шаблонизатор PHP.

Аля-MVC

Нетрудно заменить, что по своей сути код соответствует концепции MVC.

Контролёр выполняет основную логику модуля. В нашем случае он совпал с фронт-контроллером, но обычно фронт-контролёр — это уровень приложения, а просто контролёр — это уровень модуля.

Дальше контролёр дёргает определенную модель — в нашем случае это action-файлы. В модели происходит работа с данными и дальше модель передаёт управление в представление (view) — у нас это layout-файлы.

То есть у нас управление передаётся по цепочке: controller → model → view. Есть ещё один вариант, когда контролёр передаёт данные в модель, модель возвращает результат обратно, а потом контролёр их передаёт уже в представление. То есть вариант MVC будет определяться уже задачей или архитектурой приложения.

Валидация данных

И в заключение небольшой момент о валидации данных. Очень часто валидация — чуть ли не половина кода модели (action-файла), поэтому часто её также выносят в отдельный файл.


Создание сайтов (Украина) →
Краткий обзор Tailwind CSS
Понимание ООП на примере Паскаля
twitter.com facebook.com
Другие записи сайта
Чеклист (список задач, ToDo-лист)
Чеклист (список задач, ToDo-лист)
Как изменить стартовую страницу в Slimjet (Chrome)
Как изменить стартовую страницу в Slimjet (Chrome)
Релиз шаблона MF 11 (февраль 2021)
Релиз шаблона MF 11 (февраль 2021)
Автоматическая компиляция SASS в CSS
Автоматическая компиляция SASS в CSS
Работы по «MF». Редактирование записи на странице записи
Работы по «MF». Редактирование записи на странице записи
Почему нужно изучать LESS
Почему нужно изучать LESS

Комментариев: 3 RSS

1Андрей01-10-2020 09:37

Да уж, хорошо продуманная структура, действительно упрощает жизнь))

2Ден26-12-2020 10:03

А разве верно, что обработчик занимается логикой, что дальше выводить? Не лучше делать редирект назад откуда пришел запрос?

3MAX26-12-2020 15:30

Редирект не решает задачи — нужен именно обработчик входящих данных.

Оставьте комментарий!

Комментарий будет опубликован после проверки. Вы соглашаетесь с правилами сайта.

(обязательно)

Навигация
  • Шаблоны для MaxSite CMS 22
  • jQuery и JavaScript 6
  • Java и Android 5
  • PHP/ООП 25
  • SQL 17
  • Albireo Framework 11
  • Berry CSS 7
  • CSS, HTML, LESS, SASS 23
  • PHP 37
  • Тайм-менеджмент 9
  • Софт 37
  • SEO 13
  • Git. GitHub 3
  • CodeIgniter 5
  • Landing Page 3
  • Alpine.js 14
  • Фильмы 2
  • Дневник 55

Здесь можно заказать создание сайта (только Украина), шаблона или лендинга. Также вы можете выбрать готовые шаблоны для MaxSite CMS по небольшой цене. Также можно купить отдельные модули, компоненты для вашего сайта.

MaxSite.org
Как создать свой сайт

Услуги по созданию сайтов, блогов, лендингов
Обратная связь • Реклама на сайте
Карта сайта
Мои проекты
  • Шаблоны для вашего сайта
  • Заказать создание сайта
  • MaxSite CMS
  • Berry CSS (CSS Utilities)
  • Albireo Framework
  • UniCSS (Universal Atomic CSS)
  • Landing Page Framework
  • Бесплатные НТML-курсы
Ссылки
  • Telegram-канал
  • Github
  • Twitter
  • Telegram-бот
  • RSS
© MaxSite.org, 2006-2022. Работает на MaxSite CMS | Время: 0.2896 | SQL: 20 | Память: 4.64MB | Вход