Captcha. Использование Zend_Captcha_Image

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

В интернете есть достаточно количество подобных публикацией, с той лишь разницей, что все они рассматривают Zend_Captcha_Image в тандеме с Zend_Form, а я, как уже было написано выше, хотел бы избежать этого. Одна причина, как минимум, у меня имеется. Например, неоднократно приходилось внедрять защитное изображение в CMS, где изначально оно отсутствует. Разумеется, что формы, для которых использовалась captcha, создавались штатными средствами CMS и задействовать Zend_Form было либо невозможно, либо бессмысленно.

Собственно, почему именно Zend_Captcha_Image? Если вам доводилось изучать рынок CMS, то вы не могли не заметить, что в большинстве движков защитное изображение каптчи имеет совершенно одинаковый вид. Очень большую популярность завоевала библиотека, распространяемая сайтом captcha.ru. В итоге, данная каптча прекрасно распознается любым спам ботом, что делает ее совершенно бесполезной.




Может быть моя писанина о Zend_Captcha_image хоть кого-то натолкнет на мысль пойти чуть дальше в поиске решения проблемы защиты сайта от спама.

Не желая полностью копировать других авторов, буду описывать эту библиотеку в отрыве от всего остального фреймворка. То есть мы не будем использовать Zend_Form и иже с ней. Это даст возможность без особых проблем вкрутить каптчу в ваш сайт, даже если он отродясь не видел фреймворков и CMS.

Для работы Zend_Captcha_image потребуется наличие GD адекватной версии. Это не должно быть проблемой, тем не менее, если что-то не будет работать, убедитесь, что GD присутствует (смотрите в phpinfo).

Прежде всего, давайте вытащим из ZendFramework нужные нам библиотеки. Увы, взять только одну Zend_Captcha_image не получится, так как она имеет ряд зависимостей, к числу которых относится интерфейс для работы с сессиями, Zend_Loader и исключения. Это следующие файлы:

Zend/Captcha/Adapter.php
Zend/Captcha/Base.php
Zend/Captcha/Image.php
Zend/Captcha/Word.php
Zend/Session/SaveHandler/Interface.php
Zend/Session/Abstract.php
Zend/Session/Exception.php
Zend/Session/Namespace.php
Zend/Validate/Abstract.php
Zend/Validate/Interface.php
Zend/Exception.php
Zend/Loader.php
Zend/Session.php

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

application.php

<?php

/**
 * Массив с именами файлов шрифтов.
 * Каждый раз при генерации, будет выбираться случайный шрифт
 * @var array
 */
$fontsBase = array(
    'verdana.ttf',
    'arial.ttf'
);

/**
 * HTTP путь к директории с изображениями.
 * Указывается относительно корня сайта
 * @var string
 */
$imagesHttpPath = '/captcha/images';

set_include_path(
    PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] . '/libs'
);

require_once 'Zend/Captcha/Image.php';

$captcha = new Zend_Captcha_Image();

$captcha->setTimeout('600')
        ->setWordLen('5')
        ->setWidth(200)
        ->setHeight(90)
        ->setFont($_SERVER['DOCUMENT_ROOT'] . '/captcha/fonts/' . $fontsBase[array_rand($fontsBase)])
        ->setImgDir($_SERVER['DOCUMENT_ROOT'] . $imagesHttpPath)
        ->generate();

$captchaID = $captcha->getId();

?>

Дабы скрипт был чуть более интересным, я решил, что будет весьма неплохо рисовать картинку разными шрифтами. Это еще несколько усложнит отгадывание нашей каптчи. Список шрифтов хранится в массиве $fontsBase. Естественно, что лучше всего использовать какие-нибудь экзотические шрифты и избегать применения общедоступных системных.

Далее подключаем саму библиотеку и создаем объект. Чтобы не иклудить все зависимости вручную, я просто добавил путь к директории с ZF в include_path. Стандратная практика при использовании большинства фреймворков.

После создания объекта, задаем настройки защитного изображения. Имена методов говорят сами за себя. Остается пояснить лишь значение Zend_Captcha_Image::setTimeout(). Данный метод задает время жизни сессии, иными словами, за отведенное нами количество секунд, пользователь должен будет уж как-нибудь осилить заполнение формы. Иначе ему придется повторить ввод защитного кода, так как прежний станет недействительным. Думаю, 10 минут будет достаточно более, чем достаточно.

При таких настройках, мы получим примерно следующее изображение:

Также заметьте, что директория, задаваемая в Zend_Captcha_Image::setImgDir() должна существовать и быть доступна для записи. В нее буду помещаться сгенерированные изображения. Об очистке переживать не стоит, это будет происходить автоматически.

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

С формой все банально.

index.php

<?php
	require_once 'application.php';
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Captcha</title>
</head>
<body>

<form action="/target.php" method="post">
	Username: <input name="userName" /><br />
	Captcha: <input name="captchaCode" /><br />
	<input type="hidden" name="captchaId" value="<?php echo $captchaID ?>" />
	<img src="<?php echo $imagesHttpPath . '/' . $captchaID ?>.png" alt="" /><br />
	<input type="submit" value="Отправить" />
</form>

</body>
</html>

Поле captchaCode предназначено для введения текста с защитного изображения. В скрытом поле captchaId передаем ID сессии на скрипт, осуществляющий валидацию формы.

Валидатор формы. Проверка captcha кода

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

target.php

<?php

set_include_path(
    PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] . '/libs'
);

require_once 'Zend/Session/Namespace.php';

if ($sessionData = new Zend_Session_Namespace('Zend_Form_Captcha_' . $_POST['captchaId'])) {
    $iterator = $sessionData->getIterator();

    if ($_POST['captchaCode'] != $iterator['word']) {
        echo 'We have a problem with u, guy...';
    } else {
        echo 'Welcome, ' . $_POST['userName'] . '!';
    }
}

?>

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

Если подобрать хорошие шрифты, установить приличный уровень шума, то получится хорошая протекция от спама в формах. Главное, не забывайте, что помимо роботов, вашу форму захотят заполнить и люди. Не делайте код с картинки нечитаемым. Больше всего раздражает, когда невозможно разобрать символы на каптче, а следовательно правильно их ввести.

Также выкладываю архив со скриптами, о которых здесь шла речь: Zend_Captcha_Image_source

Комментарии (2)

  1. rudolfovich

    Может лучше так?
    $captcha = new Zend_Captcha_Image(array(
    «_id» => $id,
    ));
    $captchaWord = $captcha->getWord();

Добавить комментарий для Мурашов Олег Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *