INTRO Здравствуйте! Здесь я постараюсь рассказать о том, как с помощью PHP и GD распознавать обычные каптчи на примере 000webhost.com (http://www.000webhost.com/includes/php_captcha.php). Сразу хочу сказать, что на основе этого способа можно распознавать только простые каптчи. Долго я искал статьи, подобные этой, но не нашёл. И мне в голову пришла идея, которую мне получилось успешно реализовать. Именно ею я и хочу поделиться с вами! Термины Итак, для начала хочу объяснить некоторые термины (© WikiPedia): PHP - скриптовый язык программирования. GD - библиотека для динамической работы с изображениями. CAPTCHA — полностью автоматизированный публичный тест Тьюринга для различия компьютеров и людей, используемый для того, чтобы определить, кем является пользователь системы: человеком или компьютером. В Рунете часто транскрибируется как капча. Применяется CAPTCHA для того, чтобы предотвратить множественные автоматические регистрации и отправления сообщений программами-роботами. Т. е. задача CAPTCHA — защита от спама, флуда, и захвата аккаунтов. Распознавание Для начала надо создать изображение. Для этого воспользуемся функцией imagecreatefrompng, которая создает изображение из указанного файла. Синтаксис: PHP: #resource imagecreatefrompng (string filename) Использование: PHP: $captcha = imagecreatefrompng("php_captcha.png"); Теперь каптчу нужно разделить на пять ровных частей - для каждой цифры свое изображение. Конечно, вручную делать мы этого не будем, эту работу мы предоставим интерпретатору, тобишь PHP. Создадим цикл, который будет повторяться пять раз, каждый раз обрабатывая новое изображение. Далее создадим новое изображение с шириной 7px, высотой 10px. Каждый символ каптчи имеет именно такие размеры. PHP: $im = imagecreatetruecolor(7, 10); Теперь надо скопировать туда символ каптчи. Воспользуемся функцией imagecopy: PHP: #int imagecopy (resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h) Она копирует часть изображения src_im в dst_im, начиная с x,y-координат src_x, src_y, с шириной src_w и высотой src_h.Определённая часть будет скопирована в x,y-координаты dst_x и dst_y. Объясню: src_im - ресурс исходного изображения. dst_im - ресурс нового изображения, в которое и будет записан наш символ. src_x, src_y - начальные X и Y координаты нашего символа. src_w, src_h - длина и высота символа. Использовать будем так: PHP: imagecopy($im, $captcha, 0, 0, 9 * $i, 13, 7, 10); Это значит, что мы часть изображения $captcha, начиная с координат X: 9 * $i Y: 13 с шириной 7 и высотой 10. Эта часть и будет скопирована в $im. Наверное непонятно, почему X = 9 * $i, Y - 13. $i - переменная, которая при каждом выполнении цикла увеличивается на единицу. Возьмем первое повторение, когда $i - равно нулю. Таким образом X = 0, Y = 13. Если открыть изображение любым из редакторов, то можно увидеть, что именно эти координаты и будут началом первого символа. При втором выполнении, в $im скопируется второй символ, т.к. X = 9, Y = 13, и т.д... Это изображение - $im выглядит так: Теперь создаем еще один цикл, в теле которого по очереди будет перебирать каждый пиксель первого столбца, и засовывать в массив 1 или 0, в зависимости от того, закрашен этот пиксель, или нет... Воспользуемся функцией imagecolorat, которая возвращает индекс цвета пикселя. PHP: #int imagecolorat (resource image, int x, int y) Этой функции надо передать три значение - ресурс изображения, X и Y координаты. PHP: for ($j = 0; $j <= 9; $j++) { if (imagecolorat($im, 0, $j) != 16777215) $gd[$j] = 1; else $gd[$j] = 0; } Если индекс цвета не равен 16777215, тоесть не белый, записываем в массив $gd единицу, в противном случае - нолик. Итак, у нас образовался массив $gd. Если воспользоваться функцией print_r, которая выводит все ключи и элементы массива, то можно увидеть следующее: Code: Array ( [0] => 1 [1] => 1 [2] => 1 [3] => 1 [4] => 1 [5] => 0 [6] => 0 [7] => 1 [8] => 0 [9] => 0 ) Нет, это не бинарные числа Это первый столбец по матрице числа 5. А вот и вся она: Code: 1111111 1100000 1100000 1101110 1110011 0000001 0000001 1100001 0110011 0011110 А теперь выделим единички красным цветом: Code: [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]00000 [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]00000 [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0 [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] 000000[COLOR="Red"]1[/COLOR] 000000[COLOR="Red"]1[/COLOR] [COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0000[COLOR="Red"]1[/COLOR] 0[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] 00[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0 Так вот, в массиве выше у нас первый столбец этой матрицы, по которому и будем распознавать число. Сразу нарождается вопрос - как именно? Я постараюсь ответить на этот вопрос. Дело в том, что каждый символ имеет пиксели, индекс цвета которых уникален только для него, поэтому его можно легко распознать. Например в тройки закрашен первый и восьмой пиксель, если считать с нуля: Code: [COLOR="Cyan"][B]0[/B][/COLOR] 0[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0 [COLOR="Cyan"][B]1[/B][/COLOR] [B][COLOR="Yellow"][U]1[/U][/COLOR][/B][COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]2[/B][/COLOR] 000000[COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]3[/B][/COLOR] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]4[/B][/COLOR] 000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0 [COLOR="Cyan"][B]5[/B][/COLOR] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]6[/B][/COLOR] 000000[COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]7[/B][/COLOR] 000000[COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]8[/B][/COLOR] [B][COLOR="Yellow"][U]1[/U][/COLOR][/B][COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [COLOR="Cyan"][B]9[/B][/COLOR] 0[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0 А в цифры 4 - закрашен пятый и шестой, но не закрашен четвертый. Code: [B][COLOR="Cyan"]0[/COLOR][/B] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]1[/COLOR][/B] 0000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]2[/COLOR][/B] 000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]3[/COLOR][/B] 00[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]0[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]4[/COLOR][/B] [COLOR="Yellow"][U][B]0[/B][/U][/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]5[/COLOR][/B] [COLOR="Yellow"][U][B]1[/B][/U][/COLOR][COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]6[/COLOR][/B] [COLOR="Yellow"][U][B]1[/B][/U][/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]7[/COLOR][/B] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]8[/COLOR][/B] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] [B][COLOR="Cyan"]9[/COLOR][/B] 00000[COLOR="Red"]1[/COLOR][COLOR="Red"]1[/COLOR] Немножко посидев и посмотрев на эти числа в фотошопе, я вывел таблицу в виде массива уникальных индексов цвета и их закраски в цифрах 0-9. PHP: $numbers = array ( 1 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 5 => 0 ), 2 => array ( 0 => 0, 2 => 1, 9 => 1 ), 3 => array ( 1 => 1, 8 => 1 ), 4 => array ( 4 => 0, 5 => 1, 6 => 1), 5 => array ( 0 => 1, 1 => 1, 5 => 0 ), 6 => array ( 0 => 0, 1 => 0, 4 => 1, 7 => 1 ), 7 => array ( 0 => 1, 9 => 1 ), 8 => array ( 0 => 0, 1 => 0, 2 => 1, 4 => 0, 6 => 1 ), 9 => array ( 0 => 0, 1 => 0, 3 => 1, 5 => 0 ), 0 => array ( 0 => 0, 2 => 0, 3 => 1, 4 => 1, 5 => 1, 7 => 0) ); Итак, половина работы проделана, остается каждое из этих чисел проверить по первому столбцу изображения, и если все индексы и их закраска в массиве равны индексам в первом ряде символа, то вывести это число. PHP: foreach ($numbers as $k_num => $number) { foreach ($number as $key => $value) { if ($gd[$key] == $value) $k++; } if ($k == count($number)) { $cp .= $k_num; } $k = 0; } foreach - цикл предназначен специально для перебора массивов. Здесь команды циклически выполняются для каждого элемента массива, при этом очередная пара ключ=>значение оказывается в переменных $ключ и $значение. В первом цикле перебираются все массивы номеров. Дальше в цикле идет цикл, в котором - если массив $gd с индексом $key равно $value, то переменная $k увеличивается на еденицу. Тобишь если все пары индекс => цвет верны, то $k будет равно текущему числу а если это так, то оно дописывается в переменную $cp. После всего этого остается вывести переменную с каптчей: PHP: echo $cp; А вот и весь наш код: PHP: <?php error_reporting(E_ALL ^ E_NOTICE); $captcha = imagecreatefrompng("php_captcha.png"); $numbers = array(1 => array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 5 => 0), 2 => array(0 => 0, 2 => 1, 9 => 1), 3 => array(1 => 1, 8 => 1), 4 => array(4 => 0, 5 => 1, 6 => 1), 5 => array(0 => 1, 1 => 1, 5 => 0), 6 => array(0 => 0, 1 => 0, 4 => 1, 7 => 1), 7 => array(0 => 1, 9 => 1), 8 => array(0 => 0, 1 => 0, 2 => 1, 4 => 0, 6 => 1), 9 => array(0 => 0, 1 => 0, 3 => 1, 5 => 0), 0 => array(0 => 0, 2 => 0, 3 => 1, 4 => 1, 5 => 1, 7 => 0)); for ($i = 0; $i <= 4; $i++) { $im = imagecreatetruecolor(7, 10); imagecopy($im, $captcha, 0, 0, 9 * $i, 13, 7, 10); for ($j = 0; $j <= 9; $j++) { if (imagecolorat($im, 0, $j) != 16777215) $gd[$j] = 1; else $gd[$j] = 0; } foreach ($numbers as $k_num => $number) { foreach ($number as $key => $value) { if ($gd[$key] == $value) $k++; } if ($k == count($number)) { $cp .= $k_num; } $k = 0; } } echo $cp; ?> Постскриптум Это моя первая статья по PHP, так что прошу не судить строго Оценивайте, отписывайтесь, критикуйте, спрашивайте Копипаст разрешен только с согласия автора, тоесть меня! Стучите в асю 674542 с просьбой об копировании на свой форум.
С тех пор, как появились “сервисы” anti-captcha.com и ей подобные я думал, что все забросят это дело и начнут повсеместно использовать быдлотруд ишачащих там школьников ( что в принципе и случилось ). Не может не радовать тот факт, что есть люди, которые продолжают работать в направлении автоматического распознавания капчи. mailbrush, большой плюс. Их на античате было как минимум 3 (если не поудаляли). И все посвящены распознаванию элементарных капчей. Кроме того кое-какие материалы по этой теме можно найти на хабре. То, что нашел сходу http://forum.antichat.net/showthread.php?p=1131976 Так же рекомендую ознакомиться с этим https://docs.google.com/fileview?id=0B-xpafMYi--7M2U4OGY3MWEtYzNjYi00OTkyLTg0ZDYtZjQzZTVkMmJhYWEz&hl=ru Эх было б здорово чтобы какой-нибудь кодер реализовал приведенные там методы и алгоритмы =)
Возможно, были готовые скрипты, пускай даже с комментами, просто у меня руки кривые, и не нашёл Хех, завтра почитаю, а то текста много
Очень даже прикольно, зачетная статья, риспект. Осталось добавить только немного AI для распознавания чуть других капч, не таких именно. Но все равно классно
https://forum.antichat.ru/threadnav62896-1-10.html ыот тоже про капчи. имхо беспонтовая статья. именно из за простоты. надоели однообразные. в тысячу раз интереснее почитать как на php распознать капчу e-gold'a или еще какие сложные..а тут ниче интересного
Вот так мы определяем координаты по Y значению, то есть по цифрам справо, а как сделать что бы можно было и по x значению определить?
Всё же для этих целей пока лучше подходят сервисы. Написал для таких своё обвязку на PHP https://github.com/jumper423/decaptcha/blob/master/docs/README-ru.md