Обработка форм в 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. Здесь основным является то, что каждый элемент формы автоматически становится доступным вашим программам на PHP. Для подробной информации об использовании форм в PHP читайте раздел Переменные из внешних источников. Вот пример формы HTML:
Пример #1 Простейшая форма HTML
В этой форме нет ничего особенного. Это обычная форма HTML без каких-либо специальных тегов. Когда пользователь заполнит форму и нажмёт кнопку отправки, будет вызвана страница action.php . В этом файле может быть что-то вроде:
Пример #2 Выводим данные формы
Пример вывода данной программы:
Здравствуйте, Сергей. Вам 30 лет.
Если не принимать во внимание куски кода с htmlspecialchars() и (int) , принцип работы данного кода должен быть прост и понятен. htmlspecialchars() обеспечивает правильную кодировку «особых» HTML-символов так, чтобы вредоносный HTML или Javascript не был вставлен на вашу страницу. Поле age, о котором нам известно, что оно должно быть число, мы можем просто преобразовать в int , что автоматически избавит нас от нежелательных символов. PHP также может сделать это автоматически с помощью модуля filter. Переменные $_POST[‘name’] и $_POST[‘age’] автоматически установлены для вас средствами PHP. Ранее мы использовали суперглобальную переменную $_SERVER , здесь же мы точно так же используем суперглобальную переменную $_POST , которая содержит все POST-данные. Заметим, что метод отправки (method) нашей формы — POST. Если бы мы использовали метод GET, то информация нашей формы была бы в суперглобальной переменной $_GET . Кроме этого, можно использовать переменную $_REQUEST , если источник данных не имеет значения. Эта переменная содержит смесь данных GET, POST, COOKIE.
В PHP можно также работать и с XForms, хотя вы найдёте работу с обычными HTML-формами довольно комфортной уже через некоторое время. Несмотря на то, что работа с XForms не для новичков, они могут показаться вам интересными. В разделе возможностей PHP у нас также есть короткое введение в обработку данных из XForms.
User Contributed Notes 3 notes
According to the HTTP specification, you should use the POST method when you’re using the form to change the state of something on the server end. For example, if a page has a form to allow users to add their own comments, like this page here, the form should use POST. If you click «Reload» or «Refresh» on a page that you reached through a POST, it’s almost always an error — you shouldn’t be posting the same comment twice — which is why these pages aren’t bookmarked or cached.
You should use the GET method when your form is, well, getting something off the server and not actually changing anything. For example, the form for a search engine should use GET, since searching a Web site should not be changing anything that the client might care about, and bookmarking or caching the results of a search-engine query is just as useful as bookmarking or caching a static HTML page.
Also, don’t ever use GET method in a form that capture passwords and other things that are meant to be hidden.
PHP Form Handling
The PHP superglobals $_GET and $_POST are used to collect form-data.
PHP — A Simple HTML Form
The example below displays a simple HTML form with two input fields and a submit button:
Example
When the user fills out the form above and clicks the submit button, the form data is sent for processing to a PHP file named «welcome.php». The form data is sent with the HTTP POST method.
To display the submitted data you could simply echo all the variables. The «welcome.php» looks like this:
The output could be something like this:
The same result could also be achieved using the HTTP GET method:
Example
and «welcome_get.php» looks like this:
The code above is quite simple. However, the most important thing is missing. You need to validate form data to protect your script from malicious code.
Think SECURITY when processing PHP forms!
This page does not contain any form validation, it just shows how you can send and retrieve form data.
However, the next pages will show how to process PHP forms with security in mind! Proper validation of form data is important to protect your form from hackers and spammers!
GET vs. POST
Both GET and POST create an array (e.g. array( key1 => value1, key2 => value2, key3 => value3, . )). This array holds key/value pairs, where keys are the names of the form controls and values are the input data from the user.
Both GET and POST are treated as $_GET and $_POST. These are superglobals, which means that they are always accessible, regardless of scope — and you can access them from any function, class or file without having to do anything special.
$_GET is an array of variables passed to the current script via the URL parameters.
$_POST is an array of variables passed to the current script via the HTTP POST method.
When to use GET?
Information sent from a form with the GET method is visible to everyone (all variable names and values are displayed in the URL). GET also has limits on the amount of information to send. The limitation is about 2000 characters. However, because the variables are displayed in the URL, it is possible to bookmark the page. This can be useful in some cases.
GET may be used for sending non-sensitive data.
Note: GET should NEVER be used for sending passwords or other sensitive information!
When to use POST?
Information sent from a form with the POST method is invisible to others (all names/values are embedded within the body of the HTTP request) and has no limits on the amount of information to send.
Moreover POST supports advanced functionality such as support for multi-part binary input while uploading files to server.
However, because the variables are not displayed in the URL, it is not possible to bookmark the page.
Developers prefer POST for sending form data.
Next, lets see how we can process PHP forms the secure way!