2 варианта капчи для сайта

капча на сайт

От автора: интернет вещь хорошая, удобная, полезная, но… было бы совсем замечательно, если бы там не было спамеров. Думаю, все мы сталкивались с таким неприятным явлением, как спам. Это могут быть спамовые письма, спамовые комментарии, в общем, различный мусор. Если на Вашем сайте есть форма обратной связи или система комментариев и Ваш ресурс станет довольно популярным, то ему не избежать внимания спамеров. Эффективной защитой от спама является проверка на человечность — капча.

В этом уроке мы научимся писать собственную капчу, даже в двух вариантах, которая будет не слишком сложной, удобной для пользователя и, вместе с тем, довольно эффективной.

План урока:

    1. Постановка задач (8:01)

    2. Алгоритм капчи №1. Начинаем реализацию (14:56)

    3. Реализуем капчу с математическим выражением (12:03)

    4. Реализуем капчу вопрос-ответ (17:49)

скачать исходникискачать урок

1. Постановка задачи

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

Для того, чтобы не отправлять сообщения, заполненные ботами придуман не один способ. Наверное, самым первым и наиболее известным является CAPTCHA (аббревиатура, обозначающая приблизительно следующее — "автоматизированный тест для различия компьютеров и людей")… но вместе с тем — это самый неудобный для пользователя вариант (на мой взгляд). Думаю, многие сталкивались с заполнением капчи — иногда приходится буквально "расшифровывать" ее, гадая — что же это за символ? Вроде расшифровал, вводишь… получаешь сообщение, что заполнено неверно… начинаем заново наши потуги на поприще дешифрования… иногда вообще методом тыка догадываешься, что разработчики именно этой капчи учитывают еще и регистр символов, но при этом, ни слова не сказали об этом… появляется при этом стойкое желание назвать таких разработчиков нехорошим словом.

Да и к тому же на сегодня капча не является уже надежной защитой от автоматического заполнения формы или автоматической регистрации — боты "умнеют" и зачастую могут распознавать ее (из собственного опыта: на форуме со стандартной капчей, который ставил для одной фирмы, в день было до 10 автоматических регистраций, соответственно, примерно столько же непотребных тем, после замены капчи на антибот типа "вопрос-ответ" боты больше не регистрировались)… кроме того, существуют даже ресурсы, которые нанимают кликеров, чтобы те работали на благо спамеров — вводили символы с капчи.

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

Вот некоторые варианты, которые, на мой взгляд, с успехом могут конкурировать с традиционной капчей:

    1. посчитать результат сложения (или другого математического действия) двух случайных чисел;

    2. дать ответ на простой вопрос, типа "Название нашей планеты";

    3. снять/установить галочку в чекбоксе;

    4. кликнуть по определенной картинке из ряда предложенных.

Именно первые два варианта мы и реализуем в этом уроке. Для урока мы возьмем простенькую форму из двух полей, посредством которой будем отправлять значение одного из полей на e-mail. Значение второго поля — это и будет результат проверки на человечность. Создадим страницу index.php с кодом формы:

Думаю, на этом с вводной частью можно закончить и переходить к созданию алгоритма и его реализации.

2. Алгоритм капчи №1. Начинаем реализацию

Алгоритм реализации капчи с математическим выражением очень прост. Что нам необходимо? Нам необходимы 2 случайным образом сгенерированных числа, допустим от 1 до 10. Далее, мы, конечно же, должны хранить для себя результат сложения этих чисел, чтобы после того, как пользователь отправит данные, мы смогли сравнить его результат с нашим. Если результаты совпадут — проверка на человечность пройдена и можно отправлять данные на e-mail, иначе — проверка не пройдена, и мы должны сгенерировать 2 новых числа, запомнить результат их сложения и предложить пользователю попробовать еще раз. Все просто. Приступим к реализации алгоритма.

Чтобы сгенерировать числа мы воспользуемся функцией rand(), генерирующей случайное целое число в заданном диапазоне. Над кодом формы откроем конструкцию PHP и приступим к кодированию:

