From f7a4edbac35d61bd83b65c03848ddbd1ffe28f67 Mon Sep 17 00:00:00 2001 From: Repellent Date: Sat, 20 Dec 2025 23:53:48 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=B3=D0=BE=D0=BB=D0=BE?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20=D1=81=D0=B2=D1=8F=D0=B7=D0=BA=D0=BE?= =?UTF-8?q?=D0=B9=20=D0=B8=D0=BC=D1=8F+IP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- class/comment.php | 70 ++++++++++++++++++++++++++++++++++------------- sql.php | 20 ++++++++++---- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/class/comment.php b/class/comment.php index 7c8d270..c76ab9e 100644 --- a/class/comment.php +++ b/class/comment.php @@ -779,16 +779,21 @@ function commentPostDelete($comment_id) /** * Метод для обработки голосования за комментарий + * Защита: ID для залогиненных, Пара (Ключ + IP) для анонимов. */ function commentVote() { global $AVE_DB; + // Принимаем данные $comment_id = (int)($_POST['comment_id'] ?? 0); $vote_value = (int)($_POST['vote'] ?? 0); $ajax = (isset($_POST['ajax']) && $_POST['ajax'] == 1); + + // IP пользователя + $user_ip = $_SERVER['REMOTE_ADDR'] ?? ''; - // Базовая проверка значения (от 1 до 5 звезд) + // Базовая валидация if ($comment_id <= 0 || $vote_value < 1 || $vote_value > 5) { if ($ajax) { if (ob_get_length()) ob_end_clean(); @@ -798,18 +803,18 @@ function commentPostDelete($comment_id) return; } - // 1. Идентификация пользователя + // 1. Идентификация текущего голосующего $user_id = empty($_SESSION['user_id']) ? 0 : (int)$_SESSION['user_id']; $anon_key = $this->_getAnonKey(); - // 2. Получаем данные о комментарии (FetchRow исправлен) - $comment_data = $AVE_DB->Query(" - SELECT comment_author_id, anon_key + // 2. Получаем данные о комментарии, за который голосуют + $comment_row = $AVE_DB->Query(" + SELECT comment_author_id, anon_key, comment_author_ip FROM " . PREFIX . "_module_comment_info WHERE Id = '" . $comment_id . "' ")->FetchRow(); - if (!$comment_data) { + if (!$comment_row) { if ($ajax) { if (ob_get_length()) ob_end_clean(); echo 'error'; @@ -818,10 +823,25 @@ function commentPostDelete($comment_id) return; } - // 3. Запрет голосовать за свой же комментарий + $c_author_id = (int)$comment_row->comment_author_id; + + // 3. ПРОВЕРКА АВТОРСТВА (Запрет голосовать за свой же комментарий) $is_author = false; - if ($user_id > 0 && $user_id == $comment_data->comment_author_id) $is_author = true; - if ($user_id == 0 && $anon_key == $comment_data->anon_key) $is_author = true; + + if ($user_id > 0) { + // Если залогинен — проверяем только по ID + if ($user_id === $c_author_id) { + $is_author = true; + } + } else { + // Если аноним — проверяем парой (Ключ + IP) + // И только если автор комментария тоже был анонимом + if ($c_author_id === 0 && + $anon_key === $comment_row->anon_key && + $user_ip === $comment_row->comment_author_ip) { + $is_author = true; + } + } if ($is_author) { if ($ajax) { @@ -832,12 +852,19 @@ function commentPostDelete($comment_id) return; } - // 4. Проверка на повторное голосование - $sql_check = "SELECT id FROM " . PREFIX . "_module_comment_votes WHERE comment_id = '" . $comment_id . "' AND "; + // 4. ПРОВЕРКА ПОВТОРНОГО ГОЛОСОВАНИЯ + // Ищем в истории, голосовал ли уже этот человек if ($user_id > 0) { - $sql_check .= "user_id = '" . $user_id . "'"; + // Для авторизованных поиск по ID + $sql_check = "SELECT id FROM " . PREFIX . "_module_comment_votes + WHERE comment_id = '" . $comment_id . "' + AND user_id = '" . $user_id . "'"; } else { - $sql_check .= "anon_key = '" . $anon_key . "'"; + // Для анонимов поиск по связке Ключ + IP + $sql_check = "SELECT id FROM " . PREFIX . "_module_comment_votes + WHERE comment_id = '" . $comment_id . "' + AND anon_key = '" . $anon_key . "' + AND remote_addr = '" . $user_ip . "'"; } if ($AVE_DB->Query($sql_check)->GetCell()) { @@ -849,15 +876,20 @@ function commentPostDelete($comment_id) return; } - // 5. Записываем голос в лог + // 5. ЗАПИСЬ ГОЛОСА В ЛОГ $AVE_DB->Query(" INSERT INTO " . PREFIX . "_module_comment_votes - (comment_id, user_id, anon_key, vote_value, date_voted) + (comment_id, user_id, anon_key, remote_addr, vote_value, date_voted) VALUES - ('" . $comment_id . "', '" . $user_id . "', '" . $anon_key . "', '" . $vote_value . "', '" . time() . "') + ('" . $comment_id . "', + '" . $user_id . "', + '" . $AVE_DB->escape($anon_key) . "', + '" . $AVE_DB->escape($user_ip) . "', + '" . $vote_value . "', + '" . time() . "') "); - // 6. Обновляем агрегированные данные + // 6. ОБНОВЛЕНИЕ АГРЕГАТОВ В ТАБЛИЦЕ INFO $AVE_DB->Query(" UPDATE " . PREFIX . "_module_comment_info SET rating_sum = rating_sum + " . $vote_value . ", @@ -865,9 +897,9 @@ function commentPostDelete($comment_id) WHERE Id = '" . $comment_id . "' "); - // 7. ФИНАЛ: Очищаем мусор и отдаем чистый ответ + // 7. ФИНАЛ: Чистый ответ для JS if ($ajax) { - if (ob_get_length()) ob_end_clean(); // Выбрасываем все Warning-и и HTML + if (ob_get_length()) ob_end_clean(); echo 'success'; exit; } diff --git a/sql.php b/sql.php index 1083092..f509ea4 100644 --- a/sql.php +++ b/sql.php @@ -4,7 +4,7 @@ * AVE.cms - Модуль Комментарии * * Обновленная структура с поддержкой рейтинга (звезд), - * идентификации анонимных пользователей и загрузки файлов. + * идентификации анонимных пользователей, загрузки файлов и защиты по IP. */ $module_sql_install = array(); @@ -48,7 +48,7 @@ $module_sql_install[] = "CREATE TABLE `%%PRFX%%_module_comment_info` ( `comment_author_email` varchar(255) NOT NULL, `comment_author_city` varchar(255) NOT NULL, `comment_author_website` varchar(255) NOT NULL, - `comment_author_ip` varchar(15) NOT NULL, + `comment_author_ip` varchar(45) NOT NULL, /* Увеличено для поддержки IPv6 */ `anon_key` varchar(32) DEFAULT NULL, `comment_published` int(10) unsigned NOT NULL default '0', `comment_changed` int(10) unsigned NOT NULL default '0', @@ -66,18 +66,20 @@ $module_sql_install[] = "CREATE TABLE `%%PRFX%%_module_comment_info` ( KEY `anon_key` (`anon_key`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;"; -// Таблица для хранения истории голосов (защита от повторов) +// Таблица для хранения истории голосов (Добавлено поле remote_addr для защиты по IP) $module_sql_install[] = "CREATE TABLE `%%PRFX%%_module_comment_votes` ( `id` int(10) unsigned NOT NULL auto_increment, `comment_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned DEFAULT '0', `anon_key` varchar(32) DEFAULT '', + `remote_addr` varchar(45) DEFAULT '', /* Поле для хранения IP проголосовавшего */ `vote_value` tinyint(1) NOT NULL, `date_voted` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `comment_id` (`comment_id`), KEY `anon_key` (`anon_key`), - KEY `user_id` (`user_id`) + KEY `user_id` (`user_id`), + KEY `remote_addr` (`remote_addr`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"; $module_sql_install[] = "INSERT INTO `%%PRFX%%_module_comments` VALUES (1, 1000, '1,3', '1,2,3,4', '0', '1', '1' , '0', '', 1, 0, '', 1, 0, '', 0, 2048);"; @@ -99,19 +101,25 @@ $module_sql_update[] = " // Добавляем поля рейтинга в существующую таблицу $module_sql_update[] = "ALTER TABLE `%%PRFX%%_module_comment_info` ADD `rating_sum` INT(10) NOT NULL DEFAULT '0';"; $module_sql_update[] = "ALTER TABLE `%%PRFX%%_module_comment_info` ADD `rating_count` INT(10) NOT NULL DEFAULT '0';"; +$module_sql_update[] = "ALTER TABLE `%%PRFX%%_module_comment_info` MODIFY `comment_author_ip` VARCHAR(45) NOT NULL;"; -// Создаем таблицу голосов, если её еще нет +// Создаем таблицу голосов с полем IP, если её еще нет $module_sql_update[] = "CREATE TABLE IF NOT EXISTS `%%PRFX%%_module_comment_votes` ( `id` int(10) unsigned NOT NULL auto_increment, `comment_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned DEFAULT '0', `anon_key` varchar(32) DEFAULT '', + `remote_addr` varchar(45) DEFAULT '', `vote_value` tinyint(1) NOT NULL, `date_voted` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `comment_id` (`comment_id`), KEY `anon_key` (`anon_key`), - KEY `user_id` (`user_id`) + KEY `user_id` (`user_id`), + KEY `remote_addr` (`remote_addr`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"; +// Если таблица уже была, но поля remote_addr в ней нет — добавляем его +$module_sql_update[] = "ALTER TABLE `%%PRFX%%_module_comment_votes` ADD COLUMN IF NOT EXISTS `remote_addr` VARCHAR(45) DEFAULT '' AFTER `anon_key`;"; + ?> \ No newline at end of file