diff --git a/class/comment.php b/class/comment.php index d463cd4..4abacca 100644 --- a/class/comment.php +++ b/class/comment.php @@ -3,9 +3,11 @@ * Класс, включающий все свойства и методы для управления комментариями как в * Публичной части сайта, так и в Панели управления. * - * @package AVE.cms + * @package AVE4cms + * @author Александр Сальников (Repellent) + * @copyright 2026 * @subpackage module_Comment - * @since 1.4 + * @since 3.31 * @filesource */ class Comment @@ -109,11 +111,11 @@ class Comment /** * Конструктор класса - * Срабатывает автоматически при создании объекта Comment + * */ function __construct() { - // Как только класс создан, мы ПЕРВЫМ ДЕЛОМ лезем в базу за настройками + // Как только класс создан идем в базу за настройками $this->_commentSettingsGet(); } @@ -231,9 +233,6 @@ function _commentSettingsGet($param = '') return $comments[$document_id]; } -/** - * Внешние методы класса - */ /** * Следующие методы описывают работу модуля в Публичной части сайта. @@ -298,7 +297,7 @@ function commentListShow($tpl_dir) -if ($settings['comment_use_page_nav'] == 1) + if ($settings['comment_use_page_nav'] == 1) { $limit = (int)$settings['comment_page_nav_count']; $start = get_current_page() * $limit - $limit; @@ -307,8 +306,8 @@ if ($settings['comment_use_page_nav'] == 1) $num = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_module_comment_info WHERE document_id = '" . $document_id . "' AND parent_id = '0'")->GetCell(); // 2. Основной запрос: выбираем ВСЮ ветку (родителя и всё, что под ним) - // Мы ищем записи, которые либо сами являются нужными родителями, - // либо имеют parent_id, указывающий на них (включая глубокую вложенность через логику дерева) + // ищем записи, которые либо сами являются нужными родителями, + // либо имеют parent_id, указывающий на них (включая вложенность) $sql = $AVE_DB->Query(" SELECT * FROM " . PREFIX . "_module_comment_info WHERE document_id = '" . $document_id . "' @@ -350,13 +349,12 @@ if ($settings['comment_use_page_nav'] == 1) $date_time_format = $AVE_Template->get_config_vars('COMMENT_DATE_TIME_FORMAT'); $now = time(); - // ГАРАНТИРУЕМ получение лимита времени из настроек БД + // получение лимита времени из настроек БД $conf_limit = (int)($settings['comment_edit_time'] ?? 0); while ($row = $sql->FetchAssocArray()) { - // --- ВОТ ЭТОТ БЛОК --- if ($assign['saved_anon']['exists'] == false && !empty($row['anon_key']) && $row['anon_key'] == $anon_key) { $assign['saved_anon'] = [ 'name' => stripslashes($row['comment_author_name']), @@ -364,10 +362,8 @@ if ($settings['comment_use_page_nav'] == 1) 'exists' => true ]; } - // --- КОНЕЦ БЛОКА --- - -// 1. Получаем аватар через стандартную функцию системы + // Получаем аватар через стандартную функцию системы if (isset($row['comment_author_id']) && $row['comment_author_id'] > 0) { $row['avatar'] = getAvatar($row['comment_author_id'], 48); @@ -377,13 +373,13 @@ if ($settings['comment_use_page_nav'] == 1) $row['avatar'] = ''; } - // 2. ПРОВЕРКА: Если функция вернула системную заглушку, считаем, что аватара нет + // Если функция вернула системную заглушку, считаем, что аватара нет if (!empty($row['avatar']) && strpos($row['avatar'], 'user.png') !== false) { $row['avatar'] = ''; } - // 3. ЛОГИКА БУКВ: Если аватара нет (пусто или мы его обнулили выше) + // Если аватара нет (пусто или мы его обнулили выше) if (empty($row['avatar'])) { // Берем имя автора (если пусто — 'Guest') @@ -396,7 +392,7 @@ if ($settings['comment_use_page_nav'] == 1) $row['avatar_color_index'] = (abs(crc32($name)) % 12) + 1; } - // --- ИСПРАВЛЕННАЯ ЛОГИКА ТАЙМЕРА И ПРАВ (УЧЕТ АДМИНА) --- + // --- ТАЙМЕР И ПРАВА (УЧЕТ АДМИНА) --- $row['can_edit'] = 0; $is_admin = ($user_group === 1); @@ -419,14 +415,12 @@ if ($settings['comment_use_page_nav'] == 1) } } $row['is_my_own'] = $is_author; - // ------------------------------------------------------- - // --- НОВОЕ: Получаем историю имен для анонима --- + // --- Получаем историю имен для анонима --- $row['past_names'] = []; if (!empty($row['anon_key'])) { $row['past_names'] = $this->_getAnonNamesHistory($row['anon_key'], $row['comment_author_name']); } - // --- КОНЕЦ НОВОГО --- $row['comment_published_raw'] = $row['comment_published']; $row['comment_published'] = ave_date_format($date_time_format, $row['comment_published']); @@ -495,7 +489,7 @@ function commentPostFormShow($tpl_dir) $docid = (int)($_REQUEST['docid'] ?? 0); $user_group = UGROUP ?? 0; - // --- НОВОЕ: Автоподстановка для анонима --- + // --- Автоподстановка для анонима --- $anon_data = ['name' => '', 'email' => '', 'exists' => false]; if ($user_group == 2) { // Если гость $anon_key = $this->_getAnonKey(); @@ -513,7 +507,6 @@ function commentPostFormShow($tpl_dir) } } $AVE_Template->assign('saved_anon', $anon_data); - // --- КОНЕЦ НОВОГО --- $geschlossen = $AVE_DB->Query(" SELECT comments_close @@ -595,7 +588,7 @@ function commentPostFormShow($tpl_dir) $uploaded_files = []; if ($settings['comment_allow_files'] == 1 && isset($_FILES['comment_image'])) { - // --- ДОБАВЛЯЕМ ПРОВЕРКУ ЛИМИТА КОЛИЧЕСТВА --- + // --- ПРОВЕРКА ЛИМИТА КОЛИЧЕСТВА --- $max_files_limit = (int)($settings['comment_max_files'] ?? 5); $total_incoming = 0; if (is_array($_FILES['comment_image']['name'])) { @@ -636,7 +629,7 @@ function commentPostFormShow($tpl_dir) $allowed_extensions = array_map('trim', explode(',', strtolower($allowed_ext_str))); $max_file_size_bytes = (int)($settings['comment_max_file_size'] ?? 2048) * 1024; - // Защита: не даем загрузить одно и то же содержимое дважды в одном запросе + // не даем загрузить одно и то же содержимое дважды в одном запросе $processed_hashes = []; foreach ($files_to_process as $file) { @@ -755,7 +748,6 @@ function commentPostEdit($comment_id) if ($comment_id <= 0 || $user_group <= 0) exit('INVALID_ID'); // 2. Получаем данные комментария и настройки модуля (JOIN) - // ДОБАВЛЕНО: cmnt.comment_max_files в выборку $row = $AVE_DB->Query(" SELECT msg.*, @@ -774,7 +766,7 @@ function commentPostEdit($comment_id) if (!$row) exit('NOT_FOUND'); - // 3. Проверка прав (БЕЗОПАСНОСТЬ) + // 3. Проверка прав $is_admin = ($user_group == 1); $is_author = ($user_id > 0 && $user_id == $row['comment_author_id']) || @@ -823,7 +815,7 @@ function commentPostEdit($comment_id) if (file_exists($upload_dir . $rem_file)) { @unlink($upload_dir . $rem_file); } - // Удаляем из нашего массива для БД + // Удаляем из массива для БД $current_files = array_filter($current_files, function($v) use ($rem_file) { return trim($v) !== $rem_file; }); @@ -873,8 +865,7 @@ function commentPostEdit($comment_id) { if (!is_dir($upload_dir)) @mkdir($upload_dir, 0775, true); - // --- НАЧАЛО ИЗМЕНЕНИЙ --- - + // 1. Получаем оригинальное имя файла без расширения $original_basename = pathinfo($fname, PATHINFO_FILENAME); @@ -887,13 +878,8 @@ function commentPostEdit($comment_id) } // 4. Формируем новое имя: чистое_имя + время + расширение - // Убираем старый префикс 'comm_' и rand(), чтобы было как в новых комментах $new_file_name = $clean_name . '_' . time() . '.' . $file_ext; - // --- КОНЕЦ ИЗМЕНЕНИЙ --- - - - if (move_uploaded_file($tmp_name, $upload_dir . $new_file_name)) { $current_files[] = $new_file_name; } @@ -935,7 +921,7 @@ function commentPostDelete($comment_id) $comment_id = (int)$comment_id; if ($comment_id <= 0) die('Ошибка: Неверный ID'); - // --- ШАГ 0. ПОЛУЧЕНИЕ ДАННЫХ И ПРОВЕРКА ПРАВ --- + // --- ПОЛУЧЕНИЕ ДАННЫХ И ПРОВЕРКА ПРАВ --- $this->_commentSettingsGet(); $comment_data = $AVE_DB->Query(" @@ -973,7 +959,7 @@ function commentPostDelete($comment_id) $has_children = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_module_comment_info WHERE parent_id = '" . $comment_id . "'")->GetCell(); $upload_dir = BASE_DIR . '/uploads/comments/'; - // --- ВАРИАНТ А: МЯГКОЕ УДАЛЕНИЕ (если есть ответы и удаляет не админ) --- + // --- МЯГКОЕ УДАЛЕНИЕ (если есть ответы и удаляет не админ) --- if ($has_children > 0 && $user_group != 1) { // Удаляем файлы физически, если они есть if (!empty($comment_data['comment_file'])) { @@ -996,7 +982,7 @@ function commentPostDelete($comment_id) echo "OK_SOFT"; } else { - // --- ВАРИАНТ Б: ПОЛНОЕ УДАЛЕНИЕ (Админ или нет вложенных ответов) --- + // --- ПОЛНОЕ УДАЛЕНИЕ (Админ или нет вложенных ответов) --- $ids_to_delete = [$comment_id]; // Если админ — собираем всю ветку детей для удаления @@ -1066,11 +1052,11 @@ function commentPostDelete($comment_id) return; } - // 1. Идентификация текущего голосующего + // Идентификация текущего голосующего $user_id = empty($_SESSION['user_id']) ? 0 : (int)$_SESSION['user_id']; $anon_key = $this->_getAnonKey(); - // 1.5 ПРОВЕРКА ПРАВ ГОЛОСОВАНИЯ (Новое) + // ПРОВЕРКА ПРАВ ГОЛОСОВАНИЯ (Новое) // Получаем настройки модуля, чтобы узнать, разрешено ли анонимам голосовать $settings = $this->_commentSettingsGet(); if (empty($user_id) && empty($settings['comment_rating_anon_vote'])) { @@ -1082,7 +1068,7 @@ function commentPostDelete($comment_id) return; } - // 2. Получаем данные о комментарии, за который голосуют + // Получаем данные о комментарии, за который голосуют $comment_row = $AVE_DB->Query(" SELECT comment_author_id, anon_key, comment_author_ip FROM " . PREFIX . "_module_comment_info @@ -1100,7 +1086,7 @@ function commentPostDelete($comment_id) $c_author_id = (int)$comment_row->comment_author_id; - // 3. ПРОВЕРКА АВТОРСТВА (Запрет голосовать за свой же комментарий) + // ПРОВЕРКА АВТОРСТВА (Запрет голосовать за свой же комментарий) $is_author = false; if ($user_id > 0) { @@ -1127,8 +1113,8 @@ function commentPostDelete($comment_id) return; } - // 4. ПРОВЕРКА ПОВТОРНОГО ГОЛОСОВАНИЯ - // Ищем в истории, голосовал ли уже этот человек + // ПРОВЕРКА ПОВТОРНОГО ГОЛОСОВАНИЯ + // Ищем в истории, голосовал ли уже этот посетитель if ($user_id > 0) { // Для авторизованных поиск по ID $sql_check = "SELECT id FROM " . PREFIX . "_module_comment_votes @@ -1151,7 +1137,7 @@ function commentPostDelete($comment_id) return; } - // 5. ЗАПИСЬ ГОЛОСА В ЛОГ + // ЗАПИСЬ ГОЛОСА В ЛОГ $AVE_DB->Query(" INSERT INTO " . PREFIX . "_module_comment_votes (comment_id, user_id, anon_key, remote_addr, vote_value, date_voted) @@ -1164,7 +1150,7 @@ function commentPostDelete($comment_id) '" . time() . "') "); - // 6. ОБНОВЛЕНИЕ АГРЕГАТОВ В ТАБЛИЦЕ INFO + // ОБНОВЛЕНИЕ В ТАБЛИЦЕ INFO $AVE_DB->Query(" UPDATE " . PREFIX . "_module_comment_info SET rating_sum = rating_sum + " . $vote_value . ", @@ -1172,7 +1158,7 @@ function commentPostDelete($comment_id) WHERE Id = '" . $comment_id . "' "); - // 7. ФИНАЛ: Чистый ответ для JS + // ФИНАЛ: Чистый ответ для JS if ($ajax) { if (ob_get_length()) ob_end_clean(); echo 'success'; @@ -1324,7 +1310,7 @@ function commentPostDelete($comment_id) switch ($request_sort) { case 'document_desc': - $def_sort = 'ORDER BY doc.Id ASC'; // Предполагаю, что document_desc должен быть ASC + $def_sort = 'ORDER BY doc.Id ASC'; $def_nav = '&sort=document_desc'; break; @@ -1420,7 +1406,7 @@ function commentPostDelete($comment_id) // и нажал кнопку сохранить изменения), тогда выполняем запрос к БД на обновление информации. if ($post_sub == 'send' && false != $row) { - // --- !!! БЕЗОПАСНОСТЬ: Экранирование данных перед сохранением !!! --- + // --- Экранирование данных перед сохранением --- $AVE_DB->Query(" UPDATE " . PREFIX . "_module_comment_info SET @@ -1439,7 +1425,7 @@ function commentPostDelete($comment_id) return; } - // Если в первой выборке из БД мы получили нулевой результат, тогда генерируем сообщение с ошибкой + // Если в первой выборке из БД получили нулевой результат, тогда генерируем сообщение с ошибкой if ($row == false) { $AVE_Template->assign('editfalse', 1); @@ -1490,7 +1476,7 @@ function commentAdminSettingsEdit($tpl_dir) $post_allow_files = $_POST['comment_allow_files'] ?? 0; $post_allow_files_anon = $_POST['comment_allow_files_anon'] ?? 0; - /* НОВОЕ: Настройки расширений и максимального размера файла */ + /* Настройки расширений и максимального размера файла */ $post_allowed_extensions = $_POST['comment_allowed_extensions'] ?? 'jpg,jpeg,png,gif'; $post_max_file_size = $_POST['comment_max_file_size'] ?? 2048; $post_max_files = $_POST['comment_max_files'] ?? 5; @@ -1498,13 +1484,13 @@ function commentAdminSettingsEdit($tpl_dir) $post_rating_type = $_POST['comment_rating_type'] ?? 0; $post_show_user_rating = $_POST['comment_show_user_rating'] ?? 0; - /* НОВОЕ: Настройка показа авторской оценки в ответах */ + /* Настройка показа авторской оценки в ответах */ $post_show_user_rating_replies = $_POST['comment_show_user_rating_replies'] ?? 0; $post_rating_anon_vote = $_POST['comment_rating_anon_vote'] ?? 0; $post_rating_anon_set = $_POST['comment_rating_anon_set'] ?? 0; - // Новые настройки времени и куки + // настройки времени и куки $post_edit_time = $_POST['comment_edit_time'] ?? 60; $post_cookie_life = $_POST['comment_cookie_life'] ?? 30;