Пишем текстовую капчу на PHP и Javascript
Капча должна быть не сложнее, чем в этом блоге (текстовая строка, размеченная выбранными тегами), но при этом обладать следующими свойствами:
- нигде не передаваться открыто в данных HTTP;
- нигде не храниться в незашифрованном виде (в массиве
$_SESSION
будет находиться только зашифрованная капча); - быть по возможности защищённой от ботов, с этой целью раздел документа, содержащий капчу (а в реальном приложении - всю форму ввода, для которой понадобилась капча) будет заполняться данными только после полной загрузки страницы, встраиваясь в цепочку обработчиков события
load
.
Для работы капчи понадобятся включённые в браузере Javascript и Cookies.
Вот описание порядка действий и основных функций:
- если данные формы были отправлены (в данных
$_POST
есть ключ'ok'
, соответствующий кнопке типаsubmit
), из массива сессии получается зашифрованный код$valid
и сравнивается с тут же зашифрованным числом$code
, полученным от пользователя из текстового поля ввода. Если строки совпадают, выводится сообщение'ok'
, на самом деле, в этой ветке программы могут выполняться любые нужные нам действия. Если строки не совпадают, выводится'no'
и работа скрипта продолжается, то есть, повторно генерируется новая форма ввода; - в список слушателей события
load
страницы встраивается маленькая безымянная яваскрипт-функция, добавляющая в раздел документа сid="sform"
код формы с капчей. Этот код формируется и возвращается PHP-функциейcommentform
. Для удобства и во избежание проблем с "многострочной" строкой внутри яваскрипта, все разделители в сгенерированном коде формы заменяются на пробелы (функцияtrim1
), так что код формы оказывается вытянутым в одну строку; - для непосредственной генерации числа-капчи функция
commentform
обращается к функцииgenerate_code
, которая формирует случайное 4-значное число, шифрует его и сохраняет в данных сессии (значение$valid
), а также возвращает видимый код формы$str
, содержащий, в том числе, видимую часть капчи, полученную функциейvisible_code
. Эта последняя функция просто "зашумляет" строку-аргумент тегами, разрешёнными к использованию с помощью массива$tags
.
Как и в любых скриптах, работающих с данными сессии, до вывода любой разметки должна быть вызвана стандартная функция session_start
. Вот полный код скрипта-примера, его можно выполнить как файл .php
на локальном хосте, например, в Denwer. Проверено на PHP 5.5.9.
<?php session_start(); ?> <div id="sform"></div> <?php if (isset($_POST['ok'])) { $valid=''; if (isset($_SESSION['valid'])) $valid=$_SESSION['valid']; $code = strval(intval($_POST['code'])-1000); if (md5($code) == $valid) { echo '<b>ok</b>'; //любые действия, выполняемые при правильном вводе exit; } else { echo '<b>no</b>'; //при ошибке выводится no и работа скрипта продолжается } } function visible_code ($s) { $tags = Array ( Array ('<span>','</span>'), Array ( '<b>','</b>'), Array ( '<i>','</i>'), Array ('<u>','</u>'), Array ('<s>','</s>'), Array ('<sub>','</sub>'), Array ('<sup>','</sup>'), Array ('<big>','</big>'), Array ('<small>','</small>') ); $len = strlen ($s); $res = ''; for ($i = 0; $i < $len; $i++) { $c = substr ($s, $i, 1); $n = rand(0, count($tags)-1); $res .= $tags[$n][0].$c.$tags[$n][1]; } return $res; } function generate_code () { srand (time()); $str = 'Введите код сообщения: '; $valid = mt_rand(1000,9999); $str .= visible_code ($valid); $_SESSION['valid'] = md5 ($valid - 1000); $str .= ' <input type="text" name="code" size="5" maxlength="4" value="">'; return $str; } function commentform () { return '<form method="post">'.generate_code(). ' <input type="submit" name="ok"></form>'; } function trim1 ($string) { return preg_replace("/\s+/"," ",trim($string)); } echo '<script> window.addEventListener("load", function() { document.getElementById("sform").innerHTML = \''.trim1(commentform()).'\'; }); </script> <noscript>Нужен включённый в Вашем браузере Javascript</noscript>'; ?>
Вот как выглядит приложение в браузере Firefox:
Текстовая капча в Firefox, скриншот
12.01.2019, 12:43 [2255 просмотров]