Простая капча для FormIt в CMS MODX
Статья, в которой разберем, как в MODX Revolution с помощью графической капчи можно защитить форму обратной связи. Для обработки HTML формы будем использовать дополнение FormIt вместе с AjaxForm.
Создание капчи для её использования в MODX
Разработку капчи для MODX осуществим во внешнем php файле (например, captcha.php
). Для удобного хранения файлов в файловой структуре MODX будем использовать каталог captcha
, который создадим в assets
. Кроме captcha.php
в данный каталог поместим ещё файл с фоном (background.png
) и шрифт (oswald.ttf
). Скачать готовый архив каталога captcha можно с сервиса Яндекс.Диск.
assets/ ├── captcha/ │ ├── background.png │ ├── captcha.php │ └── oswald.ttf └── ...
Содержимое файла captcha.php
:
<?php require_once "../../core/model/modx/modx.class.php"; $modx = new modX(); $modx->initialize('web'); $id = 'captcha'; if (isset($_GET['id'])) { $id = filter_var($_GET['id'], FILTER_SANITIZE_STRING); } $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'; $captcha = substr(str_shuffle($string), 0, 6); $_SESSION[$id] = $captcha; $image = imagecreatefrompng(dirname(__FILE__).'/background.png'); $colour = imagecolorallocate($image, 200, 240, 240); $font = dirname(__FILE__).'/oswald.ttf'; $rotate = rand(-10, 10); imagettftext($image, 18, $rotate, 28, 32, $colour, $font, $captcha); header('Content-type: image/png'); imagepng($image);
Данный файл выполняет следующие действия:
- инициализацию системы MODX (это необходимо сделать для того, чтобы сгенерированный код капчи можно было использовать в элементах этой системы, например, в сниппетах);
- генерирование защитного кода и его регистрация в сессионной переменной;
- представление сгенерированного кода в виде изображения (в формате PNG).
Данный скрипт позволяет использовать несколько капч на одной странице. Это осуществляется посредством вызова данного файла с параметром id
. В качестве значения ключа id
необходимо указать имя CAPTCHA (например, captcha1
).
Применение капчи для защиты FormIt формы

Для обработки формы будем использовать дополнение (сниппет) FormIt
в сочетании с AjaxForm
. Сниппет AjaxForm
необходим для того, чтобы обеспечить работу с FormIt
через AJAX. Более подробно изучить работу сниппетов FormIt
и AjaxForm
можно в статье Как в MODX Revolution создать AJAX форму обратной связи.
Для внедрения капчи в форму необходимо выполнить следующие действия:
- создать кастомный валидатор для
FormIt
; - назначить проверку кода капчи этому валидатору;
- добавить в HTML форму элементы (
img
- изображение капчи,input
- поле для ввода разгаданного кода); - вставить на страницу JavaScript сценарий, который будет обновлять код капчи.
Создание пользовательского валидатора для FormIt
Для проверки того правильно или нет пользователь решил капчу напишем кастомный валидатор (например, имеющий имя isCaptchaValid
):
<?php $success = true; if (empty($value)) { $validator->addError($key,'Вы не ввели капчу!'); $success = false; } else { if (isset($_SESSION[$key])) { if (!($_SESSION[$key] == $value)) { $validator->addError($key,'Вы ввели неправильный код капчи!'); $success = false; } } else { $validator->addError($key,'Произошла ошибка при проверки кода капчи!'); $success = false; } } return $success;
Добавление капчи в HTML-форму
Вставить в HTML-форму, указанную в параметре form
сниппета AjaxForm
, следующий код капчи:
<form action="" method="post" class="ajax_form af_example"> ... <!-- Капча --> <div class="captcha"> <img class="img-captcha" src="/assets/captcha/captcha.php?rnd=[[!RandomNumber]]" data-src="/assets/captcha/captcha.php" height="46" width="132" style="display:inline-block;"> <div class="btn btn-default refresh-captcha"><i class="glyphicon glyphicon-refresh"></i> Обновить</div> <div class="form-group"> <label for="captcha" class="control-label">Пожалуйста, введите проверочный код:</label> <div class="controls"> <input id="captcha" name="captcha" type="text" class="form-control" required="required" value="" minlength="6" maxlength="6" autocomplete="off"> <span class="error_captcha"></span> </div> </div> </div> ... </form>
Сниппет randomNumber
предназначен для добавления случайного GET параметра (текущей метки времени с микросекундами) к URL. Это действие необходимо сделать для того, чтобы браузер не кэшировал ответ файла captcha.php
.
Пример сниппета RandomNumber
:
<?php return round(microtime(true)*1000);
Вызов сниппета AjaxForm с проверкой капчи
Добавить в вызов сниппета AjaxForm
(FormIt
):
- параметр
customValidators
со значениемisCaptchaValid
; - проверку поля CAPTCHA с помощью валидатора
isCaptchaValid
(параметрvalidate
).
[[!AjaxForm? &snippet=`FormIt` .. &customValidators=`isCaptchaValid` &validate=`...,captcha:isCaptchaValid` ... ]]
Пример вызова сниппета AjaxForm
с проверкой капчи:
[[!AjaxForm? &snippet=`FormIt` &form=`tpl.AjaxForm ` &hooks=`email` &emailSubject=`Тема письма` &emailTo=`to@email.ru` &emailFrom=`no-reply@mysite.ru` &emailFromName=`Мой сайт` &emailTpl=`tpl.email ` &customValidators=`isCaptchaValid` &validate=`name:required,email:required,message:required,captcha:isCaptchaValid` &validationErrorMessage=`Пожалуйста, исправьте ошибки!` &successMessage=`Ваше сообщение успешно отправлено!` ]]
JavaScript сценарий для обновления кода капчи
Вставить на страницу сценарий JavaScript, который будет обновлять код капчи в форме:
- после получения ответа от сервера;
- при нажатию на кнопку "Обновить".
$(function() { var refreshSrcCapctha = function(img) { var src = img.attr('data-src'); if (src.indexOf('?id') !== -1) { src += '&rnd='+(new Date()).getTime(); } else { src += '?rnd='+(new Date()).getTime(); } img.attr('src',src); } $(document).on('af_complete', function(event, response) { var form = response.form; if (form.find('.captcha').length == 1) { var img = form.find('.captcha .img-captcha'); refreshSrcCapctha(img); form.find('.captcha input').val(''); } }); $('.refresh-captcha').click(function(){ var img = $(this).closest('.captcha').find('.img-captcha'); refreshSrcCapctha(img); }); });
Пример использования нескольких капч на одной странице
Для того чтобы на одной странице можно было использовать несколько капч необходимо в каждую HTML форму внести следующие изменения:
- добавить в атрибуты
src
иdata-src
изображенияid
капчи; - установить в качестве значения атрибута
name
элементаinput
(в который пользователь вводит проверочный код)id
капчи; - изменить класс элемента
span
, который применяется для отображения ошибки так, чтобы он соответствовал значению атрибутуname
элементаinput
.
Пример капчи для первой HTML формы (tpl.AjaxForm1
):
<form action="" method="post" class="ajax_form af_example"> ... <!-- Капча --> <div class="captcha"> <img class="img-captcha" src="/assets/captcha/captcha.php?id=captcha1&rnd=[[!RandomNumber]]" data-src="/assets/captcha/captcha.php?id=captcha1" height="46" width="132" style="display:inline-block;"> <div class="btn btn-default refresh-captcha"><i class="glyphicon glyphicon-refresh"></i> Обновить</div> <div class="form-group"> <label for="captcha1" class="control-label">Пожалуйста, введите проверочный код:</label> <div class="controls"> <input id="captcha1" name="captcha1" type="text" class="form-control" required="required" value="" minlength="6" maxlength="6" autocomplete="off"> <span class="error_captcha1"></span> </div> </div> </div> ... </form>
Пример капчи для второй HTML формы (tpl.AjaxForm2
):
<form action="" method="post" class="ajax_form af_example"> ... <!-- Капча --> <div class="captcha"> <img class="img-captcha" src="/assets/captcha/captcha.php?id=captcha2&rnd=[[!RandomNumber]]" data-src="/assets/captcha/captcha.php?id=captcha2" height="46" width="132" style="display:inline-block;"> <div class="btn btn-default refresh-captcha"><i class="glyphicon glyphicon-refresh"></i> Обновить</div> <div class="form-group"> <label for="captcha2" class="control-label">Пожалуйста, введите проверочный код:</label> <div class="controls"> <input id="captcha2" name="captcha2" type="text" class="form-control" required="required" value="" minlength="6" maxlength="6" autocomplete="off"> <span class="error_captcha2"></span> </div> </div> </div> ... </form>
Пример вызова сниппета AjaxForm
для первой HTML формы:
[[!AjaxForm? &snippet=`FormIt` &form=`tpl.AjaxForm1` &hooks=`email` &emailSubject=`Тема письма` &emailTo=`to@email.ru` &emailFrom=`no-reply@mysite.ru` &emailFromName=`Мой сайт` &emailTpl=`tpl.email ` &customValidators=`isCaptchaValid` &validate=`name:required,email:required,message:required,captcha1:isCaptchaValid` &validationErrorMessage=`Пожалуйста, исправьте ошибки!` &successMessage=`Ваше сообщение успешно отправлено!` ]]
Пример вызовы сниппета AjaxForm
для второй HTML формы:
[[!AjaxForm? &snippet=`FormIt` &form=`tpl.AjaxForm2` &hooks=`email` &emailSubject=`Тема письма` &emailTo=`to@email.ru` &emailFrom=`no-reply@mysite.ru` &emailFromName=`Мой сайт` &emailTpl=`tpl.email ` &customValidators=`isCaptchaValid` &validate=`name:required,email:required,message:required,captcha2:isCaptchaValid` &validationErrorMessage=`Пожалуйста, исправьте ошибки!` &successMessage=`Ваше сообщение успешно отправлено!` ]]
Стояла ваша форма работала, все нормально. Но буквально только что обновившись до MODx 3.0 все перестало работать… помогите пожалуйста разобраться.
И за одним еще. По вашей же версии была разработана карусель для галереи объектов, на основе MIGx, с php ThumbOn. Сейчас тоже с ошибкой работает, не отображает изображения…
Не понимаю в чем может быть ошибка ((
Почему то при использовании двух капчей не появляются сообщения об отправке в правом верхнем углу.
Ошибок в консоли нет.
Установка .jGrowl еще дополнительных пары 99 не помогла. При этом сообщения отправляются.
И, если сообщение уходит со страницы где одна форма, то сообщение есть, если со страницы где две формы, то нет.
Что-то дополнительное править не нужно. Проверьте ответ, который вам присылает сервер (action.php). Данный ответ можно посмотреть на вкладке Network в браузере.
Вроде все по вашему сделал, но что то все же пошло не так. Получилось вот что:
То есть буквы не вмещаются, и по кнопке не происходит обновления. Пока еще посмотрю, но пока вот так. В чем может быть дело?