Капча без графики

03.02.2008г. // Рубрики: web, Perl
Капча - элемент веб-формы, препятствующий отправке данных на сервер роботами (программами). То есть, некоторая проверка на интеллект того, кто заполнил форму. Обычно капча - картинка, на которой изображены цифры (зачастую затрудненно даже человеку разглядеть их) и для продолжения своих действий пользователь должен ввести прочитанное число в поле.
Идея текстовой капчи проста - предлагается к рассмотрению слово с грамматической ошибкой, требуется исправить ошибку и ввести правильный текст.
Набор пар ошибочное слово - правильное слово я занес в таблицу БД (работаю с MySQL):
create table if not exists chkwords (
    id int unsigned not null primary key auto_increment,
    left_w varchar(24) not null,
    right_w varchar(24) not null
);
Данные в эту таблицу загоняются набором команд вида
insert into chkwords (left_w,right_w) values('интернэт', 'интернет');Самое сложное здесь - придумать набор ошибочных слов - чем больше, тем лучше :)
Вторая таблица необходима чтобы запоминанить идентификатор выставленного слова для проверки. Т.е. пользователь запросил капчу, получил ее id и по этому id будет отдавать правильный вариант ответа (точнее, пока не введет слово правильно), после чего данный идентификатор будет закрыт для использования и никогда больше не повторится.
create table if not exists usewords (
    id int unsigned not null primary key auto_increment,
    wid int unsigned not null,
    complete enum('0','1') default '0'
);
Здесь wid - ссылка на id таблицы chkwords.
Теперь сам алгоритм проверки введенного слова.
Вначале выдается слово для проверки и запоминается его идентификатор (код на языке Perl):
eval {
    $dbh -> do("lock table chkwords read, usewords write");
    ($wid,$regword) = $dbh -> selectrow_array(
        "select id, trim(left_w) from chkwords order by rand() limit 1"
    );
    $dbh -> do("insert into usewords set wid=$wid");
    ($wordno) = $dbh -> selectrow_array("select max(id) from usewords");
};
$dbh -> do('unlock tables');
После того, как пользователь заполнил капчу и подал запрос, вначале проверим, что соответственное поле complete имеет в базе значение '0':
eval {
    $dbh -> do("lock table chkwords read, usewords write");
    ($complete) = $dbh -> selectrow_array(qq~select complete
        from usewords where id=$wordno~);
    $dbh -> do("update usewords set complete='1' where id=$wordno");
};
$dbh -> do('unlock tables');
$err .= "bla-bla-bla" if $@;

if ($complete) { #+++ запись была несвободна - ошибка, на начало
    $regword ="";
    $err .= "Неправильный ввод контрольного слова. Попробуйте еще раз.... bla-bla";
    goto FIRST_STEP;
} #--- запись была несвободна - ошибка, на начало
goto FIRST_STEP if $err;
Остался заключительный этап - собственно проверка знания русского языка:
#+++ проверка корректности ввода контрольного слова
eval {
    $dbh -> do("lock table chkwords read, usewords read");
    ($right_w) = $dbh -> selectrow_array(qq~
        select trim(right_w)
        from chkwords left join usewords on chkwords.id=usewords.wid
        where usewords.id=$wordno
    ~);
};
$dbh -> do('unlock tables');
$err .= "bla-bla-bla" if $@;
goto FIRST_STEP if $err;

use locale;
use POSIX qw(locale_h);
setlocale(LC_CTYPE, "Russian_Russia.1251");
($right_w, $regword) = map {$_=lc $_; s/ё/е/g; $_} ($right_w, $regword);

$err .= "Неправильный ввод контрольного слова. Попробуйте еще раз. bla-bla"
if $right_w ne $regword;
goto FIRST_STEP if $err;

# если в результате мы дошли до этой точки, значит проверка удалась
В заключение отмечу, что вариант текстовой капчи более интеллектуален, чем графическая проверка цифр, но зато лучше отметает разных пионеров, не закончивших школу, но горящих желанием что-то написать или где-то зарегистрироваться. Разумеется, крайне желательно и вам заносить в базу правильные слова без ошибок ))
Пользуйтесь на здоровье и не забывайте выражать благодарность на мой блог примерно таким способом:
Thanks http://perlmaster.info/ :)

Рубрики