PHP: Делаем простую капчу с цифрами
Обычно в наше время для капчи ("антиспамового кода", вводимого на многих страницах Интернета) генерируют картинки средствами библиотеки GDLib, получая код вроде этого (взят из одного старого проекта):
<?php $letters = array(); function generate_key() { global $letters; $chars = array ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ); $count = count($chars) - 1; $key = array(); for($i = 0; $i < 2; $i++) { $key[ $i ] = ''; for($j = 0; $j < 3; $j++) { list($usec, $sec) = explode(' ', microtime()); mt_srand((float) $sec + ((float) $usec * 1000000)); $letter = $chars[ mt_rand(0, $count) ]; if ( isset($letters[ $letter ]) ) { --$j; } else { $letters[ $letter ] = $letter; $key[ $i ] .= $letter; } } } return implode('', $key); } $img_x = 200; $img_y = 50; $font = '/font.ttf'; $content = generate_key(); session_start(); session_register("antibot"); $_SESSION['antibot'] = $content; $img = imagecreate($img_x, $img_y); $colours = array(); $colours['white'] = imagecolorallocate($img, 255, 255, 255); $colours['grey'] = imagecolorallocate($img, 230, 230, 230); $colours['black'] = imagecolorallocate($img, 0, 0, 0); $number_of_x_lines = ($img_x - 1) / 6; $number_of_y_lines = ($img_y - 1) / 6; for($i = 0; $i < $number_of_x_lines; $i++){ imageline($img, $i * $number_of_x_lines, 0, $i * $number_of_x_lines, $img_y, $colours['grey']);} for($i = 0; $i < $number_of_y_lines; $i++){ imageline($img, 0, $i * $number_of_y_lines, $img_x, $i * $number_of_y_lines, $colours['grey']);} $txt_bbox = imagettfbbox(20, 0, $font, $content); $sx = ($img_x - ($txt_bbox[2] - $txt_bbox[0])) / 2; $sy = ($img_y - ($txt_bbox[1] - $txt_bbox[7])) / 2; $sy -= $txt_bbox[7]; header('Content-type: image/png'); imagettftext($img, mt_rand(14, 18), mt_rand(-10, 10), $sx, $sy, $colours['black'], $font, $content); imagepng($img); imagedestroy($img); ?>
Часто так сделать невозможно (отключена или недоступна GDLib, просто не хочется стрелять из пушки по воробьям) и т.п. Тогда можно сделать гораздо проще, написав скрипт, самостоятельно кодирующий GIF'ки капчи прямо в теле скрипта с помощью base64.
Для простоты ограничимся капчами, состоящими только из цифр и напишем следующий демо-скрипт:
<?php //Совсем простая капча $captha_length=4; // Количество символов в коде $captcha_random_seed="543129"; // Случайное число для защиты; поставьте своё if (isset($_REQUEST['image'])) { function write_image_number ($num) { $number="R0lGODlhCgAMAIABAFNTU////yH5BAEAAAEALAAAAAAKAAwAAAI"; // Заголовок GIFки в base64 if ($num=="0") { $len="63"; $number.="WjIFgi6e+QpMP0jin1bfv2nFaBlJaAQA7";} if ($num=="1") { $len="61"; $number.="UjA1wG8noXlJsUnlrXhE/+DXb0RUAOw==";} if ($num=="2") { $len="64"; $number.="XjIFgi6e+QpMPRlbjvFtnfFnchyVJUAAAOw==";} if ($num=="3") { $len="64"; $number.="XjIFgi6e+Qovs0RkTzXbj+3yTJnUlVgAAOw==";} if ($num=="4") { $len="64"; $number.="XjA9wG8mWFIty0amczbVJDVHg9oSlZxQAOw==";} if ($num=="5") { $len="63"; $number.="WTIAJdsuPHovSKGoprhs67mzaJypMAQA7";} if ($num=="6") { $len="63"; $number.="WjIFoB6vxmFw0pfpihI3jOW1at3FRAQA7";} if ($num=="7") { $len="61"; $number.="UDI4Xy6vtAIzTyPpg1ndu9oEdNxUAOw==";} if ($num=="8") { $len="63"; $number.="WjIFgi6e+QpMP2slSpJbn7mFeWDlYAQA7";} if ($num=="9") { $len="64"; $number.="XjIFgi6e+QpMP0jinvbT2FGGPxmlkohUAOw==";} header("Content-type: image/gif"); header("Content-length: $len"); echo base64_decode($number); } // Вывод закодированных изображений на экран if (array_key_exists('image', $_REQUEST)) { $num=$_REQUEST['image']; for ($i=0; $i<10; $i++) { if (md5($i+$captcha_random_seed)==$num) { write_image_number($i); exit; //Вывод одной цифры и выход } } } exit; } //Печатаем заголовок документа echo ' <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html; charset=Windows-1251" http-equiv="content-type"> <title>Простая капча на PHP</title> </head> <body>'; $captcha_key=''; //mt_srand(time()+(double)microtime()*1000000); //Не нужно с PHP 4.2.0 print"<form action=\"".$_SERVER["PHP_SELF"]."\" method=\"post\">Защитный код: "; for ($i=0; $i<$captha_length; $i++) { $snum=mt_rand(0,9); $psnum=md5($snum+$captcha_random_seed); echo '<img src="'.$_SERVER["PHP_SELF"]."?image=$psnum\" border=\"0\" alt=\"\">\n"; $captcha_key.=$snum; } $captcha_key=md5("$captcha_key+$captcha_random_seed"); print" <input name=\"captcha_key\" type=\"hidden\" value=\"$captcha_key\"> <input name=\"user_captcha_number\" type=\"text\" maxlength=\"$captha_length\" size=\"$captha_length\"> (введите число, указанное на картинке) <input type=\"submit\" name=\"action\" value=\"OK\"></form>"; //проверка: if (isset($_REQUEST['action'])) { //была нажата кнопка $errormsg="<font color=red>Введённый код неверен!</font>"; if (!isset($_POST['user_captcha_number']) or !isset($_POST['captcha_key'])) { print "$errormsg"; exit; } $user_captcha_number=$_POST['user_captcha_number']; $captcha_key=$_POST['captcha_key']; if (md5("$user_captcha_number+$captcha_random_seed")!=$captcha_key) { print "$errormsg"; exit; } print "Всё верно</body></html>"; } ?>
Так как скрипт вызывает сам себя для получения очередной картинки-цифры, нельзя перед выводом картинки ставить какой-нибудь HTML-код. А вот перед ветвью для вывода формы - можно, как и сделано в примере. Не уверен также, что уже нет ботов, читающих эти довольно стандартные цифровые последовательности. Попозже, может, сделаю из этого простенький модуль. Конечно, для его работы в форме всё равно нужно будет указывать текстовое поле
user_captcha_number
(число, введённое пользователем), скрытое поле captcha_key
(зашифрованный "правильный ответ") и кнопку action
(отправка формы). Разумеется, названия полей формы HTML можно изменить, тогда изменятся и названия соответствующих переменных в теле скрипта.
Почему в IE 7-8 сообщения "Код неправилен" или "Всё верно" не выводятся при отправке формы клавишей Enter, а не кнопкой формы ОК - подумаю, вроде бы, форма простая и сделана теоретически правильно...
P.S. Фиг его знает, этот IE, печать массива $_REQUEST
строкой
print_r ($_REQUEST);дала в нём следующее:
Array ( [captcha_key] => 0d38b62fe1d3fb3cebe67a35c627c59a [user_captcha_number] => 4089 [__utma] => 96992031.150883131.1284642699.1285238584.1285244288.8 [phpbb2mysql_data] => a:2:{s:11:\"autologinid\";s:0:\"\";s:6:\"userid\";i:-1;} )
Окончание статьи и исправление - на сайте
24.05.2011, 16:27 [17449 просмотров]