Поиск по блогу

воскресенье, 30 октября 2011 г.

Создаем свою собственную капчу (CAPTCHA)


Думаю, что такое капча все знают и писать смысла нету, поэтому сразу к делу...


Спасибо, спамерам и ихним спам ботам, нету сайта на которой нету капчи. А некоторые капчи, которые на рисунке слева, вообще не возможно читать, ни то, чтобы бегло считать.
Я предлагаю при использовании капчи запомнить четыре простых правила:
1. Капча создана для людей, она должна сходу читаться. Довольно таки хороший пример на первом рисунке, капчи так или иначе, возможно прочитать.
2. Капча должна быть ограничена в символах,
например reCAPTCHA... Скока тут символов? Пока это напечатаешь, пальцы отвалятся.
3. Если используются русские буквы нельзя использовать букву ё ( ~ / тыльда ), у многих пользователей буква ё, что то делает.
4. Капча должна быть стойкой к распознаванию. Но не в ущерб читаемости, это самый сложный пункт в разработке. Так же надо учитывать специфику ресурса. Если речь идет о, допустим, форуме читающих домохозяек за сорок, то на стойкость капчи можно плюнуть с высокой башни — никому он не упрется. Если речь идет о, например, имейджборде, то тут нужна капча а-ля вырвиглаз.


Проектирование.

Итак, по порядку:

1. В изображении должно быть несколько цветов. Желательно всегда разные


Изображение выше — пример того, как это выглядит в действии. На самом деле, это не очень надежный вариант, так как текст с фоном очень контрастирует. Разберемся с цветами позже. Но верхний пример несмотря ни на что, через-чур цветной в глаза бросается. 

2. Должен присутствовать шум


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

3. Буквы должны находиться всегда на разных расстояниях друг от друга


Тут главное не перестараться. На примере выше можно заметить, что буквы слипаются, это создает препятствие для бота.

4. Размеры символов должны быть разными


Если применять этот трюк, то надо помнить, что препятствие фактически выражается в том, что для сегментации капчи бот не сможет использовать постоянную матрицу. 

5. Отвратительный шрифт


Очень полезный способ. 

6. Символы под случайным углом



Весьма действенный способ оградиться от ботов. 

7. Динамические искажения



Ничего ужаснее человечество еще не придумало. Искажения в капче зачастую очень сильно снижают читаемость человеком. Разумеется, это достаточно эффективно против ботов, но это так же эффективно и против людей. Главное — не перестараться, искажения должны быть незначительными. 

Разработка


Определимся с целью:
— Генерация шума
— Генерация текста
— Форма с возможностью обновления капчи
— Обработчик введенных данных
В этом примере искажений у нас не будет. 

<form action="go.php" method="post" enctype="multipart/form-data">
<!-- Форма будет отправлять введенные пользователем данные вашему скрипту, методом POST -->
<img src='captcha.php' id='capcha-image'>
<!-- Сама капча -->
<a href="javascript:void(0);" onclick="document.getElementById('capcha-image').src='captcha.php?rid=' + Math.random();">Обновить капчу</a>
<!-- Ссылка на обновление капчи. Запрашиваем у captcha.php случайное изображение. -->
<span>Введите капчу:</span>
<input type="text" name="code">
<input type="submit" name="go" value="Продолжить">
<!-- Отправляем данные скрипту-обработчику -->
</form>

Тут все ясно.

Теперь нам надо сделать разработчик капчи, rand.php.
Выглядит он приблизительно вот так:
<?php

// Функция генерации капчи
function g_code()
{
$chars = 'abdefhknrstyz23456789'; // Задаем символы, используемые в капче. Разделитель использовать не надо.
$length = rand(4, 5); // Задаем длину капчи, в нашем случае - от 3 до 5
$numChars = strlen($chars); // Узнаем, сколько у нас задано символов
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, rand(1, $numChars) - 1, 1);
} // Генерируем код

// Перемешиваем, на всякий случай
$array_mix = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);
srand ((float)microtime()*1000000);
shuffle ($array_mix);
// Возвращаем полученный код
return implode("", $array_mix);
}
?>

Тут все от вашего воображения как делать. Идем дальше. Я исключил такие символы как "i, l, 1 и 0, o, c" так как они слишком похожи, пользователи могут ошибаться. 



Пишем генератор изображения (captcha.php)


<?php
// Устанавливаем переменную img_dir, которая примет значение пути к папке со шрифтами и (если потребуется) изображениями
define ( 'DOCUMENT_ROOT', dirname ( __FILE__ ) );
define("img_dir", DOCUMENT_ROOT."/captcha/img/"); // Если скрипт отказывается работать, то скорее всего ваш сервер не поддерживает $HTTP_SERVER_VARS. В таком случае, закомментируйте эту строчку и раскомментируйте следующую.
// define("img_dir", "/captcha/img/");

