Создание каптчи на PHP при помощи GSCP
В процессе подготовки форума, самым очевидным образом возник вопрос о создании формы регистрации. А по сложившейся традиции, в такой форме всегда имеется каптча — картинка с набором символов, которые предлагается ввести в текстовое поле ввода.
Примечание
Само понятие каптчи появилось от CAPTCHA, что является аббревиатурой Completely Automated Public Turing test to tell Computers and Humans Apart. В переводе с английского — «полностью автоматизированный публичный тест Тьюринга для различия компьютеров и людей», или ПАПТРКЛ. Однако русский перевод аббревиатуры труднопроизносим, и потому используется калька с английского, причем иногда буква Т ради благозвучия пропадает и получается просто «капча».
Сам генератор каптчи, к слову, уже имелся в распоряжении — класс TCaptcha был реализован еще в версии 1.5 PHP-библиотеки GSCP. Теперь осталось сделать 2 вещи: использовать имеющийся генератор картинки-каптчи и сделать так, чтобы её можно было проверить.
Создание CAPTCHA при помощи PHP
Первым делом нам потребуется GSCP версии 1.5 или выше (используем только что вышедший релиз-кандидат 1.6). Скачиваем архив со скриптами и подключаем к своему скрипту, который назовем captcha_image.php нужный PHP-файл — captcha.php:
include("captcha.php");
Собственно, 99% работы по части генерации картинки для капчи сделано, осталось лишь создать экземпляр класса и настроить параметры гнерации изображения. В таблице ниже приведены основные свойства класса Tcaptcha.
Свойство | Тип данных | Описание |
---|---|---|
$ctext | Строка | Текст для каптчи. Используется для записи, если вы желаете использовать собственные варианты, а не автоматически генерированные последовательности символов, и для чтения - после работы генератора (метод GenerateText()) |
$symbols | Массив | Массив символов, из которых генерируется строка для каптчи. По умолчаннию указаны все цифры и буквы латиницы, кроме нуля и букв «I» и «О» - во избежание путаницы |
$minlength | Целое число >0 | Минимальное число символов в каптче. По умолчанию 5. |
$maxlength | Целое число >0 | Максимальное число символов в каптче. По умолчанию 7. |
$bgcolor | Цвет в 16-ричном формате | Цвет фоновой заливки для каптчи (если не используется фоновый рисунок). По умолчанию 0xffffff. |
$fontcolor | Цвет в 16-ричном формате | Цвет шрифта. По умолчанию 0xffffff. |
$fontsize | Целое число >0 | Размер шрифта. По умолчанию 2 (средний системный), если указан шрифт (см. fontname), то следует указать размер от 9-10 и выше. |
$fontname | Строка | Имя файла со шрифтом TTF. По умолчанию не определен, используется встроенный GD-шрифт. |
$waves | Целое число от 0 до 3 | Волновые искажения текста в каптче: 0 - нет, 1 — по горизонтали, 2 — по вертикали, 3 – по обеим осям. По умолчанию 1. |
$lines | Целое число от 0 до 3 | Штрихи. 0 — нет, 1 — цветом фона, 2 — цветом текста, 3 — оба. По умолчанию 0. |
$angle | Целое число | Поворот в градусах. Типично используйте не более +/- 2-3 градуса для прямоугольной каптчи. По умолчанию 0. |
$width, $height | Целое число >0 | Ширина и высота рисунка, соответственно. В пикселях. По умолчанию 130 на 50. |
Собственно, достаточно написать 3 маленьких строчки кода:
$c = new Tcaptcha();
$c->GenerateText();
$c->Make();
И этого будет достаточно, чтобы получить изображение-капчу размерами 50 на 130 пикселей, состоящую из 5-7 символов и умеренно устойчивую к взлому. Впрочем, можно несколько усложнить (или наоборот, упростить) каптчу, изменить её размеры, фон, цвет и гарнитуру шрифта. Правда, в последнем случае понадобится установленная на стороне хостера поддержка ImageMagick со всеми вытекающими (поддержка TTF-шрифтов и т.д.). Если все это имеется, то можно использовать для своей каптчи, скажем, шрифт Arial с полужирным начертанием. В таком случае можно установить еще и размер шрифта, да и с другими свойствами поэкспериментировать. Для этого между созданием экземпляра класса ($c = new Tcaptcha();) и вызовом метода генерации текста ($c->GenerateText();) можно вставить следующие строки:
$c->fontname = "../arialbd.ttf"; // устанавливаем шрифт
$c->fontsize = 18; //устанавливаем размер шрифта
$c->fontcolor = 0xa0040f; //устанавливаем цвет шрифт
$c->bgcolor = 0xfeecca; //устанавливаем фоновый цвет каптчи
$c->angle = -2; // устанавливаем угол поворота текста
$c->waves = 1; // волновые искажения пусть останутся по горизонтали
$c->lines = 2; // заштрихуем цветом текста
$c->minlength = 6; // в этой и следующей строках устанавливаем фиксированное число символов в каптче - 6
$c->maxlength = 6;
Весь этот код следует поместить в какой-либо файл, который и будет картинкой (не забудьте про «include("captcha.php");» в самом начале, да и про расположение файлов библиотеки и шрифта - тоже). Назовем свой скрипт captcha_image.php. Вы можете запустить го из адресной строки браузера, например:
http://www.sitename.ru/classes/captcha_image.php
И вы увидите свою капчу.
Использование каптчи для проверки форм
Сама по себе каптча, в общем-то не нужна. Ведь суть CAPTCHA – отличать ботов от реальных посетителей. Так что давайте рассмотрим использование на примере, скажем, формы авторизации — чтоб не пытались «в лоб» брутфорсить пароли. Для этих целей в GSCP имеется стандартные формы авторизации и даже скрипты для проверки. Мы не будем их тут подробно рассматривать, но суть в том, что в версии 1.6 как раз добавлена поддержка каптчи на стандартной форме ввода логина-пароля, и для создания нужной формы достаточно подключить скрипт stdforms.php и написать:
$frm = new TStdLoginForm(NULL, "authfrm", "check.php", 11, "Введите логин, пароль и символы с картинки: ");
Суть сего сводится к генерации следующего HTML-кода:
<form name="authfrm" enctype="application/x-www-form-urlencoded" action="check.php" method="post">
<fieldset>
<legend>Введите логин и пароль: </legend>
<label for="elogin">Логин</label>
<input name="elogin" type="text" size="10" />
<label for="epasswd">Пароль</label>
<input name="epasswd" type="password" size="10" />
<label for="captcha">CAPTCHA</label>
<input name="captcha" type="text" size="10" />
<img src="captcha_image.php" alt="CAPTCHA" />
<input name="submit" type="submit" value="Войти" />
</fieldset>
</form>
Т.е. создается форма с именем authform, методом отправки POST, которую будет обрабатывать скрипт check.php. В самой форме есть поля для ввода логина, пароля, и символов с каптчи, а так же кнопка отправки.
Создав тем или иным способом форму, содержащую поле для ввода символов с каптчи (а так же не забыв вывести само изображение), останется решить только одну проблему: как проверить соответствие изображения на картинке и ответа пользователя? На самом деле, способов великое множество. Главное не ошибиться. Самое первое место по глупости занимает прямая отправка сгенерированного текста в форму (скажем, в виде скрытого input). Не намного лучше и способ, который упорно предлагается на десятках блогов в рунете, упорно вылезающих в первых строках поиска по запросу CAPTCHA: передача через сессию. Вроде как не видно, и ладно. На самом деле — видно, боты прекрасно могут получить значение из cookie, сессий и т.п. Поэтому если уж и использовать хранение в сессии, то не самого ответа, а его хэша.
В результате в самом начале скрипта captcha_image.php следует начинать сессию (session_start();), а непосредственно перед выводом самой картинки — сохранять в сессии MD5-слепок текста с каптчи. В итоге получаем окончательный вариант своего скрипта — вот его полный исходный код.
Файл captcha_image.php
<?php
session_start();
include("captcha.php");
$c = new TCaptcha();
$c->fontname = "../arialbd.ttf"; // устанавливаем шрифт
$c->fontsize = 18; //устанавливаем размер шрифта
$c->fontcolor = 0xa0040f; //устанавливаем цвет шрифт
$c->bgcolor = 0xfeecca; //устанавливаем фоновый цвет каптчи
$c->angle = -2; // устанавливаем угол поворота текста
$c->waves = 1; // волновые искажения пусть останутся по горизонтали
$c->lines = 2; // заштрихуем цветом текста
$c->minlength = 6; // в этой и следующей строках устанавливаем фиксированное число символов в каптче - 6
$c->maxlength = 6;
$c->GenerateText();
$_SESSION["captcha"]=MD5($c->ctext);
$c->Make();
?>
Здесь мы создали рисунок и сохранили в сессии хэш правильного ответа. Теперь достаточно получить значение поля captcha из формы, сделать с него MD5 слепок и сравнить их. В нашем примере обработкой формы занимается скрипт check.php. Для простоты мы опустим проверку логина-пароля (тем более, что по-хорошему это надо делать уже после проверки каптчи). Получаем примерно следующее:
Файл check.php
<?php
session_start();
$caps = $_SESSION["captcha"]; //берем сохраненный с сессии хэш
$_SESSION["captcha"]=""; //сразу же потрем за дальнейшей ненадобностью
$capp = strtoupper($_POST["captcha"]); //не будем издеваться над пользователем
if (($caps=="") || ($capp=="") || (MD5($capp) != $caps)) {
echo "Wrong captcha :(";
} else {
echo “Welcome! ;)”;
}
?>
В условном операторе дополнительно проверяется, не пустые ли строки сравниваются. В принципе, это все. Единственное, что следует учитывать — так это то, что к 3-4 символьной сроке, состоящей лишь из букв и цифр (в нашем случае даже не всех), MD5-хэш можно подобрать за приемлемое время даже на PHP. Поэтому используйте не менее 6 символов, либо вообще передавайте лишь идентификатор сессии, а ответ храните у себя на сервере в базе данных. Это чуть сложнее и чуть накладнее, но зато надежнее.
2011-05-05