Добавляем CAPTCHA к форме. Пример PHP скрипта, использующего AJAX.

О том, что такое CAPTCHA и зачем она нужна, думаю рассказывать не нужно. Все, кто хоть раз регистрировался на каком-нибудь интернет-сервисе, прекрасно понимают, о чем идет речь.

В этой статье мы посмотрим, как создать несложную CAPTCHA, добавить ее к форме, и проверить правильно ли посетитель ввел ее значение.

Сразу хочу отметить, что речь пойдет именно о работе с CAPTCHA, а не о создании рисунка для нее.

Поэтому мы используем готовую библиотеку для создания рисунка CAPTCHA. Библиотека называется достаточно незамысловато – captcha и может использоваться вместе с фрэймворком CodeIgniter. В описании библиотеки приведен пример ее использования на обычной странице, поэтому мы рассмотрим вариант проверки с применением технологии ajax.

Переходим к решению нашей задачи. Прежде всего, необходимо четко понимать, чем работа с captcha отличается от работы с обычным полем.

Разница заключается в том, что в случае captcha посетитель должен ввести заранее определенное значение (обычно оно нарисовано на картинке). Значит, мы должны каким-то образом сохранить это значение, а затем использовать для проверки.

Для хранения данных captcha мы используем базу данных, а отличать посетителей друг от друга будем по их ip адресу.

Примечание. Это, конечно, не единственное решение.

Т.к. в этом примере мы используем CodeIgniter, то предположим, что у нас есть контроллер (captchademo.php), который содержит два метода: index() (создает страницу с формой) и ajaxcheck() (выполняет проверку и обработку данных формы). Отправку ajax запроса и обработку его результатов будут выполнять функции, размещенные в checkcaptcha.js. Чтобы сократить количество JavaScript кода, используем библиотеку prototype.

При входе на страницу с формой, выполняется метод 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.

Главное, обратите внимание, что для проверки полученного значения мы создали правило 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.

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

Как видите, работа с библиотекой достаточно простая, хотя многие операции приходится выполнять вручную (в смысле писать самостоятельно код).
Теги:
CAPTCHA, AJAX.
Добавлено: 21 Апреля 2018 07:16:14 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...