Files
comment/class/comment.php

989 lines
39 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Класс, включающий все свойства и методы для управления комментариями как в
* Публичной части сайта, так и в Панели управления.
*
* @package AVE.cms
* @subpackage module_Comment
* @since 1.4
* @filesource
*/
class Comment
{
/**
* Свойства класса
*/
/**
* Идентификатор записи с настройками модуля Комментарии
*
* @var int
*/
private $_config_id = 1;
/**
* Количество комментариев на странице в административной части
*
* @var int
*/
private $_limit = 15;
/**
* Имя файла с шаблоном для вывода блока комментариев
*
* @var string
*/
public $_comments_tree_tpl = 'comments_tree.tpl';
/**
* Имя файла с шаблоном для рекурсивного вывода иерархии комментариев
*
* @var string
*/
public $_comments_tree_sub_tpl = 'comments_tree_sub.tpl';
/**
* Имя файла с шаблоном формы добавления комментария
*
* @var string
*/
public $_comment_form_tpl = 'comment_form.tpl';
/**
* Имя файла с шаблоном нового комментария
*
* @var string
*/
public $_comment_new_tpl = 'comment_new.tpl';
/**
* Имя файлаа с шаблоном уведомляющим о успешном выполнении операции
*
* @var string
*/
public $_comment_thankyou_tpl = 'comment_thankyou.tpl';
/**
* Имя файла с шаблоном редактирования шаблона в административной части
*
* @var string
*/
public $_admin_edit_link_tpl = 'admin_edit.tpl';
/**
* Имя файла с шаблоном списка комментариев в административной части
*
* @var string
*/
public $_admin_comments_tpl = 'admin_comments.tpl';
/**
* Имя файла с шаблоном редактирования настроек модуля в административной части
*
* @var string
*/
public $_admin_settings_tpl = 'admin_settings.tpl';
/**
* Имя файла с шаблоном редактирования шаблона в публичной части
*
* @var string
*/
public $_edit_link_tpl = 'comment_edit.tpl';
/**
* Имя файла с шаблоном для вывода информации об авторе комментария
*
* @var string
*/
public $_postinfo_tpl = 'comment_info.tpl';
/**
* Внутренние методы класса
*/
/**
* Метод, предназначенный для получения основных настроек модуля,которые задаются в Панели управления.
*
* @param string $param название параметра
* @return mixed значение настройки
*/
function _commentSettingsGet($param = '')
{
global $AVE_DB;
// Определяем статическую переменную, которая будет хранить полученные настройки на протяжении всего
// срока жизни объекта.
static $settings = null;
// Если переменная $settings еще не имеет значений, тогда выполняем запрос к БД на получение данных
if ($settings === null)
{
$settings = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_comments
WHERE Id = '" . $this->_config_id . "'
")->FetchAssocArray();
}
if ($param == '')
return $settings;
// В противном случае возвращаем уже имеющиеся значения
return (isset($settings[$param])
? $settings[$param]
: null);
}
/**
* Метод, предназначенный для получения количества комментариев для определенного документа.
*
* @param int $document_id - идентификатор документа
* @return int - количество комментариев
*/
function _commentPostCountGet($document_id)
{
global $AVE_DB;
// Определяем статический массив, который будет хранить количество комментариев для документов на
// протяжении всего срока жизни объекта.
static $comments = array();
// Если в массиве не найден ключ, который соответствует запрашиваемому документу, тогда выполняем
// запрос к БД на получение количества комментариев
if (! isset($comments[$document_id]))
{
$comments[$document_id] = $AVE_DB->Query("
SELECT COUNT(*)
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . (int)$document_id . "'
")->GetCell();
}
// Возвращаем количество комментариев для запрашиваемого документа
return $comments[$document_id];
}
/**
* Внешние методы класса
*/
/**
* Следующие методы описывают работу модуля в Публичной части сайта.
*/
/**
* Метод, предназначенный для получения из БД всех комментариев, относящихся к указанному
* документу с последующим выводом в Публичной части.
*
* @param string $tpl_dir - путь к шаблонам модуля
*
* @todo Вывод информации о авторе комментария
*/
function commentListShow($tpl_dir)
{
global $AVE_DB, $AVE_Template, $AVE_Core;
// Используем оператор объединения с null для PHP 8.4
$document_id = (int)($_REQUEST['id'] ?? 0);
$artpage = $_REQUEST['artpage'] ?? null;
$apage = $_REQUEST['apage'] ?? null;
$user_group = UGROUP ?? 0;
// Проверяем, что в настройках модуля разрешено комментирование документов
if ($this->_commentSettingsGet('comment_active') == 1)
{
// =================================================================================
// НОВОЕ: ПРОВЕРКА ПРАВ НА ПРОСМОТР КОММЕНТАРИЕВ (Read Permission)
// =================================================================================
$read_groups = explode(',', $this->_commentSettingsGet('comment_user_groups_read'));
$assign['no_read_permission'] = 0; // Флаг: 0 = права есть
// Если группа текущего пользователя НЕ в списке разрешенных для ЧТЕНИЯ,
if (!in_array($user_group, $read_groups))
{
// Устанавливаем флаг, что прав на чтение нет
$assign['no_read_permission'] = 1;
}
// =================================================================================
$assign['display_comments'] = 1;
// Если группа пользователя, который в текущий момент просматривает документ попадает в список
// разрешенных (в настройках модуля), тогда создаем флаг, который будет разрешать к показу
// форму для добавления нового комментария
if (in_array($user_group, explode(',', $this->_commentSettingsGet('comment_user_groups'))))
{
$assign['cancomment'] = 1;
}
// ЕСЛИ ЕСТЬ ПРАВА НА ЧТЕНИЕ, ПРОДОЛЖАЕМ ВЫБОРКУ И ВЫВОД
if ($assign['no_read_permission'] == 0)
{
$assign['comment_max_chars'] = $this->_commentSettingsGet('comment_max_chars');
$assign['im'] = $this->_commentSettingsGet('comment_use_antispam');
// Выполняем запрос к БД на получение количества комментариев для текущего документа
$comments = array();
if ($this->_commentSettingsGet('comment_use_page_nav') == 1)
{
$limit = $this->_commentSettingsGet('comment_page_nav_count');
$start = get_current_page() * $limit - $limit;
$num = $AVE_DB->Query("
SELECT COUNT(*)
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . $document_id . "'
")->GetCell();
$sql = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . $document_id . "'
" . ($user_group == 1 ? '' : "AND comment_status = '1'") . "
ORDER BY comment_published ASC
LIMIT " . $start . "," . $limit . "
");
$pages = @ceil($num / $limit);
if ($num > $limit)
{
$page_nav = '<a class="page_nav" href="index.php?id=' . $AVE_Core->curentdoc->Id
. '&amp;doc=' . (empty($AVE_Core->curentdoc->document_alias) ? prepare_url($AVE_Core->curentdoc->document_title) : $AVE_Core->curentdoc->document_alias)
. ((isset($artpage) && is_numeric($artpage)) ? '&amp;artpage=' . $artpage : '')
. ((isset($apage) && is_numeric($apage)) ? '&amp;apage=' . $apage : '')
. '&amp;page={s}">{t}</a> ';
$page_nav = get_pagination(ceil($num / $limit), 'page', $page_nav, get_settings('navi_box'));
$page_nav = rewrite_link($page_nav);
$GLOBALS['page_id'][$document_id]['page']=($GLOBALS['page_id'][$document_id]['page']>ceil($num / $limit) ? $GLOBALS['page_id'][$document_id]['page'] : ceil($num / $limit));
}
else
{
$page_nav = '';
}
}
else
{
$sql = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . $document_id . "'
" . ($user_group == 1 ? '' : "AND comment_status = '1'") . "
ORDER BY comment_published ASC
");
$page_nav = '';
}
// Получаем формат даты, который указан в общих настройках системы и
// приводим дату создания комментария и дату редактирования к этому формату
$date_time_format = $AVE_Template->get_config_vars('COMMENT_DATE_TIME_FORMAT');
while ($row = $sql->FetchAssocArray())
{
// -----------------------------------------------------
// !!! НАЧАЛО: ВНЕДРЕНИЕ АВАТАРА !!!
// -----------------------------------------------------
if (isset($row['comment_author_id']) && $row['comment_author_id'] > 0)
{
// Вызываем глобальную функцию getAvatar с нужным размером (48px)
// и сохраняем результат в поле 'avatar' для Smarty:
$row['avatar'] = getAvatar($row['comment_author_id'], 48);
}
else
{
// Для гостей (comment_author_id = 0) или неавторизованных:
// Передаем пустую строку, чтобы Smarty использовал заглушку.
$row['avatar'] = '';
}
// -----------------------------------------------------
// !!! КОНЕЦ: ВНЕДРЕНИЕ АВАТАРА !!!
// -----------------------------------------------------
$row['comment_published'] = ave_date_format($date_time_format, $row['comment_published']);
$row['comment_changed'] = ave_date_format($date_time_format, $row['comment_changed']);
$comments[$row['parent_id']][] = $row;
}
}
else
{
// Если нет прав, то эти переменные остаются пустыми/неопределенными
$comments = array();
$page_nav = '';
}
// Формируем ряд переменных для использования в шаблоне
$assign['closed'] = @$comments[0][0]['comments_close'];
$assign['comments'] = $comments;
$assign['theme'] = defined('THEME_FOLDER') ? THEME_FOLDER : DEFAULT_THEME_FOLDER;
$assign['doc_id'] = $document_id;
$assign['page'] = base64_encode(get_redirect_link());
$assign['subtpl'] = $tpl_dir . $this->_comments_tree_sub_tpl;
$AVE_Template->assign($assign);
$AVE_Template->assign('page_nav', $page_nav);
// Отображаем шаблон
$AVE_Template->display($tpl_dir . $this->_comments_tree_tpl);
}
}
/**
* Метод, предназначенный для отображения формы при добавлении нового комментария.
*
* @param string $tpl_dir - путь к шаблонам модуля
*/
function commentPostFormShow($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$docid = (int)($_REQUEST['docid'] ?? 0);
$user_group = UGROUP ?? 0;
// Получаем список комментариев на которые запрещены ответы
$geschlossen = $AVE_DB->Query("
SELECT comments_close
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . $docid . "'
LIMIT 1
")->GetCell();
// Формируем ряд переменных для использования в шаблоне
$AVE_Template->assign('closed', $geschlossen);
$AVE_Template->assign('cancomment', ($this->_commentSettingsGet('comment_active') == 1 && in_array($user_group, explode(',', $this->_commentSettingsGet('comment_user_groups')))));
$AVE_Template->assign('comment_max_chars', $this->_commentSettingsGet('comment_max_chars'));
$AVE_Template->assign('theme', defined('THEME_FOLDER') ? THEME_FOLDER : DEFAULT_THEME_FOLDER);
// Отображаем форму для добавления комментария
$AVE_Template->display($tpl_dir . $this->_comment_form_tpl);
}
/**
* Метод, предназначенный для записи в БД нового комментария.
*
* @param string $tpl_dir - путь к шаблонам модуля
*
*/
function commentPostNew($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$page = $_REQUEST['page'] ?? '';
$ajax = (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 1);
$user_group = UGROUP ?? 0;
$secure_code = $_POST['securecode'] ?? '';
$session_captcha = $_SESSION['captcha_keystring'] ?? null;
// Если запрос пришел не ajax запросом, тогда формируем ссылку для последующего редиректа
if (! $ajax)
{
$link = rewrite_link(base64_decode($page));
}
// Если в настройках модуля включено использование защитного кода, тогда
if ($this->_commentSettingsGet('comment_use_antispam') == 1)
{
// Если введенный пользователем защитный код неверен, тогда выполняем обновление кода
if (! (isset($session_captcha) && $session_captcha == $secure_code))
{
unset($_SESSION['captcha_keystring']);
if ($ajax)
{
echo 'wrong_securecode';
}
else
{
if(isset($GLOBALS['tmpl']))$GLOBALS['tmpl']->assign("wrongSecureCode", 1);
header('Location:' . $link . '#end');
}
exit;
}
unset($_SESSION['captcha_keystring']);
}
// Определяем флаг модерации комментариев
$comment_status = ($this->_commentSettingsGet('comment_need_approve') == 1) ? 0 : 1;
// Если комментарии разрешены, тогда получаем все данные, который пользователь указал в форме
if ($this->_commentSettingsGet('comment_active') == 1
&& !empty($_POST['comment_text'])
&& !empty($_POST['comment_author_name'])
&& in_array($user_group, explode(',', $this->_commentSettingsGet('comment_user_groups'))))
{
// --- !!! НАЧАЛО БЕЗОПАСНОСТИ: Санитаризация и Экранирование !!! ---
$new_comment['parent_id'] = (int)($_POST['parent_id'] ?? 0);
$new_comment['document_id'] = (int)($_POST['doc_id'] ?? 0);
// Экранирование для предотвращения SQLi:
// Санитаризация для предотвращения XSS в строковых полях:
$new_comment['comment_author_name'] = addslashes(strip_tags($_POST['comment_author_name'] ?? ''));
$new_comment['comment_author_id'] = empty($_SESSION['user_id']) ? 0 : (int)$_SESSION['user_id'];
$new_comment['comment_author_email'] = addslashes(strip_tags($_POST['comment_author_email'] ?? ''));
$new_comment['comment_author_city'] = addslashes(strip_tags($_POST['comment_author_city'] ?? ''));
$new_comment['comment_author_website'] = addslashes(strip_tags($_POST['comment_author_website'] ?? ''));
$new_comment['comment_author_ip'] = $_SERVER['REMOTE_ADDR'];
$new_comment['comment_published'] = time();
$new_comment['comment_status'] = $comment_status;
// Текст комментария до очистки
$comment_text_raw = $_POST['comment_text'] ?? '';
// Определяем максимальную длину символов для комментария
$comment_max_chars = $this->_commentSettingsGet('comment_max_chars');
$comment_max_chars = (!empty($comment_max_chars) && $comment_max_chars > 10) ? $comment_max_chars : 200;
// 1. Убираем HTML-теги для предотвращения XSS
$comment_text_clean = strip_tags(stripslashes($comment_text_raw));
// 2. Обрезка
$comment_text_cut = mb_substr($comment_text_clean, 0, $comment_max_chars);
$comment_text_cut .= (mb_strlen($comment_text_clean) > $comment_max_chars) ? '…' : '';
// 3. Экранирование текста перед вставкой в SQL
$new_comment['comment_text'] = addslashes($comment_text_cut);
// --- !!! КОНЕЦ БЕЗОПАСНОСТИ !!! ---
// Выполняем запрос к БД на добавление комментария
$AVE_DB->Query("
INSERT INTO " . PREFIX . "_module_comment_info
(`" . implode('`,`', array_keys($new_comment)) ."`)
VALUES
('" . implode("','", $new_comment) . "')
");
$new_comment['Id'] = $AVE_DB->InsertId();
// Получаем e-mail адрес из Общих настроек системы и формируем ссылку на комментарий в Публичной части
$mail_from = get_settings('mail_from');
$mail_from_name = get_settings('mail_from_name');
$page_link = get_home_link() . urldecode(base64_decode($page)) . '&subaction=showonly&comment_id=' . $new_comment['Id'] . '#' . $new_comment['Id'];
// Формируем текст уведомления для отправки на e-mail
$mail_text = $AVE_Template->get_config_vars('COMMENT_MESSAGE_ADMIN');
// Используем stripslashes для очистки текста, который будет отправлен по почте
$mail_text = str_replace('%COMMENT%', stripslashes($new_comment['comment_text']), $mail_text);
$mail_text = str_replace('%N%', "\n", $mail_text);
$mail_text = str_replace('%PAGE%', $page_link, $mail_text);
$mail_text = str_replace('&amp;', '&', $mail_text);
// Отправляем уведомление
send_mail(
$mail_from,
$mail_text,
$AVE_Template->get_config_vars('COMMENT_SUBJECT_MAIL'),
$mail_from,
$mail_from_name,
'text'
);
// Если данные были отправлены ajax-запросом, тогда выполняем автоматический показ комментария
// на странице.
if ($ajax)
{
// ---------------------------------------------------------------------
// !!! НАЧАЛО: ИСПРАВЛЕНИЕ ДЛЯ AJAX-ОТВЕТА (ПОЛУЧЕНИЕ АВАТАРА) !!!
// ---------------------------------------------------------------------
if (isset($new_comment['comment_author_id']) && $new_comment['comment_author_id'] > 0)
{
// Вызываем глобальную функцию getAvatar с нужным размером (48px)
$new_comment['avatar'] = getAvatar($new_comment['comment_author_id'], 48);
}
else
{
// Для гостей
$new_comment['avatar'] = '';
}
// ---------------------------------------------------------------------
// !!! КОНЕЦ: ИСПРАВЛЕНИЕ ДЛЯ AJAX-ОТВЕТА !!!
// ----
$new_comment['comment_changed'] = 0;
$new_comment['comment_published'] = ave_date_format($AVE_Template->get_config_vars('COMMENT_DATE_TIME_FORMAT'), $new_comment['comment_published']);
$subcomments[] = $new_comment;
$AVE_Template->assign('subcomments', $subcomments);
$AVE_Template->assign('theme', defined('THEME_FOLDER') ? THEME_FOLDER : DEFAULT_THEME_FOLDER);
$AVE_Template->display($tpl_dir . $this->_comments_tree_sub_tpl);
}
}
// Если же данные пришли НЕ ajax-запросом, тогда полностью обновляем страницу.
if (! $ajax) header('Location:' . str_replace("//", "", $link) . '#end');
exit;
}
/**
* Метод, предназначенный для редактирования комментария в Публичной части
*
* @param int $comment_id - идентификатор комментария
*/
function commentPostEdit($comment_id)
{
global $AVE_DB;
$user_id = $_SESSION['user_id'] ?? null;
$user_group = UGROUP ?? 0;
$post_text = $_POST['text'] ?? '';
if (empty($user_id)) exit;
$comment_id = intval(preg_replace('/\D/', '', $comment_id));
// Выполняем запрос к БД и получаем всю информацию о комментарии, а также ряд значений из настроек модуля
$row = $AVE_DB->Query("
SELECT
msg.parent_id,
msg.comment_text,
cmnt.comment_user_groups,
cmnt.comment_max_chars,
cmnt.comment_need_approve
FROM
" . PREFIX . "_module_comment_info AS msg,
" . PREFIX . "_module_comments AS cmnt
WHERE comment_active = '1'
AND msg.Id = '" . $comment_id . "'
" . (($user_group != 1) ? "AND comment_author_id = " . $user_id : '') . "
")->FetchAssocArray();
// Если данные получены
if ($row !== false)
{
$comment_max_chars = ($row['comment_max_chars'] != '' && $row['comment_max_chars'] > 10) ? $row['comment_max_chars'] : 20;
$comment_text = $post_text;
// --- !!! НАЧАЛО ИСПРАВЛЕНИЯ УСТАРЕВШИХ ОПЕРАТОРОВ (/e) !!! ---
// Безопасная замена: преобразуем hex-сущности
$comment_text = preg_replace_callback('/&#x([0-9a-f]{1,7});/', function($matches) {
return chr(hexdec($matches[1]));
}, $comment_text);
// Безопасная замена: преобразуем dec-сущности
$comment_text = preg_replace_callback('/&#([0-9]{1,7});/', function($matches) {
return chr($matches[1]);
}, $comment_text);
// --- !!! КОНЕЦ ИСПРАВЛЕНИЯ УСТАРЕВШИХ ОПЕРАТОРОВ !!! ---
$comment_text = stripslashes($comment_text);
$comment_text = str_replace(array("<br>\n", "<br />\n", "<br/>\n"), "\n", $comment_text);
// Санитаризация: убираем теги перед обрезкой
$comment_text = strip_tags($comment_text);
$comment_text = mb_substr($comment_text, 0, $comment_max_chars-1);
$message_length = mb_strlen($comment_text);
$comment_text .= ($message_length > $comment_max_chars) ? '…' : '';
// Если группа текущего пользователя совпадает с разрешенной группой в настройках модуля, тогда
// выполняем запрос к БД на обновление информации.
if (in_array($user_group, explode(',', $row['comment_user_groups'])) && $message_length > 3)
{
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_comment_info
SET
comment_changed = '" . time() . "',
comment_status = '" . intval(!(bool)$row['comment_need_approve']) . "',
comment_text = '" . addslashes($comment_text) . "'
WHERE
Id = '" . $comment_id . "'
");
// Преобразуем HTML теги в HTML сущности перед выводом (для XSS)
echo htmlspecialchars($comment_text, ENT_QUOTES);
exit;
}
// Если редактирование не прошло, выводим оригинальный текст (экранированный)
echo htmlspecialchars($row['comment_text'], ENT_QUOTES);
}
exit;
}
/**
* Метод, предназначенный для удаления комментария. Если комментарий содержал какие-либо ответы на него,
* то все ответы также будут удалены вместе с родительским комментарием.
*
* @param int $comment_id - идентификатор комментария
*/
function commentPostDelete($comment_id)
{
global $AVE_DB;
$comment_id = (int)$comment_id; // Убедимся, что это целое число
// Выполняем запрос к БД на удаление родительского комментария
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_comment_info
WHERE Id = '" . $comment_id . "'
");
// Выполняем запрос к БД на удаление дочерних комментариев (ответов)
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_comment_info
WHERE parent_id = '" . $comment_id . "'
AND parent_id != 0
");
exit;
}
function commentAdminDelete($comment_id)
{
global $AVE_DB;
$comment_id = (int)$comment_id; // Убедимся, что это целое число
// Выполняем запрос к БД на удаление родительского комментария
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_comment_info
WHERE Id = '" . $comment_id . "'
");
// Выполняем запрос к БД на удаление дочерних комментариев (ответов)
$AVE_DB->Query("
DELETE
FROM " . PREFIX . "_module_comment_info
WHERE parent_id = '" . $comment_id . "'
AND parent_id != 0
");
// Используем оператор объединения с null для PHP 8.4
$session_id = SESSION ?? '';
header('Location:index.php?do=modules&action=modedit&mod=comment&moduleaction=1&cp=' . $session_id);
exit;
}
/**
* Метод, предназначенный для вывода детальной информации об авторе комментария
*
* @param string $tpl_dir - путь к шаблонам модуля
*/
function commentPostInfoShow($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$comment_id = (int)($_REQUEST['Id'] ?? 0);
// Получаем полную информацию о комментарии
$row = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_comment_info
WHERE Id = '" . $comment_id . "'
")->FetchAssocArray();
// Преобразуем адрес сайта к формату ссылки
$row['comment_author_website'] = str_replace('http://', '', $row['comment_author_website']);
$row['comment_author_website'] = ($row['comment_author_website'] != '')
? '<a target="_blank" href="http://' . $row['comment_author_website'] . '">' . $row['comment_author_website'] .'</a>'
: '';
// Выполняем запрос к БД на получение количества всех комментариев, оставленных данным пользователем
$row['num'] = $AVE_DB->Query("
SELECT COUNT(*)
FROM " . PREFIX . "_module_comment_info
WHERE comment_author_id = '" . $row['comment_author_id'] . "'
AND comment_author_id != 0
")->GetCell();
// Отображаем окно с информацией
$AVE_Template->assign('c', $row);
$AVE_Template->display($tpl_dir . $this->_postinfo_tpl);
}
/**
* Метод, предназначенный для управления запретом или разрешением отвечать на комментарии
*
* @param int $comment_id - идентификатор комментария
* @param string $comment_status - {lock|unlock} признак запрета/разрешения
*/
function commentReplyStatusSet($comment_id, $comment_status = 'lock')
{
global $AVE_DB;
$comment_id = (int)$comment_id;
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_comment_info
SET comment_status = '" . (($comment_status == 'lock') ? 0 : 1) . "'
WHERE Id = '" . $comment_id . "'
");
exit;
}
/**
* Метод, предназначенный для управления запретом или разрешением комментировать документ
*
* @param int $document_id - идентификатор документа
* @param string $comment_status - {close|open} признак запрета/разрешения
*/
function commentStatusSet($document_id, $comment_status = 'open')
{
global $AVE_DB;
$document_id = (int)$document_id;
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_comment_info
SET comments_close = '" . (($comment_status == 'open') ? 0 : 1) . "'
WHERE document_id = '" . $document_id . "'
");
exit;
}
/**
* Следующие методы описывают работу модуля в Административной части сайта.
*/
/**
* Метод, предназначенный для вывода списка всех комментариев в Административной части.
*
* @param string $tpl_dir - путь к шаблонам модуля
*/
function commentAdminListShow($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$request_sort = $_REQUEST['sort'] ?? '';
$session_id = SESSION ?? '';
// Получаем общее количество комментариев
$num = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_module_comment_info")->GetCell();
// Определяем количество страниц, учитывая параметр _limit, который опроеделяет количество
// комментариев отображаемых на одной странице
@$seiten = @ceil($num / $this->_limit);
$start = get_current_page() * $this->_limit - $this->_limit;
$docs = array();
$def_sort = 'ORDER BY doc.Id DESC';
$def_nav = '';
// Определяем условия сортировки комментариев
if (!empty($request_sort))
{
switch ($request_sort)
{
case 'document_desc':
$def_sort = 'ORDER BY doc.Id ASC'; // Предполагаю, что document_desc должен быть ASC
$def_nav = '&sort=document_desc';
break;
case 'document':
$def_sort = 'ORDER BY doc.Id DESC';
$def_nav = '&sort=document';
break;
case 'comment_desc':
$def_sort = 'ORDER BY cmnt.comment_text ASC';
$def_nav = '&sort=comment_desc';
break;
case 'comment':
$def_sort = 'ORDER BY cmnt.comment_text DESC';
$def_nav = '&sort=comment';
break;
case 'created_desc':
$def_sort = 'ORDER BY cmnt.comment_published ASC';
$def_nav = '&sort=created_desc';
break;
case 'created':
$def_sort = 'ORDER BY cmnt.comment_published DESC';
$def_nav = '&sort=created';
break;
}
}
// Выполняем запрос к БД на получение комметариев с учетом параметров сортировки и лимита.
$sql = $AVE_DB->Query("
SELECT
doc.Id,
doc.document_title,
cmnt.Id AS CId,
cmnt.document_id,
cmnt.comment_text,
cmnt.comment_published,
cmnt.comment_status
FROM
" . PREFIX . "_module_comment_info AS cmnt
JOIN
" . PREFIX . "_documents AS doc
ON doc.Id = cmnt.document_id
" . $def_sort . "
LIMIT " . $start . "," . $this->_limit
);
while ($row = $sql->FetchAssocArray())
{
$row['Comments'] = $this->_commentPostCountGet($row['Id']);
array_push($docs, $row);
}
// Если количество комментариев полученных из БД превышает допустимое на странице, тогда формируем
// меню постраницной навигации
if ($num > $this->_limit)
{
$page_nav = ' <a class="pnav" href="index.php?do=modules&action=modedit&mod=comment&moduleaction=1&cp=' . $session_id . '&page={s}' . $def_nav . '">{t}</a> ';
$page_nav = get_pagination($seiten, 'page', $page_nav);
$AVE_Template->assign('page_nav', $page_nav);
}
// Передаем данные в шаблон для вывода и отображаем шаблон
$AVE_Template->assign('docs', $docs);
$AVE_Template->assign('content', $AVE_Template->fetch($tpl_dir . $this->_admin_comments_tpl));
}
/**
* Метод, предназначенный для редактирования комментариев в Административной части.
*
* @param string $tpl_dir - путь к шаблонам модуля
*/
function commentAdminPostEdit($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$post_sub = $_POST['sub'] ?? '';
$request_id = (int)($_REQUEST['Id'] ?? 0);
$request_docid = (int)($_REQUEST['docid'] ?? 0);
// Выполняем запрос к БД на получение информации о редактируемом комментарии
$row = $AVE_DB->Query("
SELECT *
FROM " . PREFIX . "_module_comment_info
WHERE Id = '" . $request_id . "'
LIMIT 1
")->FetchAssocArray();
// Если в запросе содержится подзапрос на сохранение данных (пользователь уже отредактировал комментарий
// и нажал кнопку сохранить изменения), тогда выполняем запрос к БД на обновление информации.
if ($post_sub == 'send' && false != $row)
{
// --- !!! БЕЗОПАСНОСТЬ: Экранирование данных перед сохранением !!! ---
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_comment_info
SET
comment_author_name = '" . addslashes(htmlspecialchars($_POST['comment_author_name'] ?? '')) . "',
comment_author_email = '" . addslashes(htmlspecialchars($_POST['comment_author_email'] ?? '')) . "',
comment_author_city = '" . addslashes(htmlspecialchars($_POST['comment_author_city'] ?? '')) . "',
comment_author_website = '" . addslashes(htmlspecialchars($_POST['comment_author_website'] ?? '')) . "',
comment_text = '" . addslashes(htmlspecialchars($_POST['comment_text'] ?? '')) . "',
comment_changed = '" . time() . "'
WHERE
Id = '" . (int)($_POST['Id'] ?? 0) . "'
");
echo '<script>window.opener.location.reload();window.close();</script>';
return;
}
// Если в первой выборке из БД мы получили нулевой результат, тогда генерируем сообщение с ошибкой
if ($row == false)
{
$AVE_Template->assign('editfalse', 1);
}
// в противном случае получаем список комментариев, у которых стоит запрет на ответы
else
{
$closed = $AVE_DB->Query("
SELECT comments_close
FROM " . PREFIX . "_module_comment_info
WHERE document_id = '" . $request_docid . "'
LIMIT 1
")->GetCell();
$AVE_Template->assign('closed', $closed);
$AVE_Template->assign('row', $row);
$AVE_Template->assign('comment_max_chars', $this->_commentSettingsGet('comment_max_chars'));
}
// Отображаем шаблон
$AVE_Template->assign('content', $AVE_Template->fetch($tpl_dir . $this->_admin_edit_link_tpl));
}
/**
* Метод, предназначенный для управления настройками модуля
*
* @param string $tpl_dir - путь к шаблонам модуля
*/
function commentAdminSettingsEdit($tpl_dir)
{
global $AVE_DB, $AVE_Template;
// Используем оператор объединения с null для PHP 8.4
$request_sub = $_REQUEST['sub'] ?? '';
$post_max_chars = $_POST['comment_max_chars'] ?? 0;
$post_user_groups = $_POST['comment_user_groups'] ?? array();
// НОВОЕ: Получение данных для групп, которым разрешен просмотр
$post_user_groups_read = $_POST['comment_user_groups_read'] ?? array();
// КОНЕЦ НОВОГО
$post_need_approve = $_POST['comment_need_approve'] ?? 0;
$post_active = $_POST['comment_active'] ?? 0;
$post_use_antispam = $_POST['comment_use_antispam'] ?? 0;
$post_use_page_nav = $_POST['comment_use_page_nav'] ?? 0;
$post_page_nav_count = $_POST['comment_page_nav_count'] ?? 0;
// Если в запросе содержится подзапрос на сохранение данных (пользователь нажал кнопку
// сохранить изменения), тогда выполняем запрос к БД на обновление информации.
if ($request_sub == 'save')
{
$max_chars = (empty($post_max_chars) || $post_max_chars < 50) ? 50 : $post_max_chars;
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_comments
SET
comment_max_chars = '" . (int)$max_chars . "',
comment_user_groups = '" . implode(',', $post_user_groups) . "',
comment_user_groups_read = '" . implode(',', $post_user_groups_read) . "', /* <-- СОХРАНЕНИЕ НОВОГО ПОЛЯ */
comment_need_approve = '" . (int)$post_need_approve . "',
comment_active = '" . (int)$post_active . "',
comment_use_antispam = '" . (int)$post_use_antispam . "',
comment_use_page_nav = '" . (int)$post_use_page_nav . "',
comment_page_nav_count = '" . (int)$post_page_nav_count . "'
WHERE
Id = 1
");
}
// Получаем список всех настроек модуля
$row = $this->_commentSettingsGet();
// Преобразуем поля с правами в массивы для удобства отображения в шаблоне
$row['comment_user_groups'] = explode(',', $row['comment_user_groups']);
$row['comment_user_groups_read'] = explode(',', $row['comment_user_groups_read']); /* <-- ПОЛУЧЕНИЕ НОВОГО ПОЛЯ */
// Передаем данные в шаблон и показываем страницу с настройками модуля
$AVE_Template->assign($row);
$AVE_Template->assign('content', $AVE_Template->fetch($tpl_dir . $this->_admin_settings_tpl));
}
}
?>