Итак, в переменных $a и $b у нас теперь есть случайные числа от 1 до 10. Кроме того, мы открыли сессию функцией session_start(). Думаю, Вы догадались для чего нам это нужно. Мы ведь должны где-то хранить результат сложения двух чисел после отправки данных из формы в обработчик, а проще всего сделать это используя механизм сессий. Создадим сессионную переменную и присвоим ей результат математической операции — у меня это будет сложение:

Отлично!

Осталось вывести для пользователя сгенерированные числа в нужном месте формы:

Теперь мы можем сделать промежуточное тестирование уже написанного. Для этого после старта сессии напишем следующий код:

Что означают эти строки кода?

Прежде всего, первым условием мы проверяем существует ли элемент submit в глобальном массиве POST. Это делается для того, чтобы проверить была ли нажата кнопка формы — кнопка имеет имя submit, потому-то мы и проверяем именно наличие этого элемента в POST-данных. Итак, если была нажата кнопка, то будет выполняться код в операторных скобках, иначе — этот код будет пропускаться. Ну а в операторных скобках мы также задали условие. Этим условием мы, собственно, и сравниваем то, что получили от пользователя, с тем, что у нас хранится в сессионной переменной $_SESSION[‘res’]. Если оба значения совпадают — проверка пройдена и будет выведено "OK", иначе — проверка на человечность не пройдена.

Собственно, капча уже готова. Осталось только написать необходимый нам код для обоих случаев (пройдена/не пройдена проверка). Давайте напишем простенький код для отправки данных из первого текстового поля на почтовый адрес. Мы не будем усложнять контактную форму несколькими полями, не будем добавлять дополнительные проверки (например, на обязательное заполнение полей) и прочее, поскольку это не является целью данного урока. Если же Вы хотите узнать как написать полноценную форму обратной связи — рекомендую Вам посмотреть мой цикл уроков (2 урока около 4 часов) по созданию полноценной формы обратной связи.

Итак, для начала мы напишем код для блока иначе (else), который срабатывает в том случае, если проверка не пройдена. Что нам нужно сделать в этом случае? Нужно сгенерировать 2 новых числа и сообщить пользователю, что он не прошел проверку. Для всего этого нам понадобится полностью перегрузить страницу — в этом нам поможет функция header() — и создать новую сессионную переменную, в которую будем записывать сообщения для пользователя об успехе или неудаче.

Код прост:

Теперь осталось вывести значение переменной $_SESSION[‘mes’] в нужном месте, например, под формой. Также мы должны сразу же разрегистрировать эту сессионную переменную, поскольку ее значение должно выводиться только 1 раз и после обновления страницы ее быть не должно.

Под формой напишем код:

Теперь при тестировании написанного, если мы неверно ответим на проверочное выражение, то будет выведено сообщение "Дан неверный ответ!", т.е. сработает, как и должно, блок иначе. Если ответ будет верен — сработает блок условие, но, так как он пока что пуст — ничего выводиться не будет. Теперь займемся отправкой письма в блоке условия.

3. Реализуем капчу с математическим выражением

Письмо формируется при помощи функции mail(), а затем его отправляет почтовый сервер. Данная функция имеет 3 обязательных аргумента:

    1. $to — адрес e-mail;

    2. $subject — тема сообщения;

    3. $body — тело сообщения.

Также есть еще один необязательный, но крайне желательный аргумент, в котором можно указать дополнительнвый служебные данные, к примеру, кодировку, в которой почтовой программе необходимо открывать письмо (иначе письмо будет открыто в кодировке, установленной по умолчанию для почтовой программы).

Создадим 4 переменные и функцией mail() сформируем письмо уже готовое для отправки:

Немного поясним код.

В переменной $to указываем e-mail, на который должно уходить сообщение. В переменную $body помещаем текст, полученный от пользователя из формы. В переменной $headers указываем тип письма (обычный текст) и кодировку (кириллица (Windows)) — я указываю именно эту кодировку, поскольку тестирую скрипт на Денвере, который по умолчанию имеет такую кодировку.

Далее задаем условие, в котором формируем письмо. Если все будет отработано (функция mail() вернет TRUE) — в сессионную переменную $_SESSION[‘mes’] поместим сообщение об успехе и сделаем редирект для обновления страницы. Иначе — помещаем сообщение об ошибке и также производим редирект. Теперь можно протестировать работу формы с написанной нами капчей. Если Вы также тестируете на Денвере, то все сформированные письма можно найти по адресу: Буква локального диска:\tmp\!sendmail. Так как на Денвере установлена заглушка — письма не отправляются, а складываются именно в этот каталог. Если же Вы тестируете скрипт в сети — письмо будет отправлено на указанный в переменной $to e-mail.

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

