Начинаем изучать код файла "forums.posts.php" в Cotonti CMF, который находится в дириктории: /modules/forums/inc/ php-фреймворка.
<?php
/**
* Отображение постов форума.
*
* @package Forums
* @copyright (с) Cotonti Team
* @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
*/
// Проверка, что файл был включен через Cotonti (защита от прямого доступа).
defined('COT_CODE') or die('Неверный URL');
// Импортируем ID поста из параметров запроса (GET-запрос). Тип данных: целое число.
$id = cot_import('id', 'G', 'INT'); // ID поста
// Импортируем код категории раздела форума из параметров запроса (GET-запрос). Тип данных: текст.
$s = cot_import('s', 'G', 'TXT'); // Код категории раздела
// Импортируем ID темы из параметров запроса (GET-запрос). Тип данных: целое число.
$q = cot_import('q', 'G', 'INT'); // ID темы
// Импортируем ID поста для редактирования из параметров запроса (GET-запрос). Тип данных: целое число.
$p = cot_import('p', 'G', 'INT'); // ID поста
// Импортируем параметры пагинации (страница и другие данные) через функцию cot_import_pagenav.
// Эта функция также берет значение по умолчанию для максимального количества постов на странице.
list($pg, $d, $durl) = cot_import_pagenav('d', Cot::$cfg['forums']['maxpostsperpage']); // Параметры пагинации
// Импортируем параметр цитирования из запроса. Тип данных: целое число.
$quote = cot_import('quote', 'G', 'INT');
// Подключаем файл с языковыми строками для стран.
require_once cot_langfile('countries', 'core');
// Подключаем файл с функциями для обработки форм.
require_once cot_incfile('forms');
/* === Hook === */
// Выполнение плагинов на момент первого отображения постов. Это даёт возможность расширять функциональность через сторонние плагины.
foreach (cot_getextplugins('forums.posts.first') as $pl) {
include $pl; // Включаем каждый плагин.
}
/* ===== */
Объяснение кода:
- Защита от прямого доступа:
defined('COT_CODE') or die('Wrong URL');
Эта строка гарантирует, что скрипт может быть выполнен только в контексте Cotonti (когда файл был подключен через основной фреймворк). Если кто-то пытается получить доступ к файлу напрямую, выполнение будет остановлено. - Импорт параметров из URL:
Для получения данных из URL (GET-запрос) используется функция cot_import(). В нашем случае это различные параметры, такие как:$id: ID поста (целое число)$s: код раздела форума (строка)$q: ID темы (целое число)$p: ID поста для редактирования (целое число)$quote: ID цитируемого поста (целое число)
- Пагинация:
cot_import_pagenav() используется для обработки параметров пагинации. Функция получает данные о текущей странице, размере страницы и URL для пагинации. Это позволяет правильно разделить посты на несколько страниц и контролировать навигацию по ним. - Подключение файлов:
cot_langfile('countries', 'core') подключает языковой файл для стран, что может быть полезно для отображения информации о странах.cot_incfile('forms') подключает функции для работы с формами, что важно для обработки любых пользовательских данных, например, при отправке комментариев.
- Хук на первое отображение постов:
В данном участке кода выполняется подключение плагинов через хук forums.posts.first. Хуки позволяют расширять функциональность без изменения исходного кода — сторонние разработчики могут подключать свои плагины, которые будут выполняться на этом этапе.
В результате этот код создает основу для страницы отображения постов форума, подключает необходимые файлы и выполняет сторонние плагины для расширения функционала.
$fp_posterid = null; // Инициализация переменной для хранения ID автора поста, изначально она равна null.
if ((!empty($n) && !empty($q)) || !empty($p) || !empty($id)) { // Проверка, что хотя бы один из параметров n, q, p или id не пуст.
if (!empty($q) && ($n == 'last' || ($n == 'unread' && Cot::$usr['id'] == 0))) { // Если задан параметр темы (q) и нужно получить последний пост (n = 'last') или непрочитанный пост для неавторизованного пользователя (n = 'unread' и пользователь не авторизован).
// Запрос для получения последнего поста в теме.
$sql_forums = Cot::$db->query("SELECT fp_id, fp_topicid, fp_cat, fp_posterid FROM $db_forum_posts
WHERE fp_topicid = $q ORDER by fp_id DESC LIMIT 1");
} elseif ($n == 'unread' && !empty($q) && Cot::$usr['id'] > 0) { // Если нужно получить непрочитанный пост, и пользователь авторизован.
// Запрос для получения непрочитанного поста (по времени последнего посещения пользователя).
$sql_forums = Cot::$db->query("SELECT fp_id, fp_topicid, fp_cat, fp_posterid
FROM $db_forum_posts WHERE fp_topicid = $q AND fp_updated > " . Cot::$usr['lastvisit'] . " ORDER by fp_id ASC LIMIT 1");
if ($sql_forums->rowCount() == 0) { // Если постов нет, то ищем последний пост в теме.
$sql_forums = Cot::$db->query("SELECT fp_id, fp_topicid, fp_cat, fp_posterid FROM $db_forum_posts
WHERE fp_topicid = $q ORDER by fp_id DESC LIMIT 1");
}
} elseif (!empty($p) || !empty($id)) { // Если задан ID поста (p) или ID другого объекта (id), то выбираем конкретный пост.
$p = ($p > 0) ? $p : $id; // Если p больше 0, используем p, иначе используем id.
// Запрос для получения поста по его ID.
$sql_forums = Cot::$db->query("SELECT fp_id, fp_topicid, fp_cat, fp_posterid, fp_creation FROM $db_forum_posts WHERE fp_id = ?", $p);
}
// Если результат запроса существует и найден хотя бы один пост.
if (isset($sql_forums) && is_object($sql_forums) && $sql_forums->rowCount() > 0) {
// Извлекаем данные из найденного поста.
$row = $sql_forums->fetch();
$p = $row['fp_id']; // Присваиваем ID поста.
$q = $row['fp_topicid']; // Присваиваем ID темы.
$s = $row['fp_cat']; // Присваиваем ID категории раздела.
$fp_posterid = $row['fp_posterid']; // Присваиваем ID автора поста.
}
} elseif (!empty($q)) { // Если задан только параметр темы (q), то находим информацию о категории раздела темы.
// Запрос для получения категории раздела темы.
$sql_forums = Cot::$db->query("SELECT ft_cat FROM $db_forum_topics WHERE ft_id = $q LIMIT 1");
if ($row = $sql_forums->fetch()) { // Если тема найдена, извлекаем категорию.
$s = $row['ft_cat']; // Присваиваем категорию раздела.
}
}
Объяснение кода:
- Инициализация переменной
$fp_posterid = null;
Переменная $fp_posterid инициализируется значением null. Она будет использоваться для хранения ID пользователя, который является автором поста. - Основная логика проверки условий
Основная логика заключается в проверке различных значений параметров из URL ($n, $q, $p, $id) для того, чтобы понять, какой пост или тему нужно извлечь из базы данных. - Проверка условий для разных типов запросов:
- Последний или непрочитанный пост (для неавторизованных или авторизованных пользователей):
Если $n == 'last', то выбирается последний пост в теме (ORDER by fp_id DESC), а если $n == 'unread', то извлекается первый непрочитанный пост для авторизованных пользователей, используя их lastvisit (время последнего визита). Если таких постов нет, выбирается последний. - Конкретный пост:
Если задан параметр $p или $id, то извлекается пост с соответствующим ID. - Поиск по теме:
Если задан параметр темы $q, то ищется информация о категории раздела этой темы.
- Запросы к базе данных:
Для выполнения запроса к базе данных используется метод Cot::$db->query(). Он формирует SQL-запросы для получения данных о постах и темах.
В случае с непрочитанными постами запрос фильтрует результаты по времени последнего посещения пользователя. - Обработка результата запроса:
Если запрос возвращает хотя бы одну строку (пост), то из этой строки извлекаются необходимые данные: ID поста (fp_id), ID темы (fp_topicid), категория раздела (fp_cat), и ID автора поста (fp_posterid). - Резервный запрос для категории раздела:
Если задан только параметр темы ($q), но нет других параметров, то выполняется запрос для получения категории раздела темы.
Этот участок кода позволяет извлекать информацию о постах форума по различным параметрам, таким как ID темы, ID поста, последний непрочитанный пост и другие. код отвечает за извлечение данных о постах и теме в зависимости от параметров, переданных в URL, и обработку их для дальнейшего отображения на странице форума.
(empty($s)) && cot_die(true, true); // Если переменная $s пуста (т.е. не задан раздел форума), вызывается функция cot_die, которая завершает выполнение скрипта с сообщением об ошибке (параметры true, true означают завершение с фатальной ошибкой).
isset(Cot::$structure['forums'][$s]) || cot_die(true, true); // Проверяется, существует ли раздел форума с кодом $s в массиве Cot::$structure['forums']. Если раздел не существует, то также вызывается функция cot_die, завершая выполнение скрипта с ошибкой.
list(Cot::$usr['auth_read'], Cot::$usr['auth_write'], Cot::$usr['isadmin']) = cot_auth('forums', $s); // Получение прав доступа для текущего пользователя для данного форума:
// - auth_read — право на чтение,
// - auth_write — право на написание (создание постов),
// - isadmin — является ли пользователь администратором. Все эти значения сохраняются в соответствующих элементах массива Cot::$usr.
/* === Hook === */
foreach (cot_getextplugins('forums.posts.rights') as $pl) { // Вставка плагинов для расширения прав доступа (если такие есть).
include $pl; // Для каждого плагина, найденного функцией cot_getextplugins, подключается соответствующий файл плагина.
}
/* ===== */
cot_block(Cot::$usr['auth_read']); // Блокирует выполнение кода, если у пользователя нет прав на чтение форума. Если право чтения не подтверждено, скрипт завершится с ошибкой.
$sys['sublocation'] = Cot::$structure['forums'][$s]['title']; // Устанавливает подзаголовок страницы (sublocation) как название раздела форума, полученное из структуры форума (Cot::$structure['forums'][$s]['title']).
Объяснение:
- Проверка переменной
$s- Первая строка проверяет, что переменная
$s (код раздела форума) не пуста. Если она пуста, выполнение скрипта прекращается с ошибкой, вызванной функцией cot_die. - Вторая строка проверяет, существует ли раздел форума с данным кодом
$s в структуре форума. Если раздел не найден, выполнение также прекращается с ошибкой.
Получение прав доступа пользователя
Функция cot_auth используется для получения прав доступа пользователя к разделу форума. В зависимости от результата:
auth_read — право на чтение,auth_write — право на создание сообщений,isadmin — флаг, показывающий, является ли пользователь администратором.
Эти данные сохраняются в массиве Cot::$usr для дальнейшего использования.
- Расширение прав с помощью плагинов
Этот блок кода позволяет подключать плагины, которые могут изменять или добавлять дополнительные правила доступа для постов в разделе форума. Все найденные плагины в директории forums.posts.rights подключаются с помощью функции cot_getextplugins. - Блокировка доступа без прав
Функция cot_block используется для того, чтобы заблокировать доступ к странице, если у пользователя нет прав на чтение форума (Cot::$usr['auth_read']). Если прав нет, выполнение скрипта прекращается с ошибкой. - Установка подзаголовка
Переменная $sys['sublocation'] используется для установки подзаголовка страницы, который будет отображаться в интерфейсе. В данном случае подзаголовок устанавливается как название форума, взятое из структуры форума (Cot::$structure['forums'][$s]['title']).