О том, что такое CAPTCHA и зачем она нужна, думаю рассказывать не нужно. Все, кто хоть раз регистрировался на каком-нибудь интернет-сервисе, прекрасно понимают, о чем идет речь.
В этой статье мы посмотрим, как создать несложную CAPTCHA, добавить ее к форме, и проверить правильно ли посетитель ввел ее значение. Посмотреть действующий пример можно здесь.
Сразу хочу отметить, что речь пойдет именно о работе с CAPTCHA, а не о создании рисунка для нее.
Поэтому мы используем готовую библиотеку для создания рисунка CAPTCHA. Библиотека называется достаточно незамысловато – captcha и может использоваться вместе с фрэймворком CodeIgniter. В описании библиотеки приведен пример ее использования на обычной странице, поэтому мы рассмотрим вариант проверки с применением технологии ajax.
Переходим к решению нашей задачи. Прежде всего, необходимо четко понимать, чем работа с captcha отличается от работы с обычным полем.
Разница заключается в том, что в случае captcha посетитель должен ввести заранее определенное значение (обычно оно нарисовано на картинке). Значит, мы должны каким-то образом сохранить это значение, а затем использовать для проверки.
Для хранения данных captcha мы используем базу данных, а отличать посетителей друг от друга будем по их ip адресу.
Примечание. Это, конечно, не единственное решение.
Т.к. в этом примере мы используем CodeIgniter, то предположим, что у нас есть контроллер (captchademo.php), который содержит два метода: index()
(создает страницу с формой) и ajaxcheck()
(выполняет проверку и обработку данных формы). Отправку ajax запроса и обработку его результатов будут выполнять функции, размещенные в checkcaptcha.js
. Чтобы сократить количество JavaScript кода, используем библиотеку prototype.
Принцип работы captcha показан на диаграмме.
Рассмотрим его немного подробнее.
При входе на страницу с формой, выполняется метод index
контроллера, который создает страницу с формой и отправляет ее браузеру.
function index() { $this->load->library('captcha'); //создаем captcha $vals = array( 'word' => mt_rand(0, 9999), 'img_path' => str_replace(SELF, "", FCPATH).'uploads'.DIRECTORY_SEPARATOR, 'img_url' => base_url().'uploads/', 'font_path' => str_replace(SELF, "", FCPATH).'system'.DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.'AntsyPants.ttf', 'img_width' => '100', 'img_height' => '30', 'expiration' => '7200' ); $cap = $this->captcha->create_captcha($vals); //добавляем запись с данными captcha в БД $data = array( 'captcha_id' => '', 'captcha_time' => $cap['time'], 'ip_address' => $this->input->ip_address(), 'word' => $cap['word'] ); $query = $this->db->insert_string('captcha', $data); $this->db->query($query); $pageData['title'] = "Тестирование CAPTCHA"; $pageData['scripts'] = array('js/prototype.js', 'js/checkcaptcha.js'); $pageData['image'] = $cap['image']; $this->load->view('header', $pageData); $this->load->view('captcha'); $this->load->view('footer'); }
В строках 2-13 мы загружаем библиотеку captcha и создаем массив с настройками.
word
– текст, нарисованный на картинке;
img_path
– путь к изображениям;
img_url
– адрес изображений;
font_path
– путь к файлу со шрифтом, который будет использоваться (/system/fonts/);
img_width
– длина картинки;
img_height
– высота картинки;
expiration
– время «жизни» (в секундах).
Как видите, ничего сложного, самое главное правильно указать путь и адрес файлов с картинками (для этого использована функция base_url()
и несколько констант, которые инициализируются в index.php).
Примечание. Для того, чтобы приведенный здесь код работал, библиотека captcha должна быть размещена в папке system/application/libraries
либо system/libraries
. Кроме того, необходимо создать таблицу в БД для хранения данных captcha:
CREATE TABLE `captcha` ( `captcha_id` bigint(13) unsigned NOT NULL auto_increment, `captcha_time` int(10) unsigned NOT NULL, `ip_address` varchar(16) NOT NULL default '0', `word` varchar(20) NOT NULL, PRIMARY KEY (`captcha_id`), KEY `word` (`word`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Обратите внимание. Мы задали все параметры явно, хотя большинство из них можно не задавать. Но оказалось, что значения по-умолчанию подобраны не лучшим образом и текст попросту не помещается на рисунке. Возможно, это зависит от используемых шрифтов, но все равно, стоит убедиться, что текст виден.
После того, как объект captcha создан, добавляем его данные в БД (строки 15-22).
А дальше – загружаем представление, которое содержит нашу форму. Обратите внимание, url
рисунка передан в $pageData['image']
(строка 26). Таким образом, в представлении будет создана переменная $title
с адресом рисунка.
Сама форма выглядит следующим образом:
<form action="#" method="post"> <p> <label for="checkcode">Введите число, изображенное на картинке *: </label> <input type="text" size="30" id="checkcode" /> <?php echo $image; ?> </p> <p> <input type="button" value="Проверить" id="sendBtn" onclick="check('<?php echo site_url(); ?>', '<?php echo base_url(); ?>')" /> </p> </form> <div id="res"></div>
Эта форма содержит только одно поле – для ввода captcha.
После нажатия на кнопку «Проверить» будет вызвана функция check
(находится в файле checkcaptcha.js), которая в качестве параметров получит адрес сайта. Эта информация используется для отправки запроса и вставки анимации (о ней чуть ниже).
Примечание. В строках 27 и 29 метода index()
мы загрузили представления с заголовком и хвостовиком страницы. Хвостовик не содержит ничего кроме закрывающих тегов, а вот заголовок загружает js библиотеки.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ru"> <head> <title><?php echo $title; ?></title> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" href="<?php echo base_url(); ?>css/styles.css" /> <?php if (isset($scripts)) { foreach ($scripts as $script) { echo "<script src=\"".base_url().$script."\" type=\"text/javascript\" />\n"; } } ?> </head> <body>
Теперь рассмотрим, функцию check
, которая вызывается при нажатии на кнопку «Проверить».
function check(siteUrl, baseUrl) { var pars = $H({check:$('checkcode').value}); $('res').innerHTML = '<img src=\"' + baseUrl + '/css/images/ajax-loader.gif' + '\" alt=\"Отправка данных...\" />'; $('sendBtn').style.display = "none"; new Ajax.Request( siteUrl + "/captchademo/ajaxcheck", { parameters:pars.toQueryString(), onComplete: function(transport) { var response = eval("(" + transport.responseText + ")"); $('sendBtn').style.display = ""; if (response.state == "OK") { $("res").innerHTML = "Правильно!<br />"; } else { $("res").innerHTML = response.errMessages; } }, onFailure: function() { alert("Error"); } } ); }
В строке 2 мы читаем введенное значение.
После этого, прячем кнопку «Проверить» и вставляем картинку с анимацией (строки 2 и 3).
Примечание. Я сделал картинку с анимацией с помощью сервиса www.ajaxload.info.
В строке 5 создаем и отправляем запрос.
Если запрос выполнен успешно, то для обработки его результатов будет вызвана анонимная функция, определенная в параметре onComplete
(строки 9-18).
Эта функция возвращает на место кнопку «Проверить» (строка 11) и отображает сообщение с результатом.
Теперь переходим к коду обработки ajax запроса на стороне сервера. Напомню, что этот код находится в методе ajaxcheck()
контроллера.
function ajaxcheck() { $this->load->library('validation'); $rules['check'] = "required|callback_captcha_check"; $this->validation->set_rules($rules); $fields['check'] = "captcha"; $this->validation->set_fields($fields); if ($this->validation->run()) { $res['state'] = "OK"; //тут будет код, обрабатывающий данные формы } else { $res['state'] = "ERR"; $res['errMessages'][] = $this->validation->check_error; } echo json_encode($res); return; }
Здесь мы, прежде всего, подключаем библиотеку validation. О ней можно почитать в статье «Проверка данных из форм (CodeIgniter)», поэтому подробно останавливаться на ее работе я не буду.
Главное, обратите внимание, что для проверки полученного значения мы создали правило callback_captcha_check
(строка 4), а это значит, что нужно написать метод, который эту проверку будет выполнять.
function captcha_check($str) { $exp = time() - 7200; $this->db->query("DELETE FROM captcha WHERE captcha_time < ".$exp); $qFind = "SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND captcha_time > ?"; $data = array($this->input->post('check'), $this->input->ip_address(), $exp); $query = $this->db->query($qFind, $data); $row = $query->row(); if ($row->count == 0) { $this->validation->set_message('captcha_check', 'Введенное число не соотвествует, изображенному на рисунке'); return FALSE; } else { return TRUE; } }
Здесь мы выполняем все операции, приведенные на диаграмме в начале статьи. А именно:
— удаляем из БД все устаревшие записи (строки 2 и 3);
— пробуем найти запись, у которой значения полей ip_address
и word
совпадают с переданными;
— если такая запись найдена, возвращаем true
;
— в противном случае – создаем сообщение с описанием ошибки и возвращаем false
.
После выполнения проверки метод ajaxcheck()
формирует ответ (строки 11-16) и отправляет его браузеру.
Примечание. Ответ отправляется в формате json. Подробнее о нем можно почитать в статье «Использование JSON в web приложениях».
Кстати, удаление использованных устаревших рисунков выполняется библиотекой автоматически, поэтому можете не бояться, что они займут много места.
Как видите, работа с библиотекой достаточно простая, хотя многие операции приходится выполнять вручную (в смысле писать самостоятельно код).
SourceДо встречи!