Создание капчи (captcha) на PHP

Замечания

Не забываем про вторую часть статьи с примером работы капчи.

Со временем сайт набирает популярность и возникает необходимость в организации защиты от спам-ботов. В этой статье я расскажу как можно создать собственную капчу на PHP.

Капча (captcha) представляет из себя изображение с некоторым текстом, который предлагается набрать пользователю в поле ввода для подтверждения его "человечности". Дело в том, что человеку одинаково легко читать текст, независимо от того, является ли он непосредственно машинным текстом или изображением. В то время как компьютеру требуется гораздо более сложный алгоритм для "чтения" текста в виде картинки. Очевидно, что капча каждый раз должна отображать случайную последовательность символов.

Капчи используются, как правило, при заполнении каких-либо форм на сайте. Алгоритм работы следующий: на форме присутствует изображение-captcha с некой случайной последовательностью символов. Рядом с ним имеется поле для ввода содержимого капчи пользователем. Изображение, по сути, является PHP-скриптом, который его формирует. При этом сгенерированное текстовое содержимое капчи где-то сохраняется. При отправке формы скрипт сравнивает сохраненное значение капчи с тем, что ввел пользователь. Если значения совпадают, то запрос принимается, иначе отклоняется.

Предлагаемая мной реализация предельно проста, в то же время, в ней имеется поддержка TrueType шрифтов, а также альфа-канал (прозрачный фон), поэтому капча будет хорошо вписываться в любой дизайн.

Обратите внимание, что для работы скрипта требуется PHP-расширение GD, подключите его в настройках.

Для начала необходимо определиться со шрифтом. Соответствующий выбранному шрифту ttf-файл необходимо положить в директорию с будущим скриптом капчи. Я для капчи выбрал шрифт Comic Sans MS, ему соответствует файл comic.ttf. Файлы шрифтов можно найти в системном каталоге шрифтов вашей операционной системы, либо загрузить из Интернета.

Далее создается скрипт captcha.php. В начале скрипта объявляются необходимые переменные:

$letters = 'ABCDEFGKIJKLMNOPQRSTUVWXYZ';

В виде строки перечисляется алфавит. Это символы, которые будут участвовать в формировании капчи. Я перечислил заглавные латинские буквы, можно добавить, например, цифры.

$caplen = 6;

В этой переменной задается длина капчи (6 символов).

$width = 120; $height = 20;

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

$font = 'comic.ttf';

Здесь указывается файл шрифта. В принципе, его можно разместить в поддиректории, допустим, fonts, тогда содержимое переменной должно быть такого формата: fonts/comic.ttf.

$fontsize = 14;

Размер шрифта.

С переменными разобрались. Далее, приступаем непосредственно к реализации. Во-первых, необходимо указать клиенту запрошенного скрипта, что ответный контент представляет из себя не текст, а изображение. Для этого переопределяем содержимое HTTP-заголовка content-type:

header('Content-type: image/png');

Создаем изображение с заданными размерами:

$im = imagecreatetruecolor($width, $height);

Выставляем флаг необходимости сохранения альфа-канала изображения:

imagesavealpha($im, true);

Создаем цвет фона. Это будет полностью прозрачный цвет:

$bg = imagecolorallocatealpha($im, 0, 0, 0, 127);

Заливаем этим цветом наше созданное изображение:

imagefill($im, 0, 0, $bg);

Этими действиями мы подготовили наше изображение для наложения на него капчи. Следующая строка необходима не всегда, зависит от настроек веб-сервера. Она переопределяет путь к поиску шрифтов. Оставьте ее закомментированной, если вдруг капча не будет формироваться при тестировании, а в логе ошибок Apache будет появляться ошибка "imagettftext(): Could not find/open font", попробуйте ее раскомментировать:

//putenv( 'GDFONTPATH=' . realpath('.') );

Инициализируем переменную, в которой будет содержаться текстовое значение капчи:

$captcha = '';

Далее организовывается цикл с количеством итераций равным длине капчи (caplen):

for ($i = 0; $i < $caplen; $i++)

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

$captcha .= $letters[ rand(0, strlen($letters)-1) ];

Вычисляем положение сгенерированного символа на изображении по оси x:

$x = ($width - 20) / $caplen * $i + 10;

Это положение зависит от ширины изображения, длины капчи и порядкового номера символа. Далее мы добавляем немного "случайности" в это положение:

$x = rand($x, $x+4);

Вычисляем положение сгенерированного символа на изображении по оси y:

$y = $height - ( ($height - $fontsize) / 2 );

Положение зависит от размера шрифта и высоты изображения.

Генерируем случайный цвет для символа. Этот цвет не должен быть слишком светлым, поэтому каждый из компонентов цвета (R, G и B) генерируем в диапазоне 0-100:

$curcolor = imagecolorallocate( $im, rand(0, 100), rand(0, 100), rand(0, 100) );

Для текущего символа случайным образом генерируем его угол наклона в диапазоне -25..25 градусов, чтобы буквы на капче "плясали":

$angle = rand(-25, 25);

И, наконец, рисуем символ со всеми выше полученными характеристиками на изображении:

imagettftext($im, $fontsize, $angle, $x, $y, $curcolor, $font, $captcha[$i]);

На этой строке оканчивается тело цикла. Когда цикл отработает, в переменной captcha будет содержаться текстовое значение капчи, а изображение im будет представлять из себя отрисованную капчу. Необходимо где-то сохранить значение капчи, чтобы основной скрипт, который использует ее, мог проверить значение пользователя. Лучшее для этого место — сессионная переменная. Инициализируем сессию и сохраняем значение капчи:

session_start();
$_SESSION['captcha'] = $captcha;

Наконец, выводим сформированное изображение captcha:

imagepng($im);

И освобождаем память, выведенную под изображение:

imagedestroy($im);

Ниже вы можете увидеть демонстрацию работы полученной капчи (попробуйте обновить изображение):

captcha

Чуть позже добавлю готовый скрипт капчи и пример его использования в HTML-формах.

Комментарии

Оставить комментарий »

 
Сергей
25 декабря 2011, 14:19
#1
 

неплохо, но зачем так усложнять алгоритм рандома??? не проще хранить значение в массиве и посредством интерполяции выводить соответствующее изображение

Drakmail
16 января 2012, 19:15
#2
 

Спасибо, отличная статья.

Серый волк
17 января 2012, 11:39
#3
 

Агроменное спасибо аффтару!!! Изящная капчушка получаеццо. Они не пройдут!!!

Joker-jar
18 января 2012, 4:04
#4
 

Кстати, пример использования я так и не показал :)

Игорь
6 марта 2012, 12:02
#5
 

да вроде нече так, а почему тут у тебя на блоге не стоит эта капча ? она не безопасна ?

Joker-jar
6 марта 2012, 15:33
#6
 

Просто для комментариев используется премодерация. Скоро будет регистрация, там будет эта капча.

Joker-jar
10 марта 2012, 7:16
#7
 

Ну вот, собственно, она и появилась :) Можете увидеть капчу в действии.

ILy
15 мая 2012, 16:53
#9
 

Скажите, у меня комментарии завязаны на базе данных и проверочная картинка тоже лежит в базе, эта каптча подойдет для моего варианта?

Joker-jar
16 мая 2012, 12:49
#10
 

ILy, а что значит "проверочная картинка тоже лежит в базе"?

Оставить комментарий

Ваше имя
 
Ваш e-mail
 
Комментарий