CAPTCHA Perl. Генерация при помощи ImageMagick

Небольшая функция генерации капчи для perl при помощи вызова imagemagick через библиотеку Image::Magick.
Может пригодиться в том случае, когда хостер не позволяет устанавливать свои модули для perl (например GD::SecurityImage или Auchten::Captcha). Модуль для работы с ImageMagick не стоит по умолчанию разве что у самого нерадивого хостера.
Функцию можно использовать как библиотечный вызов, при вызове передавать имя файла и строку для генерации капчи.

Код самой функции:
#!/usr/bin/perl
# Генератор капчи. Идея и параметры вызова Convert взяты с captcha.ru (http://captcha.ru/captchas/multiswirl/).
# Реализация под библиотеку Image::Magick для perl - dimio (www.dimio.org).
# 27.09.2009
use Image::Magick;
sub CreateCapImage($$){
my($cap_string,$filename) = @_;
my $font = 'times.ttf';
my $pointsize = 70;
my $path = './';

my $image = new Image::Magick;

# 1. Создаём поле 300x100 белого цвета.
$image->Set(size => '300x100');
$image->ReadImage('xc:white');
# 2. Печатаем черным с антиалиасингом
$image->Set(
			type 		=> 'TrueColor',
			antialias	=>	'True',
			fill		=>	'black',
# строку STRING шрифтом $font размером $pointsize
			font		=>	$font,
			pointsize	=>	$pointsize,
			);
$image->Draw(
			primitive	=>	'text',
			points		=>	'20,70', # ориентация строки текста внутри картинки
			text		=>	$cap_string, # что печатаем
			);
# 3. Подвинуть центр влево на 100 точек +случайная флуктуация
$image->Extent(
			geometry	=>	'400x120', # меняем размер картинки
			);
$image->Roll(
			x			=>	101+int(rand(4)),
			);
# 4. Первый swirl на случайный угол (от 37 до 51)
$image->Swirl(
			degrees		=>	int(rand(14))+37,
			);
# 5. Подвинуть центр вправо на 200 точек, тоже со случайной флуктуацией
$image->Extent(
			geometry	=>	'600x140', # меняем размер картинки
			);
$image->Roll(
			x			=>	3-int(rand(4)),
			);
# 6. Второй поворот (от 20 до 35)
$image->Swirl(
			degrees		=>	int(rand(15))+20,,
			);
# 7. Окончательная обработка и вывод
$image->Crop('300x100+100+17');
$image->Resize('150x50');

$filename = $path . $filename;
$filename .= '.png';
open(IMAGE,'>',$filename) or die $!;
$image->Write(file=>\*IMAGE, filename=>$filename);
close(IMAGE);

return $filename;
}
1;

Пример вызова:
# Вызов капчи из скрипта
my $num1 = int(rand(11))+int(rand(3));
my $num2 = int(rand(8))+int(rand(4));
my $sum = $num1+$num2;
my $cap_string = $num1.'+'.$num2.'=';
my $cap_digest = md5_hex($sum+rand(100)+rand(50));
my $cap_url = &CreateCapImage($cap_string,$cap_digest);
	$cap_url =~ s|/home/dimioorg/public_html/dimioorg||;
	$cap_url = 'http://www.dimio.org'.$cap_url;
print	$query->em("<img src=\"$cap_url\">"),
		$query->textfield(
				-name		=>	'cap_value',
				-size		=>	2,
				-maxlength	=>	2,
			);

В результате на странице будет выведена картинка с символами вида «12+7=». Строка в принципе может быть какой угодно.

Кому лень копипастить — может скачать функцию captcha.pl и три ttf шрифта.

Написано на правах памятки для себя, но вдруг кому пригодится :)

Еще на похожие темы:

Comments

10 комментариев to “CAPTCHA Perl. Генерация при помощи ImageMagick”

  1. mike пишет:

    Что-то не работает!

    Рисунок — просто белый прямоугольник,без текста, а потом

    вываливается на

    print $query->em (""),

    $query->textfield (

    -name => 'cap_value',

    -size => 2,

    -maxlength => 2,

    );

    с сообщением

    Can't call method «em» on an undefined value at /home/.......

    • dimio пишет:

      В примере указано так:

      print $query->em (""),

      ,а вы передаёте пустую строку.

      Модуль CGI подключен кстати?

      Что касается рисунка — во-первых — шрифт указан правильно? Во-вторых — можно покрутить параметры генерации. У меня получалась нормальная картинка с капчей при указанных в примере параметрах.

    • dimio пишет:

      Понятно, это движок режет код...

  2. mike пишет:

    Сделал так:

    $query = new CGI;

    print $query->em (""),

    $query->textfield (

    -name => 'cap_value',

    -size => 10,

    -maxlength => 5,

    );

    все заработало, но картинка пустая :(

  3. bash пишет:

    вот сделал капчу... все работает.

    а как правильно проверять ее и ввод юзера ?

    • dimio пишет:

      Я бы вычислял хэш сгенерированного слова для капчи и хэш пользовательского ввода, а затем сравнивал их. Модуль Digest::MD5 в помощь.

  4. bash пишет:

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

    • dimio пишет:

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

Leave a Reply