Василь, когда в исследованиях по нейронной схемотехнике лет 12 назад я показал пример, как простая схема на паре десятков нейрочипов вполне сносно распознаёт цифры с bitmap-картинки всего за несколько тактов обучения, тогда уже было понятно, что подобные идеи будут востребованы ботами, а изменение алгоритма рендеринга капчи подействует лишь до момента, пока оператор не покажет схеме как выглядят цифры в новой графике.
Так что написание иного алгоритма капчи в методе, который вы правильно назвали, оставим до лучших времён. Тем более что вся ваша работа затрётся очередным обновлением движка. Вместо этого существует способ, как навесить свою капча-логику на существующую обратную связь, вообще не влезая в файлы движка.
Как проходит запрос
Давайте вспомним порядок запуска компонентов Имперы во время обычного запроса страницы:
-
первым делом запрос проходит через корневой .htaccess, где с помощью mod_Rewrite-правил происходит первичная маршрутизация для некоторых БАЗОВЫХ написаний URL-ов
- все адреса маршрутизируются в единую стартовую точку - корневой файл index.php
-
базовые адреса тут же снабжаются GET-параметром module, где уже прописано имя связанного базового модуля
- тут записаны схемы базовых адресов
- если в запросе тоже имеется GET-параметр module, он имеет приоритет перед назначением базового
- остальные снабжаются GET-параметром special_url, перекладывая определение модуля на компонент клиентской страницы
- второй шаг состоит в исполнении index.php - той самой единой стартовой точки
-
третьим шагом происходит загрузка дефолтной модели "Клиентская Страница" - это упоминавшийся выше компонент клиентской страницы, в движке он представлен файлом objects/.def-models/ClientPage.php
- вот тут и происходит запуск хелпера - это файл helper.php, если такой присутствует в текущем шаблоне
- затем для небазовых адресов происходит определение связанного модуля (напомню, в случае базовых адресов - модуль уже известен)
-
затем выполняется загрузка модуля, если такой существует и не выключен в админпанели
-
если ещё в админке для такой страницы в поле Плагины: был прописан через запятую список подключаемых модулёчков, они подключаются подобно загрузке основного модуля в том же порядке как перечислены
- то есть каждый плагин загружается только при его наличии и включенности
- результирующий контент работы всякого плагина сохраняется в переменной $plugin_имяплагина, чтобы этот контент мог быть вывеен основным модулем, если потребуется
- концепция плагина позволяет ему вместе с контентом вернуть ещё и сигнал FALSE, что расценивается как немедленное требование прекратить генерацию страницы, а ответом считать контент плагина + отправить код "Ошибка 404"
- четвёртый шаг передаёт управление загруженному модулю, чтобы тот подготовил контент центральной части страницы на основе tpl-файла, соответствующего этому модулю
-
пятым шагом полученный контент центра страницы оборачивается в общий макет страницы - это файл index.tpl шаблона
- оборачивание в общий макет отменяется для ajax-запросов и модулей, которые заявляют об этом специальным сигналом
- теперь результат отправляется в браузер пользователя
Таким образом уже на шаге 3, а именно когда запускается хелпер шаблона, нам доступно вклиниться в контроль параметров формы, прежде чем они дойдут до модуля обратной связи. Предполагая что вас атакуют спам-боты, работающие по предварительно сохранённому оттиску формы, мы можем сломать им оттиск тем, что всякий раз станем добавлять в форму случайный параметр, а на стороне хелпера шаблона будем проверять наличие такого параметра и отфутболивать любой пост без него.
Серверная сторона
Сначала добавим защитный код в хелпер шаблона вот так:
<?php
class TemplateEmulator {
...
public function __construct ( & $cms ) {
$this->antispam($cms);
...
}
private function antispam ( & $cms ) {
$param = 'antispamFeedbackName';
if ($cms->request->existsPost('feedback_message')) {
$value = $cms->session->get($param);
$test = $cms->request->getPost($param);
if ($test === FALSE || $test !== $value) {
$_POST['captcha'] = '';
$_REQUEST['captcha'] = '';
}
}
$value = md5(uniqid());
$cms->session->set($param, $value);
$cms->smarty->assignByRef($param, $value);
}
...
}
?>
Принцип действия: если видим какой-то параметр, характерный для постинга формы обратной связи (например в POST-е присутствует поле feedback_message), тогда убеждаемся что там есть ещё и наш выдуманный параметр. В противном случае тут же портим какой-нибудь элемент POST-а, чтобы стартуемый за нами модуль обратной связи по-любому вернул пост на исправление ошибок ("вы не ввели капчу").
Клиентская сторона
Теперь добавим несколько строчек скрипта в конце файла index.tpl шаблона вот так:
<html>
...
<body>
...
<script>
$('input[name="feedback_message"]').each(function () {
var el = '<input name="{$antispamFeedbackName}" type="hidden">';
$(this).closest('form').append(el);
});
</script>
</body>
</html>
Если же ваш сайт построен по технологии NO-jQuery, вот альтернативный скрипт:
<html>
...
<body>
...
<script>
(function () {
var i, inp, el,
items = document.getElementsByName('feedback_message');
for (i = 0; i <= items.length; i++) {
el = items[i];
while (el && 'parentNode' in el) {
el = el.parentNode;
if (el.tagName == 'FORM') {
inp = document.createElement('input');
inp.setAttribute('type', 'hidden');
inp.setAttribute('name', '{$antispamFeedbackName}');
el.appendChild(inp);
break;
}
}
}
}) ();
</script>
</body>
</html>
Оба скрипта выполняют то же действие со стороны браузера: найти в полученном с сервера документе все объекты с именем feedback_message и добавить в их родителськие формы скрытое поле с именем, содержащимся сейчас в переменной $antispamFeedbackName.
Такая защита моментально ограждает от автоматических ботов, даже если всякий раз те начнут снимать новый оттиск формы. Ведь кроме оттиска надо парсить ещё и яваскрипт в поисках нашего внедрения (но и его в принципе можем обфусцировать), чтобы установить, какой параметр собираются "на лету" добавить в форму. Кстати, эта защита бесполезна против ботов с эмулятором яваскрипта.