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

14

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

У цьому уроці ми навчимося писати власну капчу, навіть у двох варіантах, яка буде не надто складною, зручною для користувача і, разом з тим, досить ефективною.

План уроку:

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

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

3. Реалізуємо капчу з математичним виразом (12:03)

4. Реалізуємо капчу питання-відповідь (17:49)

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

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() — і створити нову сесійний змінну, в яку будемо записувати повідомлення для користувача про успіх чи невдачу.

Код простий:

Дано неправильну відповідь!

‘;
header(«Location: index.php»);
exit();
}
}
$a = rand(1,10);
$b = rand(1,10);
$_SESSION[‘res’] = $a + $b;
?>

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

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

Тепер при тестуванні написаного, якщо ми неправильно відповімо на перевірочне вираз, то буде виведено повідомлення «Дано неправильну відповідь!», тобто спрацює, як і повинно, блок інакше. Якщо відповідь вірний, — спрацює блок умова, але, так як він поки що порожній, нічого виводитися не буде. Тепер займемося відправкою листа в блоці умови.

3. Реалізуємо капчу з математичним виразом

Лист формується за допомогою функції mail(), а потім його відправляє поштовий сервер. Дана функція має 3 обов’язкових аргументу:

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

2. $subject — тема повідомлення;

3. $body — тіло повідомлення.

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

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

Лист відправлено!

‘;
header(«Location: index.php»);
exit();
}else{
$_SESSION[‘mes’] = ‘

Помилка!

‘;
header(«Location: index.php»);
exit();
}
}else{
$_SESSION[‘mes’] = ‘

Дано неправильну відповідь!

‘;
header(«Location: index.php»);
exit();
}
}
$a = rand(1,10);
$b = rand(1,10);
$_SESSION[‘res’] = $a + $b;
?>

Трохи пояснимо код.

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

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

Таким чином, перша капча нами реалізована. Тепер приступимо до реалізації другої.

4. Реалізуємо капчу питання-відповідь

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

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

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

$question = array(array(0 => ‘Назва нашої планети’,
1 => ‘земля’),
array(0 => ‘Цар звірів’,
1 => ‘лев’),
array(0 => ‘Адам і…’,
1 => ‘ева’));

Тепер для того, щоб вивести на екран, припустимо, питання «Цар звірів» — нам достатньо звернутися до масиву $question таким чином:

echo $question[1][0];

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

$key = rand(0,count($question)-1); // ключ

Тут ми вказали, як і годиться, два параметра для функції rand(). З мінімумом зрозуміло — це нуль (нумерація елементів масиву починається з нуля). Другий параметр можна було вказати явно — 2. Але тоді наш скрипт трохи втратив би в універсальності — адже якщо зміниться кількість питань, то доведеться міняти і максимум функції. Щоб кількість запитань вважалося автоматично, скористаємося функцією count() — вона вважає кількість елементів масиву. У нашому випадку функція поверне 3 (3 елемента в масиві). Але останнє питання має ключ 2, а тому ми віднімемо від результату, який поверне функція count() одиницю і отримаємо потрібний результат.

Залишилося запам’ятати відповідний обраному питанню відповідь. Перший ключ у нас є, а другий завжди дорівнює 1 для відповідей:

$key = rand(0,count($question)-1); // ключ
$_SESSION[‘res’] = $question[$key][1]; // відповідь

Тепер виведемо вибраний питання в потрібному місці форми:

Власне, друга капча вже практично готова і можна її вже протестувати. Залишилося дописати пару невеликих дрібниць. Пам’ятаємо, що важливо було писати всі відповіді в нижньому регістрі. Це зроблено неспроста — адже ми не знаємо, в якому саме вигляді отримаємо від користувача відповідь, скажімо, на запитання «Назва нашої планети»… це може бути така відповідь — «Земля», а може бути і такий — «Земля». Ці відповіді не ідентичні. Відповідно, ми повинні зробити їх ідентичними для скрипта. А зробити це зовсім нескладно. Досить навести відповідь користувача до нижнього регістра, в чому нам допоможе функція strtolower(). Також, на всяк випадок, можна обрізати прогалини з обох кінців отриманої від користувача рядка (робиться це на випадок, якщо користувач випадково ввів разом з відповіддю пробіл). Обрізати пробіли з початку і кінця рядка допоможе функція trim(). Внесемо відповідні зміни в рядок коду, де перевіряється збіг отриманого від користувача з тим, що є у нас:

if(strtolower(trim($_POST[‘res’])) == $_SESSION[‘res’])

Висновок

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