| Новости | FAQ | Авторы | Документация | В действии | Библиотека |
| Инструменты | Полезные ссылки | Хостинги | Скачать | Примеры | Форум |
Sanja v.2 29.04.2004 14:46
В продолжение http://www.parser.ru/forum/?id=25379 - дошли руки переписать код. Держите, мож кому пригодится.##############################
# В этот класс вынесен код, отвечающий за отрисовку проверочной картинки
# (цифры с которой пользователь должен считать и ввести в форму, чтобы сайт
# удостоверился, что имеет дело не с роботом, а с человеком).
#
# Это довольно эффективный механизм защиты от спамерских программ a la'
# "Разместите свою рекламу в 10000 форумах Рунета одним кликом мыши".
# и вандализма (несколько тысяч матерных записей в guestbook, добавленных
# скриптом). От добавления спама и мата вручную разными [..censored..]
# это решение не спасёт, но жизнь в целом несколько проще уж точно сделает.
#
# ### SQL-код для создания таблицы для работы класса в БД: ###
# CREATE TABLE cityblog_humancheck (
# guid char(64) NOT NULL default '',
# digits char(10) NOT NULL default '',
# created datetime NOT NULL default '',
# expires datetime default NULL,
# PRIMARY KEY (guid),
# UNIQUE KEY guid (guid)
# ) COMMENT='Stores codes of images used
# to prevent automated spamming';
#
@CLASS
verify
##############################
# Генерирует случайное число, вносит его в базу и выводит картинку:
@create[delay]
# Параметр delay определяет, сколько минут будет
# действителен сгенерированный код (если 0 - вечно).
# По умолчанию - 10 минут.
$delay(^delay.int(10))
$humancheck_uuid[^math:uuid[]]
# Пятизначное число, которое мы должны вывести картинкой:
$random(^math:random(99999))
$humancheck_fivedigits[^random.format[%05u]]
^MAIN:dbconnect{
# Вносим только что сгенерированное число в базу:
^void:sql{INSERT INTO cityblog_humancheck
(guid, digits, created, expires)
VALUES("$humancheck_uuid","$humancheck_fivedigits", NOW(),
^if($delay != 0){
DATE_ADD(NOW(), INTERVAL $delay MINUTE)
}{
NULL
}
) }
}
##############################
# Сравнивает введённое пользователем и хранящееся в базе:
@compare[uuid;input]
# Если число не пятизначное, дорисовываем недостающие нули в начале:
$input(^input.int(0))
$input[^input.format[%05u]]
^MAIN:dbconnect{
# Сначала вычищаем просроченные строки:
^void:sql{DELETE FROM cityblog_humancheck
WHERE expires != "" AND expires < NOW()}
# Сравниваем введённое значение с хранящимся в базе:
$correct[^string:sql{SELECT digits FROM
cityblog_humancheck WHERE guid = "$uuid"
AND expires > NOW() }[$.limit(1) $.default{}]]
^if($correct ne ""){
^if($correct eq $input){
Правильно! <!-- Пользователь верно
прочитал цифру, разрешаем
ему действие. -->
}{
Ошибочка вышла или вы долго думали! <!-- Либо
посетитель слепой, либо опечатался. Надо дать
ему ещё один шанс - но уже с новой картинкой.
Нельзя давать возможность перебрать все варианты
цифры, сопоставленной одному и тому же uuid -
пусть в каждой попытке пользователь будет
сталкиваться с новой картинкой. -->
}
}{
Кыш, хакер! <!-- Вася-кулхакер пытается взломать
нас, манипулируя полями формы или пытается повторно
воспользоваться отработавшим uuid'ом. Посылаем
Васю на фиг - пущай ломает кого-то другого,
тут ему ничего не светит. -->
}
# Больше эту строку использовать будет нельзя:
^void:sql{DELETE FROM cityblog_humancheck WHERE guid = "$uuid"}
}
##############################
# Пример вывода формы:
@example[]
^if(def $form:uuid && def $form:input){
<h3>^compare[$form:uuid;$form:input]</h3>
<p><a href="./">Попробуем ещё?</a></p>
}{
# Генерируем число и пишем его в базу на пять минут:
^create[5]
# (если бы мы защищали форум или гестбук, где на написание реплики
# может уйти много времени, имело бы смысл дать пользователю запас
# времени побольше)
<p>Докажите, что вы - не робот, прочитайте цифры <br />
на картинке <img src="./uuid_${verify:humancheck_uuid}.gif"
width="110" height="24" border="1" alt="Докажи, что ты не робот!" />
и введите их в поле:</p>
<form action="./">
<input type="hidden" name="uuid"
value="$verify:humancheck_uuid" />
<input type="text" name="input"
maxlength="5" size="5" />
<input type="submit" value="Сравнить!" />
</form>
}
##############################
# Выводит заданное число в виде картинки
@DisplayImage[uuid]
# Размер мини-картинок с цифрами: 20 х 20px, т.е.
# пятизначное число картинкой будет занимать 20 на 20*5
$background[^image::create(100;20)]
# Если имеет место мухлёж, и $uuid не задан, будет выведена
# просто пустая картинка (фон без цифр):
^try{
^MAIN:dbconnect{
# Вытягиваем цифры для вывода на картинке из базы по uuid:
$check[^string:sql{SELECT digits FROM cityblog_humancheck
WHERE guid = "$uuid"}[$.limit(1)]]
}
# Предполагается, что мини-картинки имеют названия
# $img_path/XY.gif, где X - номер на картинке, а Y -
# вариант (00 может быть курсивным ноликом, 01 - жирным)
# Число может быть представлено любой картинкой, чтобы
# затруднить распознавание автоматическими средствами.
$digit1[^check.mid(0;1)]
$digit2[^check.mid(1;1)]
$digit3[^check.mid(2;1)]
$digit4[^check.mid(3;1)]
$digit5[^check.mid(4;1)]
# Путь к папке с картинками:
$img_path[/noise]
$file1[^image::load[$img_path/fs^math:random(9)${digit1}.gif]]
$file2[^image::load[$img_path/fs^math:random(9)${digit2}.gif]]
$file3[^image::load[$img_path/fs^math:random(9)${digit3}.gif]]
$file4[^image::load[$img_path/fs^math:random(9)${digit4}.gif]]
$file5[^image::load[$img_path/fs^math:random(9)${digit5}.gif]]
# Накладываем на фон все пять картинок:
^background.copy[$file1](0;0;23;24;^eval(0*20);0)
^background.copy[$file2](0;0;23;24;^eval(1*20);0)
^background.copy[$file3](0;0;23;24;^eval(2*20);0)
^background.copy[$file4](0;0;23;24;^eval(3*20);0)
^background.copy[$file5](0;0;23;24;^eval(4*20);0)
}{
$exception.handled(1)
}
$response:body[^background.gif[]]
#EOFСоздайте папку noise, вывалите в неё картинки из http://bougakov.com/misc/noise.zip# Запрещаем открывать картинки fs*.gif из этой папки в браузере: <Files ~ "fs(.*)\.gif$"> Order allow,deny Deny from all </Files> # Простенький rewrite для переадресации запросов к img_digits.html RewriteEngine on RewriteRule uuid_(.*)\.gif$ img_digits.html?uuid=$1 [L] # EOFи файл img_digits.html:
@USE verify.p @main[] ^verify:DisplayImage[$form:uuid]Создайте /noise/index.html с текстом:
@USE verify.p @main[] ^verify:example[]и добавьте в текущую БД новую таблицу:
CREATE TABLE cityblog_humancheck ( guid char(64) NOT NULL default '', digits char(10) NOT NULL default '', created datetime NOT NULL default '', expires datetime default NULL, PRIMARY KEY (guid), UNIQUE KEY guid (guid) ) COMMENT='Stores codes of images used to prevent automated spamming';Энджой.