4. Реализуем капчу вопрос-ответ

В этой капче у нас будет база вопросов и ответов на них (вопросов может быть сколь угодно много). Пользователю будет предложено ответить на случайно выбранный вопрос. Ну а дальше все идет по тому же алгоритму, что и в предыдущей капче. Таким образом, наша задача создать базу вопросов-ответов и случайным образом выбрать вопрос. При этом в сессионную переменную необходимо записать ответ на этот вопрос, чтобы затем сравнить его с ответом пользователя.

Для наших целей создадим новый файл (например, index2.php), в который скопируем код из предыдущего файла. Внесем минимальные правки в созданный файл: изменим везде редирект на текущий файл (index2.php) и удалим строки с генерированием чисел и записью результата сложения в сессионную переменную.

Теперь создадим базу вопросов-ответов. Хранить их можно, например, в БД, в текстовом файле или любом удобном хранилище информации. Выберем для этих целей массив. Массив будет многомерным — каждый элемент созданного массива будет также массивом, элементами которого, в свою очередь, будет вопрос и ответ. На месте генерирования чисел создаем массив с необходимыми данными — у меня будет 3 пары вопрос-ответ (Вы можете сделать таких пар гораздо больше — все ограничено лишь Вашей фантазией). Обращаю внимание на то, что все ответы должны быть записаны в нижнем регистре:

Теперь для того, чтобы вывести на экран, допустим, вопрос "Царь зверей" — нам достаточно обратиться к массиву $question таким образом:

То есть мы обращаемся вначале к элементу с ключем 1 — это массив с нужным вопросом -, а затем к вопросу, который имеет ключ 0. Обратим внимание, что все вопросы во вложенных массивах имеют одинаковый ключ — 0, а все ответы — 1. Таким образом, для случайного выбора вопроса достаточно сгенерировать первый ключ (в нашем случае это будет число от 0 до 2). Для этого создадим переменную $key и в нее поместим сгенерированное число в заданном диапазоне — это и будет первый ключ:

Здесь мы указали, как и положено, два параметра для функции rand(). С минимумом понятно — это ноль (нумерация элементов массива по умолчанию начинается с нуля). Второй параметр можно было указать явно — 2. Но тогда наш скрипт немного потерял бы в универсальности — ведь если изменится количество вопросов, то придется менять и максимум в функции. Чтобы количество вопросов считалось автоматически, воспользуемся функцией count() — она считает количество элементов массива. В нашем случае функция вернет 3 (3 элемента в массиве). Но последний вопрос имеет ключ 2, а потому мы отнимем от результата, который вернет функция count() единицу и получим нужный результат.

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

Теперь выведем выбранный вопрос в нужном месте формы:

Собственно, вторая капча уже практически готова и можно ее уже протестировать. Осталось дописать пару небольших мелочей. Помним, что важно было писать все ответы в нижнем регистре. Это сделано неспроста — мы ведь не знаем, в каком именно виде получим от пользователя ответ, скажем на вопрос "Название нашей планеты"… это может быть такой ответ — "Земля", а может быть и такой — "Земля". Эти ответы не идентичны. Соответственно, мы должны сделать их идентичными для скрипта. А сделать это совсем несложно. Достаточно привести ответ пользователя к нижнему регистру, в чем нам поможет функция strtolower(). Также, на всякий случай, можно обрезать пробелы с обоих концов полученной от пользователя строки (делается это на случай, если пользователь случайно ввел вместе с ответом пробел). Обрезать пробелы с начала и конца строки поможет функция trim(). Внесем соответствующие изменения в строку кода, где проверяется совпадение полученного от пользователя с тем, что есть у нас:

Заключение

Вот и все. Обе наши капчи реализованы и готовы к использованию на сайте и, как уже отмечалось, на мой взгляд, эти капчи гораздо эффективнее традиционной капчи. На этом наш урок завершен. Удачи в Ваших проектах и до новых встреч!

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии (68)