После того, как очередной плагин по устранению спама в формах Contact Form 7 перестал справляться со своей задачей, я был вынужден изучить этот вопрос более подробно.
Вывод такой: большинство способов защиты Contact Form 7 от спама сводятся к установке CAPTCHA или сторонних сервисов. Но мне оказался ближе более простой подход — Time-Check. Его идея заключается в проверке времени, прошедшего между загрузкой страницы и отправкой формы. Метод практически не влияет на пользователей, совместим с кэшированием страниц и позволяет отсечь значительную часть простых спам-ботов без использования CAPTCHA.
Time-Check
План прост:
- В форме есть скрытое поле
- Имя этого поле не так важно, но в моем случае — это form_loaded
- Через JS мы записываем в это поле текущее время, если форма отправлена слишком быстро или слишком поздно — отправка блокируется
- Потом в PHP обработчике мы окончательно проверяем данное поле на заполненность и также проверяем на слишком быструю или позднюю отправку
Звучит слишком просто для антиспам защиты, но главное работает.
Код
В контактную формы вставляем скрытое поле:
[hidden form_loaded id:form_loaded]В JS пишем Time-Check на стороне клиента:
(function () {
const MIN_TIME = 5; // минимальное время заполнения (сек)
const MAX_TIME = 86400; // 24 часа
function setTimestamp() {
const fields = document.querySelectorAll('input[name="form_loaded"]');
fields.forEach((field) => {
field.value = Math.floor(Date.now() / 1000);
});
}
function bindValidation() {
document.addEventListener('submit', function (e) {
const form = e.target;
if (!form.classList.contains('wpcf7-form')) {
return;
}
const field = form.querySelector('input[name="form_loaded"]');
if (!field || !field.value) {
e.preventDefault();
return;
}
const now = Math.floor(Date.now() / 1000);
const diff = now - parseInt(field.value, 10);
// слишком быстро (бот)
if (diff < MIN_TIME) {
e.preventDefault();
return;
}
// слишком старая форма
if (diff > MAX_TIME) {
e.preventDefault();
return;
}
});
}
document.addEventListener('DOMContentLoaded', function () {
setTimestamp();
bindValidation();
});
})();В functions.php уже записываем серверную часть проверки Time-Check:
add_filter(
'wpcf7_validate',
function ( $result ) {
$timestamp = isset( $_POST['form_loaded'] )
? (int) $_POST['form_loaded']
: 0;
if ( ! $timestamp ) {
$result->invalidate( '', 'Spam detected.' );
return $result;
}
$diff = time() - $timestamp;
if ( $diff < 5 ) {
$result->invalidate( '', 'Spam detected.' );
return $result;
}
if ( $diff > DAY_IN_SECONDS ) {
$result->invalidate( '', 'Form expired.' );
}
return $result;
},
20,
1
);