Здравствуйте, уважаемые читатели, в данном посте я хочу показать как может выглядеть скрипт Pраспознавание капчи php.
Все мы привыкли ежедневно видеть, на самых разнообразных ресурсах интернета, картинки, надписи на которых нас просят вписать в специальное поле формы, перед каким либо действием, к примеру, перед скачиванием файлов или отправкой сообщений. Такие картинки называются капчами, подробнее о происхождении этого термина можно прочесть в моей статье "Капча на PHP".
И ведь действительно без капчи теперь не обходится ни один из более-менее полезных сайтов. Связано это с тем, что с ростом технологического процесса и развитием ресурсов, становится все больше роботов гуляющих по интернету и вредящих безбрежному благополучию ресурсов, не имеющих защиты от ботов.
Капча как раз таки является одним из средств защиты от роботов, а как следствие и от спама. Все дело в том, что для человека распознать капчу является не трудоемким процессом, а для спам бота оно может стать невыполнимым.
Но нет таких способов защиты, на которые нельзя найти способы взлома, вопрос лишь во времени и средствах. Другими словами, выяснить, что же написано на картинке – можно программно, и я хочу показать, как может происходить распознавание капчи php скриптом.
Как действовать при распознавании капчи
На сегодняшний день существует множество сложных способов распознавания капчи на php и на любых других языках, но чтобы их понять стоит начать с малого, а именно с написания скрипта распознающего примитивную капчу.
Под примитивной капчей понимается картинка с монотонным фоном, на которой изображено трехзначное число. Число всегда выводится в одном шрифте и не имеет коэффициента искажения.
Пример примитивной капчи:
Перед тем как приступить к обдумыванию алгоритмов, и начинать изучать природу нейронных сетей, проанализируем имеющуюся примитивную капчу.
Как видите можно выделить ряд условий формирования этой картинки:
Шрифт всегда одинаковый.
Высота цифр одинаковая.
Между цифрами существует пустота минимум в 2 px.
Алгоритм распознавания такой капчи не требует знаний о нейронных сетях и может выглядеть так:
Разбить все цифры меду собой.
Составить ассоциативный массив с количеством пикселей для каждой цифры.
Посчитать для каждой цифры из капчи, из какого количества пикселей она состоит а именно сколько содержит пикселей отличных от цвета фона.
Получить цифру из массива соответствий.
Распознавание цифр с картинки по шагам.
Переводим картинку в бинарную матрицу (1 шаг)
Вычисляем интервалы содержащие цифры (2 шаг )
Складываем построчно все столбцы, получаем строку:
Вычисление интервалов
По полученной строке можно вычислить интервалы, задающие положение цифр.
Теперь мы знаем, что столбцы матрицы с индексами в интервалах [1,15], [18,32], [35,49] содержат цифры.
Вычисляем количество пикселей для каждой цифры (шаг 3)
Складываем все единицы в найденных интервалах, получаем:
[1,15] = 215 единиц;
[18,32] = 213 единиц;
[35,49] = 184 единиц.
Подсчет количества пикселей для всех возможных цифр (шаг 4)
Скачиваем несколько вариаций капчи, которые содержат все цифры от 0 до 9.
Затем необходимо вычислить количество пикселей для каждой из цифр [1234567890].
Например, подсчитав пиксели в цифре восемь – получим 215 шт.
Вычислив вручную или же с помощью скрипта пиксели, для каждой из цифр получим такую таблицу:
Теперь зная сколько пикселей содержится в каждой из цифр, мы можем распознать капчу, и то что написано на картинке.
В результате у меня получился скрипт который с 100% вероятностью распознает числа на картинках данной капчи:
Набор картинок и сам код скрипта для распознавания капчи php лежит в архиве который можно скачать по следующей ссылке.
<?php
// пробуем распознать картинку 1.png
$encrypt = new crackCapcha('1.png');
echo "<br><span style='font-size: 25px;'>Resolve: ".$encrypt->resolve."</span><br><br>";
class crackCapcha {
public $im;
public $binaryMartix;
public $assocNumber = array(
'200' => 0,
'86' => 1,
'156' => 2,
'180' => 3,
'147' => 4,
'184' => 5,
'213' => 6,
'118' => 7,
'215' => 8,
'209' => 9,
);
public $resolve;
function __construct($path) {
$this->im = @imagecreatefrompng($path);
if (!$this->im){
return false;
}
$this->binaryMartix = $this->imageToMatrix($this->im, true);
$explode = $this->explodeMatrix($this->binaryMartix);
$this->resolve = '';
foreach ($explode as $number) {
$this->resolve .= $this->assocNumber[$number];
}
}
function explodeMatrix($binaryMartix) {
$temp = array();
// сложение столбцов для выявления интервалов
for ($i = 0; $i < count($binaryMartix); $i++) {
$sum = 0;
for ($j = 0; $j < count($binaryMartix[0]); $j++) {
$sum += $binaryMartix[$i][$j];
}
$temp[] = $sum ? 1 : 0;
}
// вычисление интервалов по полученной строке
$start = false;
$countPart = 0;
$arrayInterval = array();
foreach ($temp as $k => $v) {
if ($v == 1 && !$start) {
$arrayInterval[$countPart]['start'] = $k;
$start = true;
}
if ($v == 0 && $start) {
$arrayInterval[$countPart]['end'] = $k - 1;
$start = false;
$countPart++;
}
}
// сложение всех единиц в полученных интервалах столбцов
foreach ($arrayInterval as $interval) {
$sum = 0;
for ($i = 0; $i < count($binaryMartix); $i++) {
for ($j = 0; $j < count($binaryMartix[0]); $j++) {
if ($i >= $interval['start'] && $i <= $interval['end']) {
$sum += $binaryMartix[$i][$j];
}
}
}
$result[] = $sum;
}
return $result;
}
/**
* Конвертация рисунка в бинарную матрицу
* Все пиксели отличные от фона получают значение 1
* @param imagecreatefrompng $im - картинка в формате PNG
* @param bool $rotate - горизонтальная или вертикальная матрица
*/
function imageToMatrix($im, $rotate = false) {
$height = imagesy($im);
$width = imagesx($im);
if ($rotate) {
$height = imagesx($im);
$width = imagesy($im);
}
$background = 0;
for ($i = 0; $i < $height; $i++)
for ($j = 0; $j < $width; $j++) {
if ($rotate) {
$rgb = imagecolorat($im, $i, $j);
} else {
$rgb = imagecolorat($im, $j, $i);
}
//получаем индексы цвета RGB
list($r, $g, $b) = array_values(imageColorsForIndex($im, $rgb));
//вычисляем индекс красного, для фона изображения
if ($i == 0 && $j == 0) {
$background = $r;
}
// если цвет пикселя не равен фоновому заполняем матрицу единицей
$binary[$i][$j] = ($r == $background) ? 0 : 1;
}
return $binary;
}
/**
* Выводит матрицу на экран
* @param type $binaryMartix
*/
function printMatrix($binaryMartix) {
for ($i = 0; $i < count($binaryMartix); $i++) {
echo "<br/>";
for ($j = 0; $j < count($binaryMartix[0]); $j++) {
echo $binaryMartix[$i][$j]." ";
}
}
}
}