Капча на PHP и GD

В современной веб-форме, мы часто сталкиваемся с изображением captcha . Это необходимое средство защиты от программы, которая автоматически заполняет веб-форму. Эта статья научит Вас, как сделать самому Captcha (капча) для формы веб-приложения.

Разработка CAPTCHA

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

Captcha на PHP

Рисование каптчи

Для того что бы нарисовать капчу нужно установить библиотеку GD (Graphics Draw). Эта библиотека рисует графику и изображение с помощью встроенных функции в PHP.

Установка GD

Для установки GD на Ubuntu запустите sudo apt-get install php5-gd .

В Windows, вы должны включить модуль GD2 DLL php_gd2.dll в php.ini. Старый модуль GD1 DLL php_gd.dll был удален в версии PHP 4.3.2. Функции для работы с полноцветными изображениями, такие как imagecreatetruecolor() , требуют наличие GD2.

Повысить возможности библиотеки GD для работы с большим количеством форматов изображений можно, используя опцию —with-XXXX во время конфигурации PHP.

Поддерживаемые форматы изображений
Формат изображения Опция при конфигурировании
jpeg Чтобы включить поддержку jpeg добавьте —with-jpeg-dir=DIR . Jpeg 6b, 7 или 8 поддерживаются.
png Чтобы включить поддержку png добавьте —with-png-dir=DIR . Внимание, libpng требует наличие библиотеки zlib , поэтому добавьте —with-zlib-dir[=DIR] при конфигурации.
xpm Чтобы включить поддержку xpm добавьте —with-xpm-dir=DIR . Если во время конфигурации не удается найти необходимую библиотеку, можно указать путь к библиотеке X11.

Создание капчи на PHP

Капча, как правило, состоит из 3-х вещей : фигура, искажение и текст .

Мы будем выполнять описанные ниже действия:

Вывести пустое изображение

Изображение капчи, будет отображаться как внешнее изображение с помощью простого тега “img” который используется в HTML . Для этого нужны две функции, одна — для создания изображения, а другая для вывода его в браузер.



<?php
session_start();
?>

    <title>demo.php</title>
    <body style="background-color:#ddd; ">

    <?php
    create_image();
    display();
    /***** определение функций *****/
    function display()
    {
        ?>

        <div style="text-align:center;">
            <h3>Введите текст, который видите на картинке</h3>
            <b>Чтобы проверить, что вы не робот</b>

            <div style="display:block;margin-bottom:20px;margin-top:20px;">
                <img src=
http://pixelcom.crimea.ua/"image.png">
            </div> //закрыт div1
        </div> //закрыт div2

    <?php
    }

    function  create_image()
    {
        $image = imagecreatetruecolor(200, 50);
        imagepng($image, "image.png");
    }

    ?>
    </body>
<?php
?>


Первая строка указывает, что пользователь на странице с капчей.

В функции display() не что иное, как обычный код HTML, который выводит изображение в браузер.

Внутри функции create_image() , переменная, используется для обозначения изображения, возвращенного функцией imagecreatetruecolor() , которая в качестве своих аргументов принимает длину и ширину изображения . Функция imagepng() создает изображение png по указанному пути и имени (в одном каталоге).

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

Изображение капчи на странице
Изображение капчи на странице будет в виде черного прямоугольника

Обратите внимание, что функция imagepng() будет последней строкой нашей функции а все следующие шаги должны быть вставлены в функцию create_image() до вызова этой функции, иначе они не вступят в силу.

Фигура для капчи

Фигура для captcha может быть любая, в нашем примере капчи, прямоугольник шириной 200, высотой 50, это значение функции imagefilledrectangle() и цвет фона. Вы можете использовать другую функцию например, фигуру эллипса, круга и т.д…

Функция imagecolorallocate() принимает цвет переменной, где цвет RGB в качестве аргументов. Следующий код будет добавляться в функцию create() .



$background_color = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image,0,0,200,50,$background_color);


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

Генерировать случайные линий.

В нашем примере, линии нужны что бы исказить изображение captcha для нечеткого чтения. В PHP, линии создаются по координатам от начальной точки (x1,y1) до конечной точки(x2,y2). Теперь, как сделать чтобы наши линии, были поперёк поля капчи, у нас будет <x1,x2> координаты <0,200> т.е., ширина нашего прямоугольника. Координаты <y1,y2> генерируется случайным образом. Это позволит создать линии под разным углом. Мы будем генерировать всего несколько линий, поместив данный функционал внутри цикла for.



$line_color = imagecolorallocate($image, 64,64,64);
for($i=0;$i<10;$i++) {
    imageline($image,0,rand()%50,200,rand()%50,$line_color);
}


Функция imageline() принимает x1,x2,y1,y2 — координаты в качестве аргументов. Цвет линии был выделен только в качестве цвета фона, как в предыдущем шаге.

y — координаты в виде rand()*%50 потому что это высота нашего поля для капчи и всегда будет возвращать значение ниже 50. В качестве альтернативы вы можете использовать rand(0,50) .

После добавления случайные линий, прямоугольник капчи должен иметь примерно такой вид:

Случайные линии капчи
Вид прямоугольника капчи после добавления случайных линии

Генерировать случайные точки.

Случайные точки будут создаваться точно так же, как случайных линий. Для этого используется функция imagesetpixel() . Эта функция принимает значение координат, где точки будут размещаться в поле капчи.



$pixel_color = imagecolorallocate($image, 0,0,255);
for($i=0;$i<1000;$i++) {
    imagesetpixel($image,rand()%200,rand()%50,$pixel_color);
}


x — координата, генерируется случайным образом с помощью rand()*%200 это ширина нашего прямоугольника капчи. В качестве альтернативы можно использовать rand(0,200) .

Капча с случайными точеками
Вид прямоугольника капчи после добавления случайных точек

Генерировать случайный текст

Переменная $letters содержит буквы с нижнем и верхнем регистре.



$letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$len = strlen($letters);
$letter = $letters[rand(0, $len-1)];

$text_color = imagecolorallocate($image, 0,0,0);


Внутри цикла, выглядит это примерно так:



for ($i = 0; $i< 6;$i++) {
    $letter = $letters[rand(0, $len-1)];
    imagestring($image, 5,  5+($i*30), 20, $letter, $text_color);
    $word.=$letter;
}
$_SESSION['captcha_string'] = $word;


О линиях



$word.=$letter;
 $_SESSION['captcha_string'] = $word;


смотрите в разделе, обработка ответа капчи .

Функция imagestring() пишет текст на изображении. Она имеет 6 аргументов:

  1. Изображение, ссылки.
  2. Размер шрифта текста (это может быть 5 не более).
  3. x — координата (изменение пропорционально для каждой буквы).
  4. y — координата (так же, хотя можно изменить на случайно).
  5. Фактическая строка, которая будет записана.
  6. Цвет шрифта текста.

Если вы хотите, большой шрифт или другое написание используйте для этого функцию imagettftext() . Она имеет 2 дополнительных аргумента, наклон и стиль шрифта текста.

Вычисление x — координаты осуществляется методом (научного тыка). Грубо говоря, буквы, расположенные на расстоянии около 35px (5+($i*30)) где $i=0,1,2,3,4,5,6 . Если указать значение примерно на 15-20 px, появилась бы возможность двух пересекающихся букв. Если значение было больше, чем 40px, буквы, вообще бы не поместились в прямоугольнике капчи.

Код captcha создаст текст из 6 букв. Всегда можно добавить случайности путем изменения аспектов; y — координат, цвета и т.д…

Окончательный вид captcha:

Текст в captcha будет меняться при каждом обновлении страницы
Окончательный вид капчи с текстом

Текст в captcha будет меняться при каждом обновлении страницы. Добавить случайность можно с помощью создания конструкций с пикселями или путем изменения цвета или размера.

Обработка ответа капчи

После нажатия кнопки отправить ответ пользователя обрабатывается. Есть много способов обработки captcha в соответствии с требованиями веб-приложения. Но, для простоты, результат обработки будет на той же странице.

Из предыдущих фрагментов кода, остались две строки без объяснения:

  1. $word.=$letter; — оператор конкатенации . используется, чтобы добавить все отдельные буквы одна за другой, создавая из 6-ти букв слово.
  2. $_SESSION['captcha_string'] = $word; Строка captcha хранится в переменной сеанса, который будет использоваться с целью проверки достоверности.

Мы изменим определение display() добавим форму, подобную структуре.

Для капчи будут использоваться две кнопки submit, одна для отправки, а другая обновить страницу.

Следующий код нужно добавить между закрытыми тегами div (см. комментарии для функции display() )



function display()
{
    ?>

    <div style="text-align:center;">
        <h3>Введите текст, который видите на картинке</h3>
        <b>Чтобы проверить, что вы не робот</b>

        <div style="display:block;margin-bottom:20px;margin-top:20px;">
            <img src=
http://pixelcom.crimea.ua/"image<?php echo $_SESSION['count'] ?>.png">
        </div>
        <form action=" <?php echo $_SERVER['PHP_SELF']; ?>" method="POST"
        / >
        <input type="text" name="input"/>
        <input type="hidden" name="flag" value="1"/>
        <input type="submit" value="отправить" name="submit"/>
        </form>

        <form action=" <?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
            <input type="submit" value="обновить страницу">
        </form>
    </div>

<?php
}


Прежде чем продолжить, нам нужно знать, когда показать и когда не отображать поле ввода. Поле будет отображаться при условии:

  1. если страница просто загружена.
  2. если ответ был неверным.

Первое условие выполняется с помощью $flag и имеет значение ‘1’ каждый раз при нажатии кнопки submit. Первоначально он был установлен в любое другое значение. Второе условие достигается путем проверки совпадения значении, хранящихся в нашей переменной с вводимыми пользователем (см. код ниже).

Чтобы добиться этого, мы заменим следующие строки нашего кода в начале статьи:



create_image();
    display();


на:



$flag = 5;

if (isset($_POST["flag"])) // проверка, что переменная POST не является пустым
{
    $input = $_POST["input"];
    $flag = $_POST["flag"];
}

if ($flag == 1) // кнопка submit была нажата
{
    if (isset($_SESSION['captcha_string']) && $input == $_SESSION['captcha_string']) // ввод пользователя и строка ЗАЩИТНЫЙ КОД совпадает
    {

        ?>

        <div style="text-align:center;">
            <h1>Ваш ответ правильный!</h1>

            <form action=" <?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> // обновить страницу
                <input type="submit" value="обновить страницу">
            </form>
        </div>

    <?php

    } else // ответ неправильный, ЗАЩИТНЫЙ КОД показан снова
    {

        ?>
        <div style="text-align:center;">
            <h1>Ваш ответ неправильный!<br>пожалуйста попробуйте снова</h1>
        </div>
        <?php
        create_image();
        display();
    }

} else // страница просто была загружена
{
    create_image();
    display();
}


Обратите внимание, что функции create_image() и display() вызываются лишь при двух условиях, рассмотренных выше.

Теперь Captcha будет выглядеть так;

Вид капчи на странице ввода
Вид капчи для ввода букв пользователем

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

Ввод капчи является неправильным
Неправильный ввод букв на изображении капчи

Если входные данные введены правильно, то пользователю будет показано сообщение.

Сообщение пользователю капчи
Входные данные капчи введены правильно

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

Решение очень простое — чтобы браузер не находил изображения в кэше, для них мы создадим уникальные имена. Добавим функцию time() с именем изображения при создании, для отображении в браузере.

Добавьте эту строку ниже того места, где вы начинали сессии:



$_SESSION['count']=time(); // уникальная строка


Заменить тег img src в функции display() на



<img src=
http://pixelcom.crimea.ua/"image<?php echo $_SESSION['count']?>.png">


И та часть, где мы создали изображение png в функции create_image() также замените



imagepng($image,"image".$_SESSION['count'].".png");


Изображение теперь будет называться примерно так : image39342015.png . Эта процедура будет создавать изображение столько раз, сколько раз обновляется страница, это может занять огромное количество дискового пространства, поэтому мы убедимся, что перед созданием изображения, все другие изображения png расширение удаляются. Добавьте следующею функцию вызова перед imagepng() .



$images = glob("*.png");
foreach($images as $image_to_delete)
{
    unlink($image_to_delete);
}


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

Скачать captcha на PHP

Заключение

Создать различные виды каптчи с помощью PHP не составляет труда. В этой статье рассматриваются три основные вещи, используемые для создания стандартной captcha — фигура, искажения и текст . Существует ReCaptcha, который также поддерживает вывод звука, чтобы помочь людям с нарушениями зрения. Мы надеемся, что вы нашли эту статью полезной. Оставить свои комментарии ниже!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>