parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

Цифры на гифчике - 2 или портим малину спамерам

Sanja v.2 29.04.2004 14:46

В продолжение http://www.parser.ru/forum/?id=25379 - дошли руки переписать код. Держите, мож кому пригодится.

verify.p - положите куда-нибудь в $CLASS_PATH
##############################
# В этот класс вынесен код, отвечающий за отрисовку проверочной картинки
# (цифры с которой пользователь должен считать и ввести в форму, чтобы сайт
# удостоверился, что имеет дело не с роботом, а с человеком).
#
# Это довольно эффективный механизм защиты от спамерских программ 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
Создайте файл .htaccess
# Запрещаем открывать картинки 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';
Энджой.