Итак, закончили мы на том, что нарисовали все цифры, создали массивы php с псевдографическими изображениями цифр и написали отладочную функцию, которая выводит конкретную цифру. Продолжаем!
Для начала условимся, то нашему злодею-хацкеру, распознающему каптчу, мы, хоть и ненамного, но усложним задачу: «пробельные» («пустые») символы в изображении каждой цифры, а также сами символы, изображающие цифру, будут выбраны случайно из заранее заданного набора. Зададим набор символов, изображающих цифру, в виде строки:
$pgstring="#$%@!?0"; //символы, из которых будут составлены цифры
Аналогично и для «пустых» символов:
$spstring="- "; //пробельные символы
Тут все зависит от вкуса, цвета и лично ваших глазок. Главное, чтобы в строке с возможными «пустыми» символами и в строке с возможными символами, изображающими цифру, не встретилось одинаковых символов, иначе при определенных условиях, пользователь вполне может получить вот такую вот гадость, вместо каптчи:
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
Заведем еще две переменные, которые будут хранить выбранные символы для «пробельных» и символов изображения:
$pgchar="";
$spchar="";
Пока просто оставим их пустыми, потом к ним еще вернемся.
Первым делом, нам понадобится функция, генерирующая код каптчи нужной длины. Она довольно проста:
function getcaptchacode($codelen) { $ans=""; for ($i=0;$i<$codelen;$i++) { $r=rand(0,9); $ans=$ans.$r; } return $ans; }
В качестве параметра ($codelen
) функции передается длина необходимого нам кода каптчи, далее функция генерирует строку, состоящую из символов от 0 до 9 заданной длины. На самом деле на каждой итерации цикла for
генерируется ($r=rand(0,9);
) случайное число в диапазоне от 0 до 9, но PHP такой странный язык, что отдельно (если кто не знает) заниматься преобразованием числа в строку, нам не требуется. После генерации числа от 0 до 9 просто присоединяем его к строке
$ans
($ans=$ans.$r;
), а конвертацией занимается интерпретатор.
Если философствовать, то это вообще-то большой минус, но в данном случае он вполне себе плюс. Но философствовать мы не будем, лучше продолжим.
Функция, возвращающая случайный символ из заданной строки.
//получает случайный символ из строки function randomchar($srcstr) { $i=rand(0,strlen($srcstr)-1); return $srcstr{$i}; }
Тут вообще все просто — на входе передаем строку с набором символов ($srcstr
), случайно выбираем позицию любого символа в строке, начиная с первого (нулевого) и заканчивая последним (длина строки, возвращаемая стандартной функцией strlen - 1
). Записываем полученное значение в переменную $i
($i=rand(0,strlen($srcstr)-1);
) обращаемся к конкретному символу в строке по ранее сохраненному номеру (позиции) с помощью конструкции «{}
» и возвращаем его (return $srcstr{$i}
).
Этим делом будет заниматься функция getpgnum
:
function getpgnum($numstr,$numarr,$spchr,$spctr,$startsp,$endsp) { ... }
Ей передаются следующие параметры:
$numstr
(строка, состоящая из цифр) — Строка цифр, в случае каптчи, это будет код, сгенерированный ранее вызванной функцией getcaptchacode
.
$numarr
— массив, содержащий псевдографические изображения всех цифр (ранее созданный $allnum
)
$spchr
(строка) — символ для промежутка между цифрами каптчи
$spctr
(целое число) — количество символов между цифрами каптчи.
Т.е. если мы в качестве параметра $spchr
зададим символ [!
], а в параметре $spctr
передадим число, например 4, то цифры каптчи будут разделены четырьмя восклицательными знаками. Вообще использовать можно любой символ, даже случайно выбранный. На практике я использую пробел. А тут восклицательные знаки для наглядности.
$startsp
(логическое значение) — если установлено в true
, то перед самим изображением каптчи так же будут добавлены символы, заданные в параметре $spchr
в количестве заданном в параметре $spctr
$endsp
(логическое значение) — то же самое, что и предыдущий параметр, но только для пробелов в конце строк изображения каптчи.
Определяем основные внутренние переменные функции:
Переменная, в которой будет храниться готовое псевдографическое изображение каптчи — результат работы функции:
$ans="";
Переменная, для хранения строки из пробелов между числами:
$spstr="";
Переменная, для хранения отдельной цифры из строки
$numstr
:
$num=0;
Текущая строка формируемого псевдографического изображения:
$curline="";
Проверяем, что строка в переменной $numstr
состоит только из цифр:
if (!is_numeric($numstr)) //если в строку запихали не цифру
{
echo ("ERROR: NOT NUMBER ".$numstr); //выводим ошибку и
//завершаем скрипт
die();
}
Формируем строку символов между цифрами каптчи:
//формируем строку пробельных символов
for ($i=0;$i<$spctr;$i++)
{
$spstr=$spstr.$spchr;
}
Формируя изображение каптчи, алгоритм будет действовать примерно, как ЭЛТ-монитор, т.е. формировать изображение сразу всех цифр, но построчно, т.е. брать первую строку, из всех изображений цифр, указанных в переменной $numstr
, дополнять ее после перехода к следующей цифре из переменной $numstr
пробелами. Получившуюся строчку при надобности обрабатывать (добавлять начальные и удалять конечные пробелы, добавлять перенос строки) и присовокуплять обработанную строчку к значению, возвращаемому функцией.
Вот видео, иллюстрирующее процесс:
Прямая ссылка
//проходим по всем строчкам изображения
//цифры все одинаковой высоты - 5 строк
for ($j=0;$j<5;$j++)
{
//проходим по строке с числом
for ($i=0;$i<strlen($numstr);$i++)
{
$num=$numstr{$i}; //вытаскиваем отдельную цифру $imgnum=$numarr[$num]; //вытаскиваем изображение конкретной цифры
//$imgnum[$j] - конкретная строчка изображения
//формируем текущую линию для изображения всех цифр каптчи
$curline=$curline.$imgnum[$j].$spstr;
}
//линия сформирована
if ($startsp) //если нужны стартовые пробелы - добавляем
{
$curline=$spstr.$curline;
}
if (!$endsp) //если НЕ нужны конечные пробелы - удаляем
{
$curline=substr($curline,0,strlen($curline)-$spctr);
}
$ans=$ans.$curline."\r\n"; //в конце строчки добавляем перенос строки
$curline=""; //очищаем переменную для хранения текущей строки каптчи
}
Во внешнем цикле (for ($j=0;$j<5;$j++)
) проходим по всем строчкам изображения каптчи, поскольку у нас все цифры одинаковой высоты, то это можно прямо на месте и указать ($j<5
). Сразу же начинаем внутренний цикл, формирующий конкретную строчку изображения всей каптчи (for ($i=0;$i<strlen($numstr);$i++)
). Этот цикл пройдет по всей строке с заданным кодом ($numstr
).
В нем сначала извлекаем из строки конкретную цифру и сохраняем ее значение в переменной $num
($num=$numstr{$i}
).
Далее, копируем псевдографическое изображение отдельной цифры в переменную $imgnum
($imgnum=$numarr[$num];
).
Формируем текущую строку ($curline
) изображения всех цифр каптчи с пробелами ($spstr
) между строками изображения конкретной цифры ($curline=$curline.$imgnum[$j].$spstr
). Переменная $j
, задается во внешнем цикле - это номер строки изображения, обрабатываемый в данный момент.
После внутренний цикл завершается, и готовая строка ($curline
) дообрабатывается во внешнем цикле, ей добавляются или из нее удаляются начальные/конечные пробелы, в зависимости от установленных переменных ($startsp
и $endsp
):
//линия сформирована
if ($startsp) //если нужны стартовые пробелы - добавляем
{
$curline=$spstr.$curline;
}
if (!$endsp) //если НЕ нужны конечные пробелы - удаляем
{
$curline=substr($curline,0,strlen($curline)-$spctr);
}
Далее добавляются символы переноса строки, сформированная строка присоединяется к общему ответу функции:
$ans=$ans.$curline."\r\n";
Текущая строка изображения обнуляется, и внешний цикл переходит к формированию следующей строки.
$curline=""; //очищаем переменную для хранения текущей строки
//каптчи
Если цикл формирования изображения завершился, то функция возвращает значение:
return $ans;
С функциями вроде закончили. Осталось, как я и обещал в самом начале, немного подгадить злодею, подбирающему каптчу. Ранее были заданы переменные $pgchar
и $spchar
, пока никак не использованные, строки $pgstring
и $spstring
содержащие заданный набор символов, а также создана функция randomchar
, возвращающая случайный символ из строки.
В первой части мы условились, что символы, формирующие изображение цифры, это символы $
, а символы, занимающие пустые места в изображении - *
.
Настало время ОТКРЫТЬ ВРАТА ШТАЙНЕРА, ХА-ХА-ХА использовать это и функцию randomchar
, наконец.
После области функций пишем следующий код.
1. Случайно выбираем символ для символа изображения ($pgchar
) и пустого ($spchar
), из содержащихся в заранее заданных строках ($pgstring
и $spstring
):
$pgchar=randomchar($pgstring);
$spchar=randomchar($spstring);
2. Теперь заменяем заранее определенные символы *
и $
в массиве с изображением цифр, на полученные случайные:
//заменяем символы в псевдографике на случайные for ($i=0; $i<count($allnum); $i++) //цикл по массиву со всеми цифрами { for ($j=0; $j<count($allnum[$i]); $j++) //цикл по всем строчкам с псевдографикой { $allnum[$i][$j]=str_replace("$",$pgchar,$allnum[$i][$j]); $allnum[$i][$j]=str_replace("*",$spchar,$allnum[$i][$j]); } }
В данный момент, мы имеем готовый include-модуль, формирующий код каптчи и ее псевдографическое изображение. В следующей части будут примеры ее использования.
Pingback: ASCII-каптча, каптча псевдографикой. Часть I. | Персональный блог Толика Панкова
Pingback: ASCII-каптча, каптча псевдографикой. Часть III. Примеры использования. | Персональный блог Толика Панкова