Обновление от 18.09.2015: изменён исходный код примера — теперь не нужно перезагружать страницу даже если через форму отправляется файл.

Это небольшой урок, в котором мы будем делать форму обратной связи. После того, как пользователь заполнит необходимые поля, введённые данные будут отправляться на сервер посредством AJAX-запроса. Если данные невалидные (например, отсутствуют обязательные для заполнения поля), то соответствующее сообщение будет показано пользователю.

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

Я знаю, что в Интернете огромное множество готовых решений, в том числе с очень красивыми формами. Более того, значительная часть этого кода была «подсмотрена» у других. Главная цель написания статьи — систематизировать собственные знания о функции отправки почты в PHP-скрипте. Если кому-то моя заметка пригодится и сэкономит время, то я буду очень рад.

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

Кстати, для тестирования отправки почты на локалхосте незаменимой станет почтовая заглушка. Поэтому рекомендую посмотреть статью «Почта на локальном сервере — установка почтовой заглушки».

Я разделил код на два файла: файл с формой и файл обработчик/отправитель письма. Конечно, можно всё собрать в один файл, но для образовательных целей лучше полностью разделить PHP и HTML код для наглядности.

Это наша форма:

Одной её уже достаточно, чтобы принять и отправить сообщение на сервер. Я не буду останавливаться на описании полей — т.к. это совсем просто.

В первой строке:

<form method=»post» action=»mails_sender.php» id=»feedback» name=»feedback» enctype=»multipart/form-data»>

mails_sender.php — означает имя файла, которому отправляются данные из формы для обработки.

enctype=»multipart/form-data» — выбран этот метод кодирования данных, поскольку к форме может быть присоединён файл.

id=»feedback» name=»feedback» задано и имя и айди для AJAX.

Данная форма вполне работоспособна и может выполнять свои функции. Использование AJAX позволяет отправлять на сервер запросы без перезагрузки страницы. Это здорово улучшает юзабилити, нравится пользователям, ведь в случае ошибки им не нужно заново вводить все данные — достаточно только исправить ошибку.

Этой строкой мы подключаем JQuery, эта библиотека на порядок облегчает AJAX-запросы, да и другие действия, для которых можно использовать «чистый» JavaScript:

<script src=»//code.jquery.com/jquery-2.1.4.min.js»></script>

Ещё две новых строки:

Первая строка представляет собой div элемент, для которого задан стиль (красный цвет), но в котором ничего нет, т. е. при загрузке формы он невидим. В него мы будем записывать ответы, полученные от сервера.

Вторая строка — это гифка «ожидание». При загрузке формы для неё задан стиль невидимости.

Код JavaScript/JQuery довольно объёмный, но больше половина строк в нём — это комментарии. Я не буду переписывать здесь содержимое комментариев, посмотрите сами — на мой взгляд, довольно доступно.

Наш JavaScript/JQuery (form.htm) у нас получился таким:

Второй файл называется mails_sender.php и содержание у него следующее:

В нём также много комментариев и, на мой взгляд, код достаточно простой для понимания.

Разве что можно сделать несколько ремарок по поводу блока:

Про использование фильтров валидации и очистки данных я рекомендую посмотреть официальную справку от PHP. Фильтр filter_input(INPUT_POST, ‘имя_элемента_формы’, FILTER_VALIDATE_EMAIL) валидирует почтовый адрес. Если адрес электронной почты неверен, то возвращается пустая строка.

Для сообщения мы дополнительно используем фильтр тэгов с помощью функции strip_tags. При этом в кавычках мы перечисляем разрешённые тэги. Если мы хотим, чтобы были отброшены все тэги и все специальные символы, то мы можем использовать filter_input(INPUT_POST, ‘имя_элемента_формы’, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); в результате чего удаляются все тэги, удаляются и кодируются специальные символы.

Но если мы хотим, чтобы некоторые тэги передавались (актуально для HTML-писем с разметкой), то мы используем более мягкий фильтр FILTER_SANITIZE_MAGIC_QUOTES, который эквивалентен функции addslashes(). Применением этого фильтра мы защищаемся от SQL-инжектов. Мы фильтруем остальные тэги для защиты от XSS-атак.

Предотвращения спама из формы обратной связи

Форма обратной связи выгодно отличается от формы добавления комментариев тем, что она не интересна «ссылочным» спамерам, которые пишут комментарий только для того, чтобы разместить свою ссылку.

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

Форма обратной связи может стать объектом «шутки» когда через неё присылается большое количество сообщений (иногда бессмысленных). Нормальные люди при этом не используют форму для отправки (нормальным людям это просто лень), а пишут скрипт/программу, которая напрямую отправляет обработчику сообщения. В качестве простого фильтра можно использовать отсев запросов, в заголовках которых отсутствует должный реферер или присутствует нестандартный пользовательский клиент. К сожалению, эти данные легко подменить, поэтому дополнительно для предотвращения этого, можно в форму добавить скрытое поле. На сервере, при получении сообщения, проверять, присутствует ли значение этого скрытого поля. Если нет — сообщение можно смело игнорировать и не беспокоить им админа.

Для простых случаев достаточно статичного скрытого поля. Если же вам «шутники» досаждают слишком много, то это поле можно сделать переменным. Например, в это поле можно записывать хеш от сегодняшнего числа + какой-нибудь соли. Т.е. скрытое поле будет «протухать» в течение дня, чтобы злоумышленник опять мог отправлять сообщения, ему нужно будет зайти на ваш сайт, чтобы увидеть новое значение скрытого поля.

Токен (метку) скрытого поля можно устанавливать и одноразовые. Главное, не делайте слишком короткое время «протухания» токена. Многие валидные пользователи пишут сообщение долго и если пользователь старался, два часа писал умное длинное сообщение, а оно не было принято сервером из-за каких-то фобий админа, то после этого пользователь может быстро написать короткое и обидное сообщение. 🙂

Если всё вышеназванное не помогает, то можно ввести ограничение на максимальное число отправленных сообщений с одного IP за определённый промежуток времени. Ну и опять можно вспомнить про капчу как про крайний вариант.

Если у вас есть своё видение по этому вопросу (а вариантов здесь множество), то буду рад увидеть ваше мнение в комментариях.

Похожие темы

Разрешение проблемы с Warning: mysqli::mysqli(): T... На моём хостинге можно выбирать версию PHP. На выбор предоставляются PHP 5.2 / 5.3 / 5.4 / 5.5 / 5.6. Много лет назад, когда я только создавал свой ...
Новости софта от 19 июля 2015 года (Router Scan v2... Router Scan v2.52 by Stas'M Про Router Scan v2.52 by Stas'M уже писалось в статье «Router Scan by Stas’M на Kali Linux (взло...
Самые частые ошибки и вопросы при настройке и уста... Ошибка: Fatal error: Call to undefined function mb_detect_encoding() in C:serverdatahtdocsphpmyadminlibrariesphp-gettextgettext.inc on line 177 Реше...
Новости софта от 13 февраля 2015 года (jQuery, Ver... jQuery UI 1.11.3 Вышла третья версия jQuery UI из линейки 1.11. Пакет с темами для этой версии можете скачать по этой ссылке: http://jqueryui.co...
Новости софта от 31 декабря 2014 года (PHP, phpMyA... PHP 5.6.4, PHP 5.5.20, PHP 5.4.36 Обновились все три поддерживаемых ветки PHP. Исправлений достаточно много, в ядре и в различных модулях, но кр...