// Подключаем генератор текста
include("rand.php");
$captcha = g_code();

// Вносим в куки хэш капчи. Куки будет жить 120 секунд.
$cookie = md5($captcha);
$cookietime = time()+120; // Можно указать любое другое время
setcookie("captcha", $cookie, $cookietime);

// Пишем функцию генерации изображения
function img_code($code) // $code - код нашей капчи, который мы укажем при вызове функции
{
// Отправляем браузеру Header'ы
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s", 10000) . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Content-Type:image/png");
// Количество линий. Обратите внимание, что они накладываться будут дважды (за текстом и на текст). Поставим рандомное значение, от 3 до 5.
$linenum = rand(3, 5);
// Задаем фоны для капчи. Можете нарисовать свой и загрузить его в папку /img. Рекомендуемый размер - 150х70. Фонов может быть сколько угодно
$img_arr = array(
"1.png"
);
// Шрифты для капчи. Задавать можно сколько угодно, они будут выбираться случайно
$font_arr = array();
$font_arr[0]["fname"] = "Arial.ttf"; // Имя шрифта.
$font_arr[0]["size"] = rand(20, 30); // Размер в pt
// Генерируем "подстилку" для капчи со случайным фоном
$n = rand(0,sizeof($font_arr)-1);
$img_fn = $img_arr[rand(0, sizeof($img_arr)-1)];
$im = imagecreatefrompng (img_dir . $img_fn);
// Рисуем линии на подстилке
for ($i=0; $i<$linenum; $i++)
{
$color = imagecolorallocate($im, rand(0, 150), rand(0, 100), rand(0, 150)); // Случайный цвет c изображения
imageline($im, rand(0, 20), rand(1, 50), rand(150, 180), rand(1, 50), $color);
}
$color = imagecolorallocate($im, rand(0, 200), 0, rand(0, 200)); // Опять случайный цвет. Уже для текста.

// Накладываем текст капчи
$x = rand(0, 35);
for($i = 0; $i < strlen($code); $i++) {
$x+=15;
$letter=substr($code, $i, 1);
imagettftext ($im, $font_arr[$n]["size"], rand(2, 4), $x, rand(50, 55), $color, img_dir.$font_arr[$n]["fname"], $letter);
}

// Опять линии, уже сверху текста
for ($i=0; $i<$linenum; $i++)
{
$color = imagecolorallocate($im, rand(0, 255), rand(0, 200), rand(0, 255));
imageline($im, rand(0, 20), rand(1, 50), rand(150, 180), rand(1, 50), $color);
}
// Возвращаем получившееся изображение
ImagePNG ($im);
ImageDestroy ($im);
}
img_code($captcha) // Выводим изображение
?>

Весь код максимально закомментирован.

Пишем обработчик (go.php)

<META http-equiv=content-type content="text/html; charset=UTF-8">
<?php
include("random.php");

$cap = $_COOKIE["captcha"]; // берем из куки значение MD5 хэша, занесенного туда в captcha.php

// Пишем функцию проверки введенного кода
function check_code($code, $cookie)
{

// АЛГОРИТМ ПРОВЕРКИ
$code = trim($code); // На всякий случай убираем пробелы
$code = md5($code);
// НЕ ЗАБУДЬТЕ ЕГО ИЗМЕНИТЬ!

// Работа с сессией, если нужно - раскомментируйте тут и в captcha.php, удалите строчки, где используются куки
//session_start();
//$cap = $_SESSION['captcha'];
//$cap = md5($cap);
//session_destroy();

if ($code == $cap){return TRUE;}else{return FALSE;} // если все хорошо - возвращаем TRUE (если нет - false)

}

// Обрабатываем полученный код
if (isset($_POST['go'])) // Немного бессмысленная, но все же защита: проверяем, как обращаются к обработчику.
{
// Если код не введен (в POST-запросе поле 'code' пустое)...
if ($_POST['code'] == '')
{
exit("Ошибка: введите капчу!"); //...то возвращаем ошибку
}
// Если код введен правильно (функция вернула TRUE), то...
if (check_code($_POST['code'], $cookie))
{
echo "Ты правильно ввел капчу. Возьми с полки тортик, он твой."; // Поздравляем с этим пользователя
}
// Если код введен неверно...
else
{
exit("Ошибка: капча введена неверно!"); //...то возвращаем ошибку
}
}
// Если к нам обращаются напрямую, то дело дрянь...
else
{
exit("Access denied"); //..., возвращаем ошибку
}

?>

Тут все предельно ясно. Берем куки, записанную ранее в captcha.php, берем введенный код, точнее его хэш и сравниваем. Внимание! Если планируете пользоваться этим кодом, не забудьте изменить алгоритм проверки.

Результат:




ВСЕ! НАКОНЕЦ. статья получилась о громадной просто.!

Комментариев нет:

Отправить комментарий