Диагностика проблемы: почему повторные голоса вредят опросам
Повторные голоса и накрутки искажают результаты опросов, делают аналитику недостоверной. Часто встроенные механизмы плагинов опросов не гарантируют 100% защиту от повторного голосования, особенно если база данных не должна модифицироваться (например, на хостингах с ограничениями или при использовании сторонних сервисов хранения).
Основные признаки проблемы:
- В опросах появляются голоса с одного IP или с одного аккаунта/браузера более одного раза.
- Отсутствует ограничение по времени между голосованиями.
- Пользователи жалуются, что могут голосовать повторно.
Пошаговое решение: защита на уровне кук и проверки IP
1. Установка куки с отметкой о голосовании
При успешном голосовании в опросе устанавливаем cookie с уникальным идентификатором опроса. При попытке повторного голосования проверяем наличие этой куки. Такой подход прост и не требует изменений в базу.
function wppolls_set_vote_cookie($poll_id) {
setcookie('wppolls_voted_' . $poll_id, '1', time() + 365 * DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
}
// Хук, срабатывающий после голосования
add_action('wppolls_after_vote', 'wppolls_set_vote_cookie', 10, 1);2. Проверка наличия куки перед голосованием
Перед добавлением голоса проверяем, есть ли куки. Если есть — блокируем голос.
function wppolls_block_repeat_vote() {
if ( isset($_POST['poll_id']) ) {
$poll_id = intval($_POST['poll_id']);
if ( isset($_COOKIE['wppolls_voted_' . $poll_id]) ) {
wp_send_json_error(array('message' => 'Вы уже голосовали в этом опросе.'));
wp_die();
}
}
}
add_action('wp_ajax_wppolls_vote', 'wppolls_block_repeat_vote', 1);
add_action('wp_ajax_nopriv_wppolls_vote', 'wppolls_block_repeat_vote', 1);3. Проверка IP-адреса по сессии
Для дополнительной защиты можно хранить IP в сессии или transient, чтобы не использовать базу данных.
function wppolls_check_ip_before_vote($poll_id) {
if (!session_id()) session_start();
$user_ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SESSION['wppolls_ips'][$poll_id]) && $_SESSION['wppolls_ips'][$poll_id] === $user_ip) {
wp_send_json_error(array('message' => 'Вы уже голосовали с этого IP.'));
wp_die();
}
}
function wppolls_save_ip_after_vote($poll_id) {
if (!session_id()) session_start();
$user_ip = $_SERVER['REMOTE_ADDR'];
$_SESSION['wppolls_ips'][$poll_id] = $user_ip;
}
add_action('wp_ajax_wppolls_vote', function() {
if ( isset($_POST['poll_id']) ) {
wppolls_check_ip_before_vote(intval($_POST['poll_id']));
}
}, 0);
add_action('wppolls_after_vote', 'wppolls_save_ip_after_vote', 10, 1);Проверка результата после внедрения
Для проверки корректности решения:
- Откройте опрос в браузере в режиме инкогнито, голосуйте — голос должен пройти.
- Обновите страницу и попробуйте проголосовать повторно — должно появиться сообщение об ошибке.
- Проверьте, что в куках браузера появилась
wppolls_voted_[poll_id]. - Повторите голосование с другого браузера или с другого IP (например, через VPN) — голос должен пройти.
Частые ошибки и как их исправить
- Куки не устанавливаются: проверьте, что
setcookie()вызывается до вывода контента. Иначе куки не сохранятся. - JavaScript плагина не учитывает блокировку: дополнительно нужно модифицировать JS плагина, чтобы он корректно обрабатывал ошибки сервера и показывал сообщения.
- Пользователь чистит куки: в таком случае IP-проверка помогает ограничить повторные голоса.
- Сессии не работают: убедитесь, что сессии PHP включены и не конфликтуют с другими плагинами.
Практические советы по безопасности и производительности
- Не храните IP пользователей в базе данных без согласия — используйте сессии или transient с ограниченным сроком.
- Комбинируйте несколько методов (куки, IP, сессии) для лучшей защиты.
- Для критичных опросов рассмотрите CAPTCHA или авторизацию перед голосованием.
- Обрабатывайте ошибки AJAX-запросов на стороне клиента, чтобы улучшить UX.
Сравнение вариантов защиты от повторных голосов
| Метод | Изменения в базе | Надежность | Производительность | Сложность |
|---|---|---|---|---|
| Куки | Нет | Средняя (куки можно чистить) | Высокая | Низкая |
| IP в сессии | Нет | Выше (но IP может меняться) | Высокая | Средняя |
| Хранение IP в базе | Да (изменение структуры) | Высокая | Средняя | Высокая |
| Авторизация пользователей | Нет | Очень высокая | Средняя | Средняя |