Pull to refresh

Yii: капча против Ajax

Фреймворк — штука удобная. Нужна форма? Нет проблем. Создал таблицу в базе данных, запустил генератор кода и вуаля! Приложение уже готово взаимодействовать с пользователем по всем фронтам.
А уж если в фреймворк встроена валидация, которая проверит введенные данные (хорошо бы через ajax запрос, а не только через сабмит) и сообщит пользователю сайта об ошибках, то на душе становится совсем уж привольно.

Сегодня речь пойдет о фреймворке Yii, а конкретно о валидации форм, ну уж совсем конкретно — о проблеме совместимости капчи и ajax, при валидации. Дело в том, что после того как форма показана пользователю, при любом ajax-запросе, капча изменяется внутри фреймворка, в то время как на странице остается оригинальное изображение. В итоге, когда форма заполнена и отправлена на сервер, валидация заканчивается неудачей.

Эта проблема не раз обсуждалась на профильных форумах и в баг-трекере. В итоге лучшее, что могут предложить авторы фреймворка — установить неограниченное количество показов одной и той же капчи пользователю. Решение, прямо сказать, не логичное. Любой робот, однажды распознав капчу, сможет сколько угодно бродить по сайту и оставлять сообщения, гадить в комментариях или того хуже — подбирать пароли пользователей перебором.

Как оказалось решение проблемы не такое сложное, если не сказать — банальное.

В первую очередь необходимо создать новый валидатор activeCaptcha, который будет пользоваться стандартным контроллером класса Captcha.

public function activeCaptcha() {
$code = Yii::app()->controller->createAction('captcha')->getVerifyCode();
if ($code != $this->verifyCode)
$this->addError('verifyCode', 'Неправильный код проверки.');
if (!(isset($_POST['ajax']) && $_POST['ajax']==='user-form'))
Yii::app()->controller->createAction('captcha')->getVerifyCode(true);
}


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

После этого необходимо задать правила валидации для атрибутов модели (используя валидатор «activeCaptcha» вместо «captcha»):
array('verifyCode', 'activeCaptcha', 'on'=>'register')

Если у вас отключена ajax-валидация форм, то теперь ее можно включить.
В представлении (view) пишем:
$form=$this->beginWidget('CActiveForm', array(
'id'=>'user-form',
'enableAjaxValidation'=>true,
));


И в контролере:
$this->performAjaxValidation($model);

Теперь можно запустить веб-приложение и увидеть, что все работает как надо:
капча обновляется при каждом обновлении страницы и после сабмита формы. При этом при заполнении формы капча ведет себя культурно и пользователь может воспользоваться ей без всяких проблем.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.