Создание юзабильной капчи на PHP с картинками

Приветствую Вас, дорогие друзья!

Сегодня мы рассмотрим и создадим с нуля оригинальную и юзабильную («дружественную» для пользователя) капчу на PHP. То есть, все наверняка встречали капчи, где прямо, так скажем, надо всё расшифровывать по буквам. Вот я лично не люблю такие капчи и по этому решил создать такую юзабильную и простую капчу. Ну что же, начнём…


Для начала разберемся с организацией файлов. Для данной работы нам понадобиться локальный сервер (например, Denwer). Создаём директорию с нашим проектом (например, captcha.loc) в которой будут следующие директории и файлы:

директория css -> style.css – файл стилей;

директория images -> apple.png, apricot.png, kiwi.png, lemon.png, orange.png – наши картинки для капчи;

файл .htaccess -> в данном случаем он нам понадобиться для дополнительного указания кодировки UTF-8;

файл index.php -> в нём мы и будем писать весь наш код.

И так – приступим.

ШАГ 1 – Создаём HTML-разметку:

Здесь идёт простая HTML-разметка. Единственный момент который может Вас насторожить, это: почему в скрытом поле (строка 33) атрибут value не заполнен? В атрибут value будет подставляться и сравниваться значение с тем, что выбрал пользователь, и тем сгенерированным значением, что было запомнено в сессии.

Файл .htaccess — это файл дополнительной конфигурации веб-сервера Apache. В нём всего одна строчка кода, в которой указывается кодировка нашего документа. Хотя в самом HTML-документе мы указали кодировку, но бывает такая ситуация, когда в самом браузере стоит кодировка Windows-1251 (кириллица), а в документа — UTF-8 — понятно, что документ будет отображаться в кодировке Windows-1251 (приоритет браузера выше), и для того, чтобы документ отображался в той кодировке что нам и нужно — служит файл .htaccess. В этом файле добавим строчку: AddDefaultCharset utf-8

<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="css/style.css">
  <title>Юзабильная капча с картинками</title>
 <!-- Подключаем jQuery-библиотеку -->
 <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
 <!-- Здесь будет Наш дальнейший JavaScript код -->
</head>
<body>

<div class="form">

 <h2>Оставить комментарий:</h2>

 <form method="POST" action="">
   <label for="name">Ваше имя:</label><br />
   <input type="text" id="name" name="name" size="45" /><br />

   <label for="text">Введите сообщение:</label><br />
   <textarea name="text" id="text" rows="5" cols="33"></textarea><br />
   <p>Выберите <strong><?php echo $_SESSION['fruit']?>:</strong></p>

   <div class="captcha">
     <img src="images/apple.png" width="50px" height="50px" alt="яблоко">
     <img src="images/apricot.png" width="50px" height="50px" alt="абрикос">
     <img src="images/kiwi.png" width="50px" height="50px" alt="киви">
     <img src="images/lemon.png" width="50px" height="50px" alt="лимон">
     <img src="images/orange.png" width="50px" height="50px" alt="апельсин">
   </div>

   <input type="hidden" name="fruit" id="fruit" value="">
   <input type="submit" name="submit" id="submit" value="Отправить" />
 </form>
 <!-- Здесь будут выводиться данные -->

</div>

</body>
</html>

ШАГ 2 – Добавляем стили:

Правило !important (строка 14) — позволяет повысить приоритет стиля, т.е. это правило для нас будет важнее. Как результат, когда мы щёлкнем по картинке, то рамка останется.

.captcha {
  margin: 10px 0;
}
.captcha img {
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
  margin-right: 5px;
}
.captcha img:hover, .active {
  -moz-box-shadow: 0 0 10px #808080;
  -webkit-box-shadow: 0 0 10px #808080;
  box-shadow: 0 0 10px #808080;
  border: 1px solid #7CFC00 !important;
}
/* стили для вывода конечного сообщения */
.ok, .not_ok {
  width: 285px;
  padding: 5px;
  margin: 10px 0;
  border-radius: 5px;
}
.ok {
  border: 1px solid #008000;
  background: #BAFAC1;
  color: #008000;
}
.not_ok {
  border: 1px solid #FF0000;
  background: #FFD5D5;
  color: #FF0000;
}

ШАГ 3 – Пишем код JavaScript:

Этот JavaScript код нужно вставлять межу тегами head.

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

И так, когда пользователь кликает по картинке, мы берем все картинки и методом each проходим по всем картинкам, и при клике по картинке скрипт будет добавлять класс active (то есть, просто будет устанавливаться зеленая рамка) и получать значение атрибута alt.

Если пользователь кликнет на другую картинку, то ей просто будет добавляться класс active, а для остальных картинок класс active — удаляется!

Дальше, мы обращаемся к тому элементу, по которому был клик и обращаемся к его атрибуту alt, потом помещаем его значение в переменную fruit, обращаемся к нашему скрытому полю с id=»fruit» и в его же значение записываем то, что есть в переменной fruit — это нужно для сравнения значений!

А в  строке 4 мы просто будем очищать значение скрытого поля, чтобы оно постоянно не запоминалось.

<script type="text/javascript">
 $(document).ready(function () {

  $("#fruit").val('');

  $(".captcha img").click(function() {
     $(".captcha img").each(function() {
     $(this).removeClass("active");
  });
     $(this).addClass("active");
     var fruit = $(this).attr("alt");
     $("#fruit").val(fruit);
  });

 });
</script>

ШАГ 4 – Пишем серверный (РНР) код:

Этот РНР код нужно вставлять в самом начале документа, то есть писать РНР код с первой же строки.

Замечание: пробелов и комментариев перед открытием РНР кода НЕ должно быть, иначе выдаст ошибку!

И так, мы создали массив fruits. Далее, генерируем случайный элемент массива fruits и его значение записывается в сессию. Потом проверяем не приходили ли нам данные из формы, то есть, ели данные из формы методом POST вообще НЕ приходили, то мы будем записывать в сессию случайный элемент (фрукт), а иначе мы принимаем данные из формы средствами РНР и будем сравнивать с теми, что у нас есть скрытом поле.

Затем получаем данные из полей формы и проверяем, если пользователь что-то ввел в поле, если ничего не ввел, мы просто его представляем как «Гость«.

Дальше мы должны сравнивать с тем, что у нас есть в сессии и что попало в скрытое поле. И если в глобальном массиве СЕССИЯ, элемент fruit будет равен тому что у нас есть в переменной fruit, то выводим сообщение типа:»Вы прошли проверку и т.д.», а иначе, то есть, элемент fruit НЕ будет равен тому что у нас есть в переменной fruit, мы выводим сообщение типа:»Вы не прошли проверку и т.д.».  Затем делаем редирект, чтобы сбросить POST-данные.

<?php
session_start();
$fruits = array("яблоко", "абрикос", "киви", "лимон", "апельсин");
$randNum = mt_rand(0,4);

if (!$_POST)
{
  $_SESSION['fruit'] = $fruits[$randNum];
}
else
{
  $name = trim(htmlspecialchars($_POST['name']));
  if (empty($name))
  {
     $name = "Гость";
  }
  $text = $_POST['text']; //текстовая облать
  $fruit = $_POST['fruit']; //скрытое поле

  if ($_SESSION['fruit'] == $fruit)
  {
    $_SESSION['result'] = "<div class='ok'>{$name}, Вы прошли проверку. Спасибо за комментарий!</div>";
    header("Location: {$_SERVER['PHP_SELF']}");
    exit();
  }
  else
  {
    $_SESSION['result'] = "<div class='not_ok'>{$name}, Вы не прошли проверку. Попробуйте ещё раз!</div>";
    header("Location: {$_SERVER['PHP_SELF']}");
    exit();
  }
}
?>

ШАГ 5 – Выводим информационное окно:

Этот маленький РНР код нужно вставить после формы.

<?php
if($_SESSION['result'])
{
  echo $_SESSION['result'];
  unset($_SESSION['result']);
}
?>

На этом всё!

Спасибо всем за внимание!

Ждём Ваших отзывов об уроке в комментариях.

Авторские права: webformyself.com

Комменты

  • Привет, ребята. Всё сделал как было указано, а капча срабатывает при любом варианте ответа. Подскажите, что за фигня.
    Спасибо

  • отправил на почту архивом

  • Привет. Капча выглядит красиво, но это не капча, и не потому, что реализация не совсем классическая, а потому что «обходится» за «5 секунд».
    1) картинки выводятся статически с определенной последовательностью и самое главное за определенной картиркой закреплено одно и то же имя, что позволяет без труда создать массив соответсвий.
    2) у каждой картинки в alt прописаны так называемые ответы на вопрос
    3) но в данной реализации капчи, даже на первые два пункта не надо обращать внимание, надо просто взять из лимон: название фрукта и вставить понятное дело куда.
    Что можно сделать для доведения идеи «до ума»:
    Картинки на сервере придется таки генеривовать «на лету», ну или хотябы их имена. Это не означает, что каждый раз надо выдумывать новое мия, достаточно менять местами соответсвие имен с картинками. Но если добавить шума или искажений, то вроде как не повредит. Последовательность картинок надо менять с каждым обновлением страницы. Естественно на сервере в сессии хранить текущее соответсвие правильного ответа

  • Уважаемый теска, а это вы себе верстали тему для вашего блога и заказали у фрилансера?

  • Вот интересно, все стараются вынести скрипты из тега HEAD в конец — перед тегом , а Вы пишете -» Этот JavaScript код нужно вставлять межу тегами head». Тогда надо прикручивать асинхронную загрузку.

  • На Денвере все прекрасно работает! Спасибо! Но на хостинге
    Рамка после клика не остается зеленой… и картинка не выбирается.
    Подскажите в чем может быть причина?

  • Спасибо! Отличная стать! Заточил по похожему принципу капчу для codeigniter. Добавил ещё несколько картинок, плюс сделал примочку, — по наведению на картинку немного увеличивать её (onMouseOver и onMouseOut). Если кому интересно, пишите на aleksandro13-87@mail.ru, или возникнут вопросы, как подобную капчу сделать под поджигателя кода.

  • Sergey, пользуйтесь на здоровье! Спасибо за комментарий 😉

  • Огромное спасибо!

  • У меня есть сайт на локальном сервере (Denwer). Никак не могу сообразить где находиться этот файл style.css.
    Прошу прощения за мою тупость.

  • Alisa, в файл .htaccess просто добавьте строчку — AddDefaultCharset utf-8 , как написал Дмитрий выше.
    В файл style.css просто добавьте те стили, что я написал в уроке.
    Картинки просто перенесите в свою папку с картинками, но правильно укажите путь к ним.
    Если что-то еще не понятно, то пишите здесь или мне на «мыло» — admin@bykandrey.ru

  • Вордпресс-f1, спасибо большое за отзыв!

  • А я вот не поняла.
    На ПК я все сделаю. Но на своем сайте у меня уже есть файл .htaccess. Что туда прописывать?
    И, еще, данный комплект помещать в отдельной папке своего сайта? Потому, что у меня уже есть файлы с аналогичными названиями…
    Поясните…
    Кстати, я бы не прочь иметь такую капчу как у Вас: выбор одного из трех человечков.
    Если можно. опишите данный вариант. Спасибо.

    • Дмитрий Валак: 26-07-2013 в 15:36

      Алиса, в .htaccess добавьте строчку AddDefaultCharset utf-8.
      Картинки можете помещать куда Вам угодно, главное потом пропишите правильно пути к данным картинкам.
      Вместо фруктов можно использовать и человечков. Вам нужны другие картинки и немного поменять код. Вместо массива с фруктами создать массив с человечками и т.д.

  • Спасибо, все работает на внешнем сервере, видимо причина в настройках моего локального сервера.

  • Спасибо, Дмитрий!

    Очень пригодилась вот моя реализация данной капчи:
    http://ketov.biz/kontakt/

    Действительно всё очень просто на самом деле.

  • Исходники скачал и все заработало. Спасибо большое.

  • Как раз вовремя урок попался — только подумал о том, как можно капчу сделать

  • Скачал исходники поставил на сервер, проверил почему-то не работает, выдает сообщение что я прошел проверку, даже если я отвечаю не верно или вообще не выбирал картинку? в чем дело?..

  • Классно! Спасибо большое, очень хорошо все разжевано

  • Дмитрий, спасибо!
    Отличный и полезный урок!
    Я еще просил вас создать урок по добавлению товара в корзину с помощью jQuery. на базе вашего мини урока по созданию интернет магазина.
    Если Вас не затруднит.
    Заранее благодарен!

  • Спасибо, долго ждал)))