Перейти к содержимому

Отправка формы через AJAX - проверка полей, защита, ответ с ошибками

Принимаем форму запросом без перезагрузки страницы: проверяем данные на сервере, закрываемся от ботов и отвечаем так, чтобы браузер показал ошибки по полям.

Решение

Отправляем данные вместе с идентификатором сеанса:

const data = new FormData(form);
data.append('sessid', BX.bitrix_sessid()); // без него запрос отклонят
const res = await fetch('/local/ajax/feedback.php', { method: 'POST', body: data });
const answer = await res.json();

Идентификатор сеанса подставляется в каждый пишущий запрос к сайту. Он и отличает форму, отправленную с вашей страницы, от запроса, собранного кем-то со стороны, а проверяет его сервер, а не браузер.

Принимаем и проверяем на сервере:

define('NO_KEEP_STATISTIC', true);
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
$errors = [];
if (!check_bitrix_sessid()) { $errors['form'] = 'Обновите страницу'; }
if (!filter_var($_POST['EMAIL'] ?? '', FILTER_VALIDATE_EMAIL)) { $errors['EMAIL'] = 'Неверная почта'; }
if (mb_strlen(trim($_POST['NAME'] ?? '')) < 2) { $errors['NAME'] = 'Укажите имя'; }

Проверка в браузере нужна для удобства гостя, а не для надёжности. Запрос к обработчику отправляется чем угодно, поэтому серверная проверка обязательна для каждого поля, включая скрытые.

Проверяем картинку с кодом:

if (!$APPLICATION->CaptchaCheckCode($_POST['captcha_word'] ?? '', $_POST['captcha_sid'] ?? '')) {
$errors['captcha'] = 'Код с картинки не совпал';
}
// код одноразовый: после проверки нужен новый идентификатор картинки

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

Отвечаем списком ошибок по полям:

header('Content-Type: application/json; charset=UTF-8');
if ($errors) {
echo Json::encode(['ok' => false, 'errors' => $errors]);
} else {
CEvent::Send('FEEDBACK_FORM', SITE_ID, ['NAME' => $_POST['NAME'], 'EMAIL' => $_POST['EMAIL']]);
echo Json::encode(['ok' => true]);
}
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php';

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

Обработчик стоит держать отдельным файлом, а не куском шаблона страницы. Файл переживает смену шаблона, отдаёт чистый ответ без разметки и проверяется запросом из консоли за одну команду.

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

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

Типичные проблемы

Запрос отклоняется с ошибкой сеанса.

В данные формы не добавлен идентификатор текущего сеанса. Пишущие запросы без него платформа просто не принимает.

В ответе приходит разметка вместо данных.

В обработчике подключён полный пролог вместе с шаблоном сайта. Для ответа данными берут облегчённое подключение ядра.

Форма проходит с пустыми полями.

Проверка полей сделана только на стороне браузера. Запрос к обработчику отправляется в обход страницы и её кода.

Код с картинки не совпадает со второй попытки.

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

Заявки приходят пустыми пачками.

Обработчик открыт всем и не ограничивает частоту отправки. Рассыльщики находят такие адреса за считанные дни.

Частые вопросы

Чем свой файл лучше контроллера платформы?

Ничем: контроллер даёт готовую проверку сеанса и единый формат ответа. Свой файл берут, когда нужен полный контроль над подключением.

Как показать ошибки рядом с полями?

Ответом с картой «поле - текст ошибки». Браузеру остаётся разложить её по полям формы.

Нужна ли картинка с кодом, если есть скрытое поле-ловушка?

Ловушка отсеивает простых ботов, картинка - настойчивых. На форме с деньгами лучше оба способа.

Куда сохранять заявки?

В веб-форму модуля или в свой инфоблок. Хранить только письмом - значит потерять заявку вместе с почтой.

Смежное

Первоисточник