Новости | 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';Энджой.