Файл admin.extensions.php в Cotonti CMF
Файл "admin.extensions.php" в движке Cotonti CMF является важным компонентом административной части системы, предназначенным для работы с расширениями — модулями и плагинами. Он включает в себя обработку запросов, отображение информации об установленных расширениях, управление их состоянием, а также взаимодействие с базой данных и другими частями системы.
Основное назначение файла
Файл предназначен для управления расширениями в админ-панели сайта. Он выполняет несколько ключевых задач:
- Отображение списка установленных расширений: Файл выполняет запросы к базе данных, извлекает информацию о модулях и плагинах, отображает их пользователю с возможностью фильтрации и сортировки.
- Проверка состояния расширений: Файл проверяет, активны ли расширения, отображает их версии, количество установленных частей и настройки.
- Управление зависимостями: Он проверяет и отображает зависимости между расширениями (например, если плагин зависит от другого модуля или плагина).
- Взаимодействие с правами доступа: Для каждого расширения выводится информация о правах доступа, ограничениях для пользователей и других настройках безопасности.
- Хуки и плагины: Файл обрабатывает хуки, позволяя другим расширениям вставлять свой код в определенные места данного кода.
Основные задачи и условия, которые выполняет код
- Получение данных о расширениях: Код выполняет SQL-запросы для получения списка установленных расширений, их категорий, состояний и метаданных (версии, авторы, права доступа и т. д.).
- Фильтрация по статусу: Есть возможность фильтровать расширения по статусу (установлены или нет), а также сортировать их по категориям или алфавиту.
- Обработка ошибок: Если для расширения указана ошибка, она отображается пользователю в административной панели.
- Отображение и вывод информации: Файл использует шаблонный движок для вывода информации на странице (с помощью
$t->assignи$t->parse). - Интеграция с системой прав доступа: Интеграция с функцией
cot_auth_getmaskдля определения прав доступа для различных пользователей. - Подключение хуков: В коде имеются места для добавления внешнего кода через хуки, что позволяет расширить функциональность без изменения основного кода.
Список методов и функций
В данном фрагменте кода явно не определены собственные функции или методы, однако используются следующие системные функции и методы:
- cot_import() — для получения данных из входных параметров.
- cot_url() — для генерации URL на страницы административной панели.
- cot_extension_list_info() — для получения списка расширений.
- cot_getextplugins() — для получения списка подключенных плагинов (расширений).
- cot_langfile() — для загрузки языковых файлов.
- cot_get_extensionparams() — для получения параметров расширений.
- cot_plugin_active() — для проверки активности плагинов.
- cot_infoget() — для получения информации о расширениях.
Характеристика стиля PHP
- Использование шаблонного движка: В коде активно используется шаблонный движок для отображения данных. Через объект
$tвыполняются операции присваивания значений в шаблон и его парсинг ($t->assign,$t->parse). - Открытые и явные переменные: Применяется довольно явное объявление переменных и их использование. Код не сильно скрывает детали реализации, что делает его более прозрачным.
- Процедурный стиль программирования: В коде наблюдается доминирование процедурного подхода. В частности, используется множество прямых SQL-запросов, а также конструкций
ifиforeachдля обработки данных. - Использование современных PHP-функций: Код использует современные функции PHP, такие как
isset(),empty(), операторы типа??, массивы и работу с объектами. - Отсутствие ООП: В коде не наблюдается использования объектно-ориентированного подхода в чистом виде. Хотя используются объекты для работы с шаблонами и базой данных, большая часть логики выполняется в процедурной манере.
Резюме
Файл "admin.extensions.php" является важным элементом административной панели Cotonti, предназначенным для управления расширениями (модулями и плагинами). Он извлекает, отображает и управляет данными о расширениях, их зависимостями и состоянием, а также взаимодействует с правами доступа и системой безопасности. Код написан в процедурном стиле с активным использованием шаблонного движка для вывода данных и взаимодействия с пользователем.
находится по адресу: /system/admin/admin.extensions.php движка php-фреймворка Cotonti.
<?php
/**
* Extension administration
*
* @package Cotonti
* @copyright (c) Cotonti Team
* @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
*/
// Задается пространство имен и подключение необходимых классов для работы с расширениями
use cot\extensions\ExtensionsControlService; // Используется класс для управления расширениями
use cot\extensions\ExtensionsDictionary; // Используется класс для работы с базой данных расширений
use cot\extensions\ExtensionsService; // Используется класс для основной логики работы с расширениями
(defined('COT_CODE') && defined('COT_ADMIN')) or die('Wrong URL.'); // Проверка, что файл был вызван в правильном контексте, иначе ошибка
/**
* @var array $cot_plugins
*/
// Извлекаются права доступа текущего пользователя
list(Cot::$usr['auth_read'], Cot::$usr['auth_write'], Cot::$usr['isadmin']) = cot_auth('admin', 'a'); // Получение прав пользователя для раздела администрирования
cot_block(Cot::$usr['isadmin']); // Проверка, что у пользователя есть права администратора
require_once cot_incfile('auth'); // Подключение файла аутентификации для дополнительной проверки прав
$t = new XTemplate(cot_tplfile('admin.extensions', 'core')); // Создание экземпляра шаблонизатора для администрирования расширений
$adminPath[] = array (cot_url('admin', 'm=extensions'), Cot::$L['Extensions']); // Добавление ссылки на раздел расширений в путь навигации
$adminTitle = Cot::$L['Extensions']; // Установка заголовка страницы как "Расширения"
$pl = cot_import('pl', 'G', 'ALP'); // Получение параметра 'pl' из глобального массива GET (может быть названием плагина)
$mod = cot_import('mod', 'G', 'ALP'); // Получение параметра 'mod' из глобального массива GET (может быть названием модуля)
$part = cot_import('part', 'G', 'TXT'); // Получение параметра 'part' из глобального массива GET (часть или категория плагина)
$sort = cot_import('sort', 'G', 'ALP'); // Получение параметра 'sort' из глобального массива GET (параметр сортировки)
Этот участок кода отвечает за инициализацию страницы администрирования расширений, а также проверку прав доступа пользователя и подготовку данных для дальнейшей работы с расширениями в системе.
if (empty($mod)) { // Если переменная $mod пустая (нет модуля)
if (empty($pl)) { // Если переменная $pl пустая (нет плагина)
if (!empty($a) && $a != 'hooks') { // Если параметр $a существует и не равен 'hooks'
cot_die(); // Завершаем выполнение с ошибкой
}
} else { // Если передан плагин
$is_module = false; // Устанавливаем флаг, что это не модуль
$code = $pl; // Присваиваем название плагина переменной $code
$arg = 'pl'; // Устанавливаем тип как 'pl' (плагин)
$dir = Cot::$cfg['plugins_dir']; // Устанавливаем директорию плагинов
$type = ExtensionsDictionary::TYPE_PLUGIN; // Устанавливаем тип как плагин
}
} else { // Если передан модуль
$is_module = true; // Устанавливаем флаг, что это модуль
$code = $mod; // Присваиваем название модуля переменной $code
$arg = 'mod'; // Устанавливаем тип как 'mod' (модуль)
$dir = Cot::$cfg['modules_dir']; // Устанавливаем директорию модулей
$type = ExtensionsDictionary::TYPE_MODULE; // Устанавливаем тип как модуль
}
$status[0] = $R['admin_code_paused']; // Статус 'приостановлен'
$status[1] = $R['admin_code_running']; // Статус 'работает'
$status[2] = $R['admin_code_partrunning']; // Статус 'частично работает'
$status[3] = $R['admin_code_notinstalled']; // Статус 'не установлен'
$status[4] = $R['admin_code_missing']; // Статус 'отсутствует'
$found_txt[0] = $R['admin_code_missing']; // Текст для статуса 'отсутствует'
$found_txt[1] = $R['admin_code_present']; // Текст для статуса 'присутствует'
unset($disp_errors); // Удаляем переменную $disp_errors
$extensionsService = ExtensionsService::getInstance(); // Получаем экземпляр сервиса расширений
/* === Hook === */
foreach (cot_getextplugins('admin.extensions.first') as $pl) { // Включаем плагины, связанные с хуком 'admin.extensions.first'
include $pl; // Подключаем каждый плагин
}
/* ===== */
Этот участок кода отвечает за определение того, работает ли с плагином или модулем, а также за настройку статусов и текстов, которые используются для отображения состояния расширений в админке. В нем также настраивается использование хуков для подключения внешних плагинов.
switch($a) { // В зависимости от значения переменной $a, выполняем соответствующие действия
/* =============== */
case 'details': // Если значение $a равно 'details', выполняем следующий блок
/* =============== */
$extDir = $dir . '/' . $code; // Устанавливаем путь к директории расширения, комбинируя директорию и код расширения
if (!file_exists($extDir)) { // Если директория расширения не существует
cot_die_message(404); // Завершаем выполнение с ошибкой 404 (не найдено)
}
$ext_info = $extDir . '/' . $code . '.setup.php'; // Устанавливаем путь к файлу настроек расширения
$info = false; // Инициализируем переменную для информации о расширении как false
$exists = file_exists($ext_info); // Проверяем, существует ли файл настроек расширения
if ($exists) { // Если файл настроек существует
$old_ext_format = false; // Устанавливаем флаг старого формата в false
$info = cot_infoget($ext_info, 'COT_EXT'); // Загружаем информацию о расширении
if (!$info && cot_plugin_active('genoa')) { // Если информация не загружена и плагин 'genoa' активен
// Try to load old format info
$info = cot_infoget($ext_info, 'SED_EXTPLUGIN'); // Пытаемся загрузить информацию в старом формате
$old_ext_format = true; // Устанавливаем флаг старого формата в true
cot_message('ext_old_format', 'warning'); // Отправляем сообщение с предупреждением о старом формате
}
}
if ($info == false) { // Если информация о расширении не загружена
// Failed to load info block
// Lets use default data
$info = array( // Инициализируем массив с дефолтными данными для расширения
'Code' => $code,
'Name' => $code,
'Description' => '',
'Category' => '',
'Version' => '',
'Date' => '',
'Author' => '',
'Copyright' => '',
'Notes' => '',
'Auth_members' => '',
'Lock_members' => '',
'Auth_guests' => '',
'Lock_guests' => '',
'Requires_modules' => '',
'Requires_plugins' => '',
'Recommends_modules' => '',
'Recommends_plugins' => ''
);
}
$extensionControlService = ExtensionsControlService::getInstance(); // Получаем экземпляр сервиса управления расширениями
switch($b) { // В зависимости от значения переменной $b выполняем следующие действия
case 'install': // Если значение $b равно 'install', выполняем установку расширения
$installed_modules = $db->query("SELECT ct_code FROM $db_core WHERE ct_plug = 0")->fetchAll(PDO::FETCH_COLUMN); // Получаем все установленные модули
$installed_plugins = $db->query("SELECT ct_code FROM $db_core WHERE ct_plug = 1")->fetchAll(PDO::FETCH_COLUMN); // Получаем все установленные плагины
$dependencies_satisfied = cot_extension_dependencies_statisfied($code, $is_module, $installed_modules, $installed_plugins); // Проверяем удовлетворение зависимостей для расширения
if ($dependencies_satisfied) { // Если все зависимости удовлетворены
$result = cot_extension_install($code, $is_module); // Устанавливаем расширение
}
break;
case 'update': // Если значение $b равно 'update', выполняем обновление расширения
$result = cot_extension_install($code, $is_module, true, true); // Обновляем расширение
break;
Этот участок кода отвечает за обработку деталей расширений в админке. Он выполняет проверку существования расширения, загружает его информацию, а затем в зависимости от команды ($b) выполняет установку или обновление расширения, учитывая зависимости.
$info = array( // Инициализируем массив с дефолтными данными для расширения
'Code' => $code, // Код расширения, который равен переменной $code
'Name' => $code, // Имя расширения, которое также равно переменной $code
'Description' => '', // Пустое описание расширения
'Category' => '', // Пустая категория расширения
'Version' => '', // Пустая версия расширения
'Date' => '', // Пустая дата расширения
'Author' => '', // Пустое имя автора расширения
'Copyright' => '', // Пустое поле для информации о копирайте
'Notes' => '', // Пустые заметки для расширения
'Auth_members' => '', // Пустой доступ для зарегистрированных пользователей
'Lock_members' => '', // Пустая блокировка для зарегистрированных пользователей
'Auth_guests' => '', // Пустой доступ для гостей
'Lock_guests' => '', // Пустая блокировка для гостей
'Requires_modules' => '', // Пустые требования для модулей
'Requires_plugins' => '', // Пустые требования для плагинов
'Recommends_modules' => '', // Пустые рекомендации для модулей
'Recommends_plugins' => '' // Пустые рекомендации для плагинов
);
case 'uninstall': // Обрабатываем случай, когда требуется удалить расширение
/* === Hook === */
foreach (cot_getextplugins('admin.extensions.uninstall.first') as $pl) { // Запускаем плагины, связанные с процессом деинсталляции
include $pl; // Подключаем плагин
}
/* ===== */
if (cot_check_xg(false)) { // Проверяем, если запрос прошел проверку X-Token
// Check if there are extensions installed depending on this one
$dependencies_satisfied = true; // Переменная для проверки зависимостей
$res = $db->query("SELECT ct_code, ct_plug FROM $db_core ORDER BY ct_plug, ct_code"); // Получаем все расширения из базы данных
foreach ($res->fetchAll() as $row) { // Перебираем все расширения
$ext = $row['ct_code']; // Код текущего расширения
$dir_ext = $row['ct_plug'] ? Cot::$cfg['plugins_dir'] : Cot::$cfg['modules_dir']; // Определяем путь к плагину или модулю
$dep_ext_info = $dir_ext . '/' . $ext . '/' . $ext . '.setup.php'; // Путь к файлу setup.php расширения
if (file_exists($dep_ext_info)) { // Проверяем, существует ли файл setup.php для зависимого расширения
$dep_info = cot_infoget($dep_ext_info, 'COT_EXT'); // Получаем информацию о расширении
if (!$dep_info && cot_plugin_active('genoa')) { // Если информация не найдена и плагин 'genoa' активен
// Try to load old format info
$dep_info = cot_infoget($dep_ext_info, 'SED_EXTPLUGIN'); // Пробуем загрузить информацию в старом формате
}
$dep_field = $is_module ? 'Requires_modules' : 'Requires_plugins'; // Определяем поле для зависимостей
if (in_array($code, explode(',', $dep_info[$dep_field]))) { // Если текущее расширение указано как зависимость
cot_error(cot_rc('ext_dependency_uninstall_error', array( // Выводим ошибку о зависимости
'type' => $row['ct_plug'] ? Cot::$L['Plugin'] : Cot::$L['Module'], // Указываем тип (плагин или модуль)
'name' => $dep_info['Name'] // Указываем имя зависимого расширения
)));
$dependencies_satisfied = false; // Устанавливаем флаг зависимости как неудовлетворенную
}
}
}
if ($dependencies_satisfied) { // Если все зависимости удовлетворены
$result = cot_extension_uninstall($code, $is_module); // Выполняем деинсталляцию расширения
}
$adminPath[] = Cot::$L['adm_opt_uninstall']; // Добавляем ссылку на деинсталляцию в путь навигации
} else { // Если проверка X-Token не пройдена
$url = cot_url('admin', "m=extensions&a=details&$arg=$code&b=uninstall&x={$sys['xk']}"); // Формируем URL для подтверждения деинсталляции
cot_message(cot_rc('ext_uninstall_confirm', array('url' => $url)), 'error'); // Показываем сообщение об ошибке с ссылкой на подтверждение
cot_redirect(cot_url('admin', "m=extensions&a=details&$arg=$code", '', true)); // Перенаправляем на страницу с расширением
}
break;
Объяснение:
- Этот блок кода обрабатывает запрос на удаление расширения (модуль или плагин).
- Если проверка X-Token проходит, происходит проверка зависимостей расширений: если текущее расширение зависит от других, которые ещё не удалены, выводится ошибка.
- Если зависимости удовлетворены, расширение деинсталлируется, иначе отображается ошибка.
- Если проверка X-Token не проходит, система предлагает пользователю подтвердить удаление расширения по предоставленной ссылке.
case 'pause': // Обрабатываем запрос на паузу расширения
$extensionControlService->pause($code); // Приостанавливаем расширение по коду
cot_message('adm_paused'); // Показываем сообщение о приостановке
break;
case 'unpause': // Обрабатываем запрос на возобновление работы расширения
$extensionControlService->resume($code); // Возобновляем работу расширения по коду
cot_message('adm_running'); // Показываем сообщение о возобновлении работы
break;
case 'pausepart': // Обрабатываем запрос на приостановку части расширения
$extensionControlService->pause($code, $part); // Приостанавливаем часть расширения по коду и части
cot_message('adm_partstopped'); // Показываем сообщение о приостановке части
break;
case 'unpausepart': // Обрабатываем запрос на возобновление работы части расширения
$extensionControlService->resume($code, $part); // Возобновляем работу части расширения по коду и части
cot_message('adm_partrunning'); // Показываем сообщение о возобновлении работы части
break;
} // закрываем switch($b)
Объяснение:
- В этом участке кода обрабатываются запросы на изменение состояния расширений: приостановка и возобновление работы.
- Каждый из случаев (pause, unpause, pausepart, unpausepart) вызывает соответствующий метод
pause()илиresume()в сервисе управления расширениями и выводит сообщение о результате действия.
if (!empty($b)) { // Если переменная $b не пуста
Cot::$db->update(Cot::$db->users, array('user_auth' => ''), "user_auth != ''"); // Обновляем записи в таблице пользователей, сбрасывая авторизацию
if (Cot::$cache) { // Если существует кэш
Cot::$cache->clear(); // Очищаем кэш
}
cot_redirect(cot_url('admin', "m=extensions&a=details&$arg=$code", '', true)); // Перенаправляем на страницу деталей расширения
}
$registeredParts = []; // Инициализируем пустой массив для зарегистрированных частей расширения
$parts = []; // Инициализируем пустой массив для частей расширения
if ($exists) { // Если расширение существует
// Собираем все части из директории расширения
$handle = opendir($dir . '/' . $code); // Открываем директорию расширения
while ($f = readdir($handle)) { // Читаем файлы в директории
if (
preg_match("#^$code(\.([\w\.]+))?.php$#", $f, $mt) // Проверяем, соответствует ли имя файла шаблону
&& (!isset($mt[2]) || !in_array($mt[2], $cot_ext_ignore_parts)) // И проверяем, что часть не находится в списке игнорируемых
) {
$parts[] = $f; // Добавляем файл в массив частей
}
}
closedir($handle); // Закрываем директорию
// ...И собираем части из базы данных
// Может быть несколько записей с одинаковым pl_part. Одна для каждого хука (для частей с несколькими хуками).
// Но все они содержат информацию о одном и том же расширении. Таблица не нормализована.
$registeredParts = []; // Инициализируем массив для зарегистрированных частей
$query = Cot::$db->query(
'SELECT * FROM ' . Cot::$db->plugins . ' WHERE pl_code = :code', // Запрашиваем все части для данного расширения
['code' => $code] // Параметр для запроса
);
while ($row = $query->fetch()) { // Для каждой записи
if (!isset($registeredParts[$row['pl_part']]['hooks'])) { // Если еще не существует ключа для хуков в данной части
$registeredParts[$row['pl_part']]['hooks'] = []; // Инициализируем массив для хуков
}
$registeredParts[$row['pl_part']]['hooks'][$row['pl_hook']] = [ // Добавляем хук в массив
'hook' => $row['pl_hook'],
'order' => (int) $row['pl_order'], // Сохраняем порядок хуков
];
unset($row['pl_hook'], $row['pl_order']); // Убираем ненужные данные
$registeredParts[$row['pl_part']] = array_merge($registeredParts[$row['pl_part']], $row); // Мержим данные с остальными частями
}
$query->closeCursor(); // Закрываем курсор запроса
// Дополняем список частей расширения, если оно не зарегистрировано
foreach ($registeredParts as $reg_data) {
if ($reg_data['pl_code'] == $code) { // Если код расширения совпадает
$f = str_replace($code . '/', '', $reg_data['pl_file']); // Извлекаем имя файла без пути
if (!in_array($f, $parts)) { // Если части ещё нет в массиве
$parts[] = $f; // Добавляем часть в массив
}
}
}
// Получаем значения прав доступа для членов и гостей
$info['Auth_members'] = cot_auth_getvalue($info['Auth_members']);
$info['Lock_members'] = cot_auth_getvalue($info['Lock_members']);
$info['Auth_guests'] = cot_auth_getvalue($info['Auth_guests']);
$info['Lock_guests'] = cot_auth_getvalue($info['Lock_guests']);
} else { // Если расширение не существует в директории
$row = Cot::$db->query('SELECT * FROM ' . Cot::$db->core . ' WHERE ct_code = '.
Cot::$db->quote($code))->fetch(); // Запрашиваем данные о расширении из основной таблицы
if ($row) { // Если запись найдена
$info['Name'] = $row['ct_title']; // Присваиваем название расширения
$info['Version'] = $row['ct_version']; // Присваиваем версию расширения
}
}
Объяснение:
- В этом участке кода происходит проверка состояния расширения, сбор информации о его частях как из файловой системы, так и из базы данных.
- В случае наличия переменной
$b, очищается кэш и происходит перенаправление на страницу расширения. - Собираются части расширения как из файловой системы, так и из базы данных, а также проверяются зависимости между ними.
- Данные о расширении, такие как права доступа для участников и гостей, обновляются через функции
cot_auth_getvalue. - Если расширение не найдено в директории, производится запрос к основной таблице для получения информации.
$ext_info = cot_get_extensionparams($code, $is_module); // Получаем параметры расширения с указанным кодом и типом (модуль или плагин)
$adminPath[] = [cot_url('admin', ['m' => 'extensions', 'a' => 'details', $arg => $code]), $ext_info['name']]; // Добавляем ссылку на страницу деталей расширения в путь навигации, используя имя расширения
$isInstalled = $extensionsService->isInstalled($code, $type, true); // Проверяем, установлено ли расширение с указанным кодом и типом (модуль или плагин)
$sql = Cot::$db->query(
'SELECT COUNT(*) FROM ' . Cot::$db->config . ' WHERE config_owner = :type AND config_cat = :code ' // Запрашиваем количество конфигураций для данного типа расширения (модуль/плагин) и его кода
. 'AND config_type NOT IN (' . COT_CONFIG_TYPE_HIDDEN . ', ' . COT_CONFIG_TYPE_SEPARATOR . ') ' // Исключаем конфигурации типа скрытого и разделителя
. "AND (config_subcat IN ('', '__default') OR config_subcat IS NULL)", // Учитываем только конфигурации с пустым или дефолтным подкатегориями
['type' => $type, 'code' => $code] // Параметры для запроса (тип и код расширения)
);
$totalConfig = $sql->fetchColumn(); // Получаем количество таких конфигураций
Объяснение:
- Этот участок кода выполняет несколько ключевых действий:
- Получает параметры расширения с помощью
cot_get_extensionparamsи добавляет ссылку на страницу подробностей этого расширения в навигационный путь. - Проверяет, установлено ли расширение через сервис
ExtensionsService. - Выполняет SQL-запрос к базе данных для подсчета количества конфигураций, связанных с данным расширением, с исключением определенных типов конфигураций (скрытые и разделители).
- Получает параметры расширения с помощью
if (count($parts) > 0) { // Если количество элементов в массиве $parts больше 0 (т.е. есть части для обработки)
sort($parts); // Сортируем массив $parts в порядке возрастания
/* === Hook - Part1 : Set === */
$extp = cot_getextplugins('admin.extensions.details.part.loop'); // Получаем плагины, которые подключаются к хуку 'admin.extensions.details.part.loop'
/* ===== */
foreach ($parts as $i => $x) { // Для каждой части в массиве $parts
$extplugin_file = $dir . '/' . $code . '/' . $x; // Формируем полный путь к файлу плагина, добавляя код расширения и часть
$extensionPart = []; // Инициализируем пустой массив для данных части расширения
if (file_exists($extplugin_file)) { // Если файл существует
$extensionPart = cot_infoget($extplugin_file, 'COT_EXT'); // Получаем информацию о расширении из файла с помощью функции cot_infoget
$hooks = explode(',', $extensionPart['Hooks']); // Разделяем строку хуков на массив по запятой
$extensionPart['Hooks'] = []; // Инициализируем пустой массив для хуков
$hookOrders = (isset($extensionPart['Order']) && $extensionPart['Order'] !== '') // Если указаны порядки хуков
? explode(',', $extensionPart['Order']) // Разделяем строку порядков хуков по запятой
: []; // Если порядок не указан, создаем пустой массив
$hookOrders = array_map(function($el) { return (int) trim($el); }, $hookOrders); // Преобразуем элементы массива $hookOrders в целые числа и удаляем лишние пробелы
foreach ($hooks as $key => $hook) { // Для каждого хука
$hook = trim($hook); // Убираем лишние пробелы вокруг хука
if (empty($hook)) { // Если хук пустой
continue; // Пропускаем текущую итерацию
}
$extensionPart['Hooks'][$hook] = [ // Добавляем хук в массив хуков
'hook' => $hook, // Указываем сам хук
'order' => isset($hookOrders[$key]) ? (int) $hookOrders[$key] : COT_PLUGIN_DEFAULT_ORDER, // Указываем порядок хука (по умолчанию COT_PLUGIN_DEFAULT_ORDER)
];
}
unset($hooks, $hookOrders); // Удаляем временные переменные $hooks и $hookOrders
}
if (empty($extensionPart['Hooks'])) { // Если массив хуков пустой
$extensionPart['Hooks'] = []; // Инициализируем его как пустой массив
}
$info_part = preg_match("#^$code\.([\w\.]+).php$#", $x, $mt) ? $mt[1] : 'main'; // Проверяем, соответствует ли имя файла расширения шаблону и извлекаем часть, иначе присваиваем 'main'
$extensionPart['Status'] = 3; // Устанавливаем статус части расширения по умолчанию в 3 (не установлена)
$extensionPart['installedOrder'] = null; // Устанавливаем порядок установки части как null
if (isset($registeredParts[$info_part])) { // Если эта часть уже зарегистрирована
$extensionPart['Status'] = $registeredParts[$info_part]['pl_active']; // Присваиваем статус части на основе данных о зарегистрированной части
}
// проверка на незарегистрированные хуки
$not_registred = []; // Инициализируем пустой массив для незарегистрированных хуков
if ($extensionPart['Status'] == 1) { // Если часть активна (статус 1)
foreach ($extensionPart['Hooks'] as $hook) { // Для каждого хука в массиве хуков
$regsistred_by_hook = isset($cot_plugins[$hook['hook']]) ? $cot_plugins[$hook['hook']] : null; // Получаем плагины, зарегистрированные для этого хука
if (is_array($regsistred_by_hook) && sizeof($regsistred_by_hook)) { // Если для хука есть зарегистрированные плагины
$found = false; // Инициализируем флаг, который будет указывать на нахождение плагина
foreach ($regsistred_by_hook as $reg_data) { // Для каждого зарегистрированного плагина
if ($reg_data['pl_file'] == $code . '/' . $x) { // Если путь к файлу плагина совпадает с текущим расширением
$found = true; // Устанавливаем флаг в true
break; // Выходим из цикла
}
}
if (!$found) { // Если плагин не найден среди зарегистрированных
$not_registred[] = $hook['hook']; // Добавляем хук в массив незарегистрированных
}
} else {
$not_registred[] = $hook['hook']; // Если для хука нет зарегистрированных плагинов, добавляем его в массив незарегистрированных
}
}
}
$deleted = []; // Инициализируем пустой массив для удалённых хуков
// проверка на удалённые хуки
if (file_exists($extplugin_file)) { // Если файл плагина существует
foreach ($registeredParts as $reg_data) { // Для каждого зарегистрированного элемента
if ($reg_data['pl_file'] !== $code . '/' . $x) { // Если файл плагина не соответствует текущему
continue; // Пропускаем эту итерацию цикла
}
foreach ($reg_data['hooks'] as $registeredHook) { // Для каждого зарегистрированного хука
if (!isset($extensionPart['Hooks'][$registeredHook['hook']])) { // Если хук не найден в текущем расширении
$deleted[] = $registeredHook['hook']; // Добавляем хук в массив удалённых
}
}
}
}
if ($isInstalled && (!file_exists($extplugin_file)) || sizeof($deleted) > 0 || sizeof($not_registred) > 0) { // Если расширение установлено, но файл плагина отсутствует, или есть удалённые/незарегистрированные хуки
$extensionPart['Error'] = Cot::$L['adm_hook_changed']; // Устанавливаем сообщение об ошибке, что хуки были изменены
if (sizeof($not_registred)) { // Если есть незарегистрированные хуки
$extensionPart['Error'] .= cot_rc('adm_hook_notregistered', array('hooks' => implode(', ', $not_registred))); // Добавляем сообщение об незарегистрированных хуках
}
if (sizeof($deleted)) { // Если есть удалённые хуки
$extensionPart['Error'] .= cot_rc('adm_hook_notfound', ['hooks' => implode(', ', $deleted)]); // Добавляем сообщение об удалённых хуках
}
if (!file_exists($extplugin_file)) { // Если файл плагина не найден
$extensionPart['Error'] .= cot_rc('adm_hook_filenotfound', array('file' => $extplugin_file)); // Добавляем сообщение о том, что файл плагина не найден
}
$extensionPart['Error'] .= Cot::$L['adm_hook_updatenote']; // Добавляем уведомление о необходимости обновления
}
$hooks = ''; // Инициализируем переменную для хранения хуков
if (!empty($extensionPart['Hooks'])) { // Если хуки существуют
$hooks = implode('<br />', array_column($extensionPart['Hooks'], 'hook')); // Собираем список хуков, разделённых переносами строк
}
$installedHooks = ''; // Инициализируем переменную для установленных хуков
if (!empty($registeredParts[$info_part])) { // Если для данной части расширения есть зарегистрированные хуки
$installedHooks = implode('<br />', array_column($registeredParts[$info_part]['hooks'], 'hook')); // Собираем список установленных хуков
}
if (!empty($extensionPart['Error'])) { // Если есть ошибки в расширении
$t->assign([ // Присваиваем значения в шаблон для отображения ошибок
'ADMIN_EXTENSIONS_DETAILS_ROW_I_1' => $i+1, // Индекс строки, увеличенный на 1 (для отображения в шаблоне)
'ADMIN_EXTENSIONS_DETAILS_ROW_PART' => $info_part, // Информация о части расширения
'ADMIN_EXTENSIONS_DETAILS_ROW_HOOKS' => $hooks, // Хуки, указанные в расширении
'ADMIN_EXTENSIONS_DETAILS_ROW_HOOKS_INSTALLED' => $installedHooks, // Установленные хуки
'ADMIN_EXTENSIONS_DETAILS_ROW_FILE' => $x, // Имя файла расширения
'ADMIN_EXTENSIONS_DETAILS_ROW_ERROR' => $extensionPart['Error'], // Сообщение об ошибке
]);
$t->parse('MAIN.DETAILS.ROW_ERROR_PART'); // Парсим шаблон строки с ошибкой
} else { // Если нет ошибок в расширении
В этом участке кода происходит проверка на наличие ошибок в расширении. Если ошибки есть, данные об ошибке, хука, файле и другие параметры передаются в шаблон для отображения. Если ошибок нет, выполнение кода продолжается дальше.
if (empty($extensionPart['Tags'])) { // Если нет тегов в расширении
$t->assign([ // Присваиваем в шаблон информацию об ошибке для отсутствия тегов
'ADMIN_EXTENSIONS_DETAILS_ROW_I_1' => $i+1, // Индекс строки, увеличенный на 1
'ADMIN_EXTENSIONS_DETAILS_ROW_PART' => $info_part, // Информация о части расширения
]);
$t->parse('MAIN.DETAILS.ROW_ERROR_TAGS'); // Парсим шаблон строки с ошибкой для тегов
} else { // Если теги присутствуют
$taggroups = explode(';', $extensionPart['Tags']); // Разбиваем теги по группам
foreach ($taggroups as $taggroup) { // Для каждой группы тегов
$line = explode(':', $taggroup); // Разбиваем группу на имя шаблона и список тегов
$line[0] = trim($line[0]); // Убираем лишние пробелы в имени шаблона
$tplbase = explode('.', preg_replace('#\.tpl$#i', '', $line[0])); // Получаем базовое имя шаблона без расширения
// Определяем тип контейнера шаблона
if (in_array($tplbase[0], array('admin', 'users'))) {
$tpltype = 'core'; // Тип шаблона - ядро
} elseif (file_exists(Cot::$cfg['plugins_dir'] . '/' . $tplbase[0])) {
$tpltype = 'plug'; // Тип шаблона - плагин
} else {
$tpltype = 'module'; // Тип шаблона - модуль
}
$tags = explode(',', $line[1]); // Разбиваем теги по запятой
$tpl_file = cot_tplfile($tplbase, $tpltype); // Получаем путь к файлу шаблона
$listtags = $tpl_file.' :<br />'; // Начинаем список тегов
if (Cot::$cfg['xtpl_cache']) { // Если включен кэш шаблонов
// Очищаем кэш, если он существует
$cache_file = str_replace(array('./', '/'), '_', $tpl_file);
$cache_path = Cot::$cfg['cache_dir'] . '/templates/' .
pathinfo($cache_file, PATHINFO_FILENAME );
$cache_files_ext = array('.tpl','.idx','.tags'); // Расширения файлов кэша
foreach ($cache_files_ext as $ext) { // Для каждого расширения кэшированных файлов
if (file_exists($cache_path.$ext)) {
unlink($cache_path.$ext); // Удаляем кэшированные файлы
}
}
}
$tpl_check = new XTemplate($tpl_file); // Загружаем шаблон для проверки тегов
$tpl_tags = $tpl_check->getTags(); // Получаем теги шаблона
unset($tpl_tags[array_search('PHP', $tpl_tags)]); // Удаляем тег 'PHP' из списка тегов
foreach($tags as $k => $v) { // Для каждого тега в группе
if(mb_substr(trim($v), 0, 1) == '{') { // Если тег начинается с '{'
$tag = str_replace(array('{','}'),'',$v); // Убираем скобки из тега
$found = in_array($tag, $tpl_tags); // Проверяем, найден ли тег в шаблоне
$listtags .= $v.' : '; // Добавляем тег в список
$listtags .= $found_txt[$found].'<br />'; // Добавляем статус нахождения тега
} else { // Если тег не содержит фигурные скобки
$listtags .= $v.'<br />'; // Добавляем тег в список
}
}
$t->assign([ // Присваиваем данные в шаблон для отображения тегов
'ADMIN_EXTENSIONS_DETAILS_ROW_I_1' => $i + 1, // Индекс строки
'ADMIN_EXTENSIONS_DETAILS_ROW_PART' => $info_part, // Информация о части расширения
'ADMIN_EXTENSIONS_DETAILS_ROW_FILE' => $line[0].' :<br />', // Имя шаблона
'ADMIN_EXTENSIONS_DETAILS_ROW_LISTTAGS' => $listtags, // Список тегов
]);
$t->parse('MAIN.DETAILS.ROW_TAGS'); // Парсим шаблон строки с тегами
}
}
В этом участке кода происходит обработка тегов, указанных в расширении. Если теги присутствуют, они обрабатываются и проверяются на наличие в шаблоне, при этом очищается кэш шаблонов (если это необходимо). Результаты добавляются в шаблон для отображения информации о тегах и их статусе.
Если теги отсутствуют, выводится соответствующее сообщение об ошибке.
$order = array_column($extensionPart['Hooks'], 'order'); // Извлекаем массив значений порядка (order) из хуков расширения
$installedOrder = !empty($registeredParts[$info_part]) ? // Проверяем, если зарегистрированная часть расширения существует
array_column($registeredParts[$info_part]['hooks'], 'order') // Извлекаем порядок хуков для зарегистрированной части
: ''; // Если нет, устанавливаем пустую строку
if (empty($installedOrder) || count($order) === count($installedOrder)) { // Если порядок установлен, или их количество совпадает
if (min($order) === max($order)) { // Если минимальный и максимальный порядок одинаковы
$order = $order[0]; // Устанавливаем порядок равным единственному значению
}
if (!empty($installedOrder) && min($installedOrder) === max($installedOrder)) { // Если установлен порядок для зарегистрированных хуков
$installedOrder = $installedOrder[0]; // Устанавливаем его в единственное значение
}
}
if (is_array($order)) { // Если порядок является массивом
$order = implode(', ', $order); // Преобразуем его в строку, разделённую запятой
}
if (is_array($installedOrder)) { // Если установлен порядок для зарегистрированных хуков как массив
$installedOrder = !empty($installedOrder) ? implode(', ', $installedOrder) : null; // Преобразуем в строку или null, если пусто
}
$t->assign([ // Присваиваем данные в шаблон для отображения информации о расширении
'ADMIN_EXTENSIONS_DETAILS_ROW_I_1' => $i + 1, // Индекс строки
'ADMIN_EXTENSIONS_DETAILS_ROW_PART' => $info_part, // Информация о части расширения
'ADMIN_EXTENSIONS_DETAILS_ROW_FILE' => $x, // Имя файла
'ADMIN_EXTENSIONS_DETAILS_ROW_HOOKS' => $hooks, // Список хуков
'ADMIN_EXTENSIONS_DETAILS_ROW_HOOKS_INSTALLED' => $installedHooks, // Список установленных хуков
'ADMIN_EXTENSIONS_DETAILS_ROW_ORDER' => $order, // Порядок хуков в расширении
'ADMIN_EXTENSIONS_DETAILS_ROW_ORDER_INSTALLED' => $installedOrder, // Порядок установленных хуков
'ADMIN_EXTENSIONS_DETAILS_ROW_STATUS' => $status[$extensionPart['Status']], // Статус расширения
//'ADMIN_EXTENSIONS_DETAILS_ROW_PART_ODDEVEN' => cot_build_oddeven($ii) // Строка для чётности/нечётности (закомментировано)
]);
В этом участке кода происходит обработка порядка хуков (order). Если для расширения и зарегистрированной части порядок совпадает, он приводится к единому значению. Порядок хуков конвертируется в строку, если это массив. После этого данные о расширении, включая порядок хуков, устанавливаются в шаблон для дальнейшего отображения.
if ($extensionPart['Status'] == 3) { // Если статус расширения равен 3 (не установлено)
$t->parse('MAIN.DETAILS.ROW_PART.ROW_PART_NOTINSTALLED'); // Загружаем шаблон для отображения состояния "не установлено"
} elseif ($extensionPart['Status'] == 1) { // Если статус равен 1 (пауза)
$t->assign('ADMIN_EXTENSIONS_DETAILS_ROW_PAUSEPART_URL', // Присваиваем URL для действия "пауза" для части расширения
cot_url('admin', "m=extensions&a=details&$arg=$code&b=pausepart&part=".$info_part));
$t->parse('MAIN.DETAILS.ROW_PART.ROW_PART_PAUSE'); // Загружаем шаблон для состояния "пауза"
} elseif($extensionPart['Status'] == 0) { // Если статус равен 0 (не в паузе)
$t->assign('ADMIN_EXTENSIONS_DETAILS_ROW_UNPAUSEPART_URL', // Присваиваем URL для действия "отпаузить" для части расширения
cot_url('admin', "m=extensions&a=details&$arg=$code&b=unpausepart&part=".$info_part));
$t->parse('MAIN.DETAILS.ROW_PART.ROW_PART_UNPAUSE'); // Загружаем шаблон для состояния "не в паузе"
}
/* === Hook - Part2 : Include === */
foreach ($extp as $pl) { // Для каждого расширения из плагинов
include $pl; // Включаем плагин
}
/* ===== */
$t->parse('MAIN.DETAILS.ROW_PART'); // Загружаем шаблон для части расширения
В этом участке кода проверяется статус части расширения. В зависимости от статуса (не установлено, на паузе, не на паузе) генерируется URL для дальнейших действий и соответствующие шаблоны загружаются для отображения. Также подключаются внешние плагины, если таковые есть.
} } }
Этот блок закрывает несколько структур:
-
Цикл
foreach ($parts as $i => $x)— он заканчивает обход всех элементов массива$parts, то есть завершает обработку всех частей расширений. -
Условие
if (count($parts) > 0)— если в начале кода был список частей, то этотifпроверяет, что в массиве$partsесть элементы, и весь код внутри этого блока выполняется только если массив не пуст. Эта закрывающая скобка завершает его работу.
В результате, данный участок завершает выполнение основной логики работы с частями расширений и закрывает все активные циклы и условия в этом коде.
$structurePartUrl = null; // Инициализация переменной для хранения URL структуры, изначально пусто
$extensionsWithStructure = cot_getExtensionsWithStructure(); // Получение списка расширений, связанных с структурой
if (in_array($code, $extensionsWithStructure, true)) { // Проверка, есть ли текущее расширение в списке расширений со структурой
$structurePartUrl = cot_url('admin', ['m' => 'structure', 'n' => $code]); // Если да, формируется URL для структуры
}
$installed_ver = Cot::$db->query( // Запрос к базе данных для получения версии установленного расширения
'SELECT ct_version FROM ' . Cot::$db->core . ' WHERE ct_code = :code', // Запрос к таблице для получения версии по коду расширения
['code' => $code] // Параметры запроса, код расширения
)->fetchColumn(); // Извлекаем единственное значение — версию
$params = cot_get_extensionparams($code, $type === ExtensionsDictionary::TYPE_MODULE); // Получение параметров для расширения в зависимости от типа
$extensionCategoryTitle = ''; // Инициализация переменной для хранения названия категории расширения
if (!empty($info['Category'])) { // Если категория расширения не пуста
$extensionCategoryTitle = Cot::$L['ext_cat_' . $info['Category']] ?? $info['Category']; // Присваиваем название категории или использует значение категории, если нет перевода
}
Здесь реализована логика получения информации о расширении, включая формирование URL для структуры, извлечение версии расширения из базы данных и обработку категории расширения.
// Universal tags
$t->assign([
'ADMIN_EXTENSIONS_NAME' => htmlspecialchars($params['name']), // Название расширения, экранированное для безопасности
'ADMIN_EXTENSIONS_TYPE' => $type === ExtensionsDictionary::TYPE_MODULE
? Cot::$L['Module'] // Тип расширения: "Module" или "Plugin", в зависимости от типа
: Cot::$L['Plugin'],
'ADMIN_EXTENSIONS_CODE' => $code, // Код расширения
'ADMIN_EXTENSIONS_ICON' => $params['icon'], // Иконка расширения
'ADMIN_EXTENSIONS_DESCRIPTION' => $params['desc'], // Описание расширения
'ADMIN_EXTENSIONS_NOTES' => $params['notes'], // Примечания к расширению
'ADMIN_EXTENSIONS_CATEGORY' => $info['Category'], // Категория расширения
'ADMIN_EXTENSIONS_CATEGORY_TITLE' => $extensionCategoryTitle, // Заголовок категории
'ADMIN_EXTENSIONS_VERSION' => $info['Version'], // Версия расширения
'ADMIN_EXTENSIONS_VERSION_INSTALLED' => $installed_ver, // Установленная версия расширения
'ADMIN_EXTENSIONS_VERSION_COMPARE' => version_compare($info['Version'], $installed_ver), // Сравнение текущей версии с установленной
'ADMIN_EXTENSIONS_DATE' => $info['Date'], // Дата релиза расширения
'ADMIN_EXTENSIONS_CONFIG_URL' => cot_url(
'admin',
['m' => 'config', 'n' => 'edit', 'o' => $type, 'p' => $code]
), // URL для настройки расширения
'ADMIN_EXTENSIONS_ADMIN_URL' => $extensionsService->getAdminPageUrl($code, $type), // Административный URL для расширения
'ADMIN_EXTENSIONS_JUMPTO_URL' => $extensionsService->getPublicPageUrl($code, $type), // Публичный URL для расширения
'ADMIN_EXTENSIONS_STRUCTURE_URL' => $structurePartUrl, // URL для структуры расширения
'ADMIN_EXTENSIONS_TOTALCONFIG' => $totalConfig, // Общая конфигурация
'ADMIN_EXTENSIONS_INSTALL_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=install"), // URL для установки
'ADMIN_EXTENSIONS_UPDATE_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=update"), // URL для обновления
'ADMIN_EXTENSIONS_UNINSTALL_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=uninstall"), // URL для удаления
'ADMIN_EXTENSIONS_UNINSTALL_CONFIRM_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=uninstall&x={$sys['xk']}"), // URL для подтверждения удаления
'ADMIN_EXTENSIONS_PAUSE_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=pause"), // URL для приостановки
'ADMIN_EXTENSIONS_UNPAUSE_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code&b=unpause"), // URL для возобновления
]);
// Если включен режим совместимости (legacy mode)
if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) {
$t->assign([
// @deprecated Для обратной совместимости. Будет удалено в будущих версиях
'ADMIN_EXTENSIONS_ICO' => $params['legacyIcon'], // Иконка для устаревших версий
/** @deprecated in 0.9.26 */
'ADMIN_EXTENSIONS_JUMPTO_URL_TOOLS' => $extensionsService->getAdminPageUrl($code, $type), // URL для инструментов расширения (устаревший)
'ADMIN_EXTENSIONS_JUMPTO_URL_STRUCT' => $structurePartUrl, // URL для структуры расширения (устаревший)
]);
}
if ($exists) { // Проверяем, существует ли расширение
// Tags for existing exts
$t->assign([ // Присваиваем значения переменным для отображения информации о расширении
'ADMIN_EXTENSIONS_RIGHTS_URL' => $extensionsService->getRightsUrl($code, $type), // URL для прав доступа
'ADMIN_EXTENSIONS_ADMRIGHTS_AUTH_GUESTS' => cot_auth_getmask($info['Auth_guests']), // Маска прав для гостей
'ADMIN_EXTENSIONS_AUTH_GUESTS' => $info['Auth_guests'], // Правила доступа для гостей
'ADMIN_EXTENSIONS_ADMRIGHTS_LOCK_GUESTS' => cot_auth_getmask($info['Lock_guests']), // Блокировка доступа для гостей
'ADMIN_EXTENSIONS_LOCK_GUESTS' => $info['Lock_guests'], // Блокировка доступа для гостей
'ADMIN_EXTENSIONS_ADMRIGHTS_AUTH_MEMBERS' => cot_auth_getmask($info['Auth_members']), // Маска прав для зарегистрированных пользователей
'ADMIN_EXTENSIONS_AUTH_MEMBERS' => $info['Auth_members'], // Правила доступа для пользователей
'ADMIN_EXTENSIONS_ADMRIGHTS_LOCK_MEMBERS' => cot_auth_getmask($info['Lock_members']), // Блокировка доступа для пользователей
'ADMIN_EXTENSIONS_LOCK_MEMBERS' => $info['Lock_members'], // Блокировка доступа для пользователей
'ADMIN_EXTENSIONS_AUTHOR' => $info['Author'], // Автор расширения
'ADMIN_EXTENSIONS_COPYRIGHT' => $info['Copyright'], // Авторские права
]);
// Check and display dependencies
$dependencies_satisfied = true; // Инициализируем переменную, которая будет отслеживать состояние зависимостей
foreach (['Requires_modules', 'Requires_plugins', 'Recommends_modules', 'Recommends_plugins'] as $dep_type) { // Перебираем типы зависимостей
if (!empty($info[$dep_type])) { // Проверяем, есть ли зависимости для текущего типа
$dep_obligatory = strpos($dep_type, 'Requires') === 0; // Проверяем, обязательная ли зависимость
$dep_module = strpos($dep_type, 'modules') !== false; // Проверяем, является ли зависимость модулем
$arg = $dep_module ? 'mod' : 'pl'; // Устанавливаем аргумент в зависимости от типа зависимости
$dir = $dep_module ? Cot::$cfg['modules_dir'] : Cot::$cfg['plugins_dir']; // Устанавливаем директорию в зависимости от типа зависимости
foreach (explode(',', $info[$dep_type]) as $ext) { // Перебираем все зависимости для текущего типа
$ext = trim($ext); // Убираем лишние пробелы
$dep_installed = $extensionsService->isInstalled($ext, null, true); // Проверяем, установлено ли зависимое расширение
if ($dep_obligatory) { // Если зависимость обязательная
$dep_class = $dep_installed ? 'highlight_green' : 'highlight_red'; // Устанавливаем класс для отображения зависимости
$dependencies_satisfied &= $dep_installed; // Если зависимость обязательная, проверяем, удовлетворена ли она
} else {
$dep_class = ''; // Для необязательных зависимостей класс не устанавливаем
}
$dep_ext_info = $dir . '/' . $ext . '/' . $ext . '.setup.php'; // Путь к файлу настройки расширения
if (file_exists($dep_ext_info)) { // Если файл настройки существует
$dep_info = cot_infoget($dep_ext_info, 'COT_EXT'); // Получаем информацию о расширении
if (!$dep_info && cot_plugin_active('genoa')) { // Если не удалось получить информацию, но активен плагин genoa
// Try to load old format info
$dep_info = cot_infoget($dep_ext_info, 'SED_EXTPLUGIN'); // Пробуем загрузить информацию в старом формате
}
} else {
$dep_info = array( // Если файл настройки не существует, создаем массив с названием расширения
'Name' => $ext
);
}
$dependencyUrl = ''; // Инициализируем URL зависимости
if (
($dep_module && file_exists(Cot::$cfg['modules_dir'] . '/' . $ext)) // Если зависимость является модулем и он существует
|| (!$dep_module && file_exists(Cot::$cfg['plugins_dir'] . '/' . $ext)) // Если зависимость является плагином и он существует
) {
$dependencyUrl = cot_url('admin', ['m' => 'extensions', 'a' => 'details', $arg => $ext]); // Получаем URL для просмотра информации о зависимости
}
$t->assign([ // Присваиваем значения для отображения информации о зависимости
'ADMIN_EXTENSIONS_DEPENDENCIES_ROW_CODE' => $ext, // Код зависимости
'ADMIN_EXTENSIONS_DEPENDENCIES_ROW_NAME' => $dep_info['Name'], // Имя зависимости
'ADMIN_EXTENSIONS_DEPENDENCIES_ROW_URL' => $dependencyUrl, // URL зависимости
'ADMIN_EXTENSIONS_DEPENDENCIES_ROW_TYPE' => $dep_module ? Cot::$L['Module'] : Cot::$L['Plugin'], // Тип зависимости (модуль или плагин)
'ADMIN_EXTENSIONS_DEPENDENCIES_ROW_CLASS' => $dep_class, // Класс для отображения зависимости
]);
$t->parse('MAIN.DETAILS.DEPENDENCIES.DEPENDENCIES_ROW'); // Рендерим строку с зависимостью
}
$t->assign(array(
'ADMIN_EXTENSIONS_DEPENDENCIES_TITLE' => Cot::$L['ext_' . strtolower($dep_type)] // Присваиваем заголовок для зависимостей
));
$t->parse('MAIN.DETAILS.DEPENDENCIES'); // Рендерим блок с зависимостями
}
}
}
/* === Hook === */
foreach (cot_getextplugins('admin.extensions.details') as $pl) { // Подключаем все плагины, которые зарегистрированы для хука 'admin.extensions.details'
include $pl; // Включаем каждый плагин
}
/* ===== */
$t->parse('MAIN.DETAILS'); // Рендерим блок деталей расширения
break; // Завершаем выполнение текущего case в switch
/* =============== */
case 'hooks': // Обрабатываем случай, когда выбран раздел "hooks" (хуки)
/* =============== */
$adminPath[] = array(cot_url('admin', 'm=extensions&a=hooks'), Cot::$L['Hooks']); // Добавляем путь к разделу хуков в навигацию
$sql = $db->query("SELECT * FROM $db_plugins ORDER BY pl_hook ASC, pl_code ASC, pl_order ASC"); // Выполняем SQL-запрос для получения всех плагинов из базы данных, сортируя их по хук, код плагина и порядок
while($row = $sql->fetch()) { // Для каждой строки результата запроса
$t->assign(array( // Присваиваем значения для отображения информации о плагинах
'ADMIN_EXTENSIONS_HOOK' => $row['pl_hook'], // Хук плагина
'ADMIN_EXTENSIONS_CODE' => $row['pl_code'], // Код плагина
'ADMIN_EXTENSIONS_ORDER' => $row['pl_order'], // Порядок плагина
'ADMIN_EXTENSIONS_ACTIVE' => $cot_yesno[$row['pl_active']] // Статус активности плагина (Да/Нет)
));
$t->parse('MAIN.HOOKS.HOOKS_ROW'); // Рендерим строку с информацией о плагине
}
$sql->closeCursor(); // Закрываем курсор SQL-запроса
$t->assign(array( // Присваиваем количество плагинов в базе данных
'ADMIN_EXTENSIONS_CNT_HOOK' => $sql->rowCount() // Количество строк в результате запроса
));
$t->parse('MAIN.HOOKS'); // Рендерим блок с хуками
break; // Завершаем выполнение текущего case в switch
/* =============== */
default: // Обрабатываем случай по умолчанию, если ни одно из условий в switch не выполнено
/* =============== */
// Params to show only installed extensions
$only_installed = cot_import('inst', 'G', 'BOL'); // Получаем параметр 'inst' из GET-запроса, который определяет, показывать ли только установленные расширения
if (Cot::$cfg['default_show_installed']) { // Если настройка по умолчанию предполагает показ только установленных расширений
if (is_null($only_installed)) { // Если параметр 'inst' не был передан
$only_installed = true; // По умолчанию показываем только установленные расширения
}
$only_installed_urlp = $only_installed ? '' : '&inst=0'; // Формируем URL для отображения установленных или неустановленных расширений
$only_installed_toggle = $only_installed ? '&inst=0' : ''; // Формируем URL для переключения между установленными и неустановленными расширениями
} else { // Если настройка по умолчанию не предполагает показ только установленных расширений
$only_installed_urlp = $only_installed ? '&inst=1' : ''; // Формируем URL для отображения установленных или неустановленных расширений
$only_installed_toggle = $only_installed ? '' : '&inst=1'; // Формируем URL для переключения между установленными и неустановленными расширениями
}
$sort_urlp = $sort == 'cat' ? '&sort=cat' : ''; // Формируем URL для сортировки по категориям
// Filter/sort tags
$t->assign([ // Присваиваем значения для отображения фильтров и сортировки расширений
'ADMIN_EXTENSIONS_HOOKS_URL' => cot_url('admin', 'm=extensions&a=hooks'), // URL для перехода в раздел хуков
'ADMIN_EXTENSIONS_SORT_ALP_URL' => cot_url('admin', 'm=extensions'.$only_installed_urlp), // URL для сортировки по алфавиту
'ADMIN_EXTENSIONS_SORT_ALP_SEL' => $sort != 'cat', // Определяем, выбран ли режим сортировки по алфавиту
'ADMIN_EXTENSIONS_SORT_CAT_URL' => cot_url('admin', 'm=extensions&sort=cat'.$only_installed_urlp), // URL для сортировки по категориям
'ADMIN_EXTENSIONS_SORT_CAT_SEL' => $sort == 'cat', // Определяем, выбран ли режим сортировки по категориям
'ADMIN_EXTENSIONS_ALL_EXTENSIONS_URL' => cot_url('admin', 'm=extensions'.$sort_urlp), // URL для отображения всех расширений
'ADMIN_EXTENSIONS_ONLY_INSTALLED_URL' => cot_url('admin', 'm=extensions'.$sort_urlp.$only_installed_toggle), // URL для отображения только установленных расширений
'ADMIN_EXTENSIONS_ONLY_INSTALLED_SEL' => $only_installed, // Определяем, показывать ли только установленные расширения
]);
// Prefetch common data to save SQL queries // Предзагружаем общие данные, чтобы сократить количество SQL-запросов
$totalConfigs = []; // Инициализируем массив для хранения информации о конфигурациях
$sql = Cot::$db->query( // Выполняем SQL-запрос для получения количества конфигураций по владельцу и категории
'SELECT COUNT(*) AS cnt, config_owner, config_cat FROM ' . Cot::$db->config // Запрашиваем количество конфигураций, владельца и категорию
. ' WHERE config_type NOT IN (' . COT_CONFIG_TYPE_HIDDEN . ', ' . COT_CONFIG_TYPE_SEPARATOR . ') ' // Исключаем скрытые и разделительные конфигурации
. "AND (config_subcat IN ('', '__default') OR config_subcat IS NULL) " // Оставляем только те, которые принадлежат основной категории или не имеют подкатегории
. 'GROUP BY config_owner, config_cat'); // Группируем по владельцу и категории конфигураций
while ($row = $sql->fetch()) { // Перебираем результаты запроса
$totalConfigs[$row['config_owner']][$row['config_cat']] = (int) $row['cnt']; // Сохраняем количество конфигураций для каждого владельца и категории
}
$sql->closeCursor(); // Закрываем курсор SQL-запроса
$totalactives = []; // Инициализируем массив для хранения информации о количестве активных плагинов
$totalinstalleds = []; // Инициализируем массив для хранения информации о количестве установленных плагинов
foreach ($db->query("SELECT SUM(pl_active) AS sum, COUNT(*) AS cnt, pl_code FROM $db_plugins GROUP BY pl_code")->fetchAll() as $row) { // Выполняем SQL-запрос для получения суммы активных плагинов и их общего количества по коду плагина
$totalactives[$row['pl_code']] = (int) $row['sum']; // Сохраняем количество активных плагинов для каждого кода плагина
$totalinstalleds[$row['pl_code']] = (int) $row['cnt']; // Сохраняем количество установленных плагинов для каждого кода плагина
}
$installed_vers = []; // Инициализируем массив для хранения информации о версиях установленных компонентов
foreach($db->query("SELECT ct_version, ct_code FROM $db_core")->fetchAll() as $row) { // Выполняем SQL-запрос для получения версий установленных компонентов
$installed_vers[$row['ct_code']] = $row['ct_version']; // Сохраняем версию для каждого компонента по его коду
}
$extensionsWithStructure = cot_getExtensionsWithStructure(); // Получаем список расширений с структурой
foreach (['module', 'plug'] as $type) { // Перебираем типы расширений: 'module' и 'plug'
$sql = $db->query("SELECT DISTINCT(config_cat), COUNT(*) FROM $db_config // Выполняем SQL-запрос для получения уникальных категорий конфигураций и их количества
WHERE config_owner='$type' GROUP BY config_cat"); // Где владелец конфигурации соответствует текущему типу расширений
while ($row = $sql->fetch(PDO::FETCH_NUM)) { // Перебираем результаты запроса
$cfgentries[$row[0]] = $row[1]; // Сохраняем количество конфигураций для каждой категории
}
$sql->closeCursor(); // Закрываем курсор SQL-запроса
$dir = $type == 'module' ? Cot::$cfg['modules_dir'] : Cot::$cfg['plugins_dir']; // Определяем директорию в зависимости от типа расширения
$extensions = cot_extension_list_info($dir); // Получаем информацию о расширениях из соответствующей директории
$ctplug = $type == 'module' ? '0' : '1'; // Устанавливаем значение для типа расширения: 0 для модуля, 1 для плагина
if ($only_installed) { // Если нужно фильтровать только установленные расширения
// Filter only installed exts
$tmp = []; // Создаем временный массив для хранения установленных расширений
$installed_exts = $db->query("SELECT ct_code FROM $db_core WHERE ct_plug = $ctplug")->fetchAll(PDO::FETCH_COLUMN); // Получаем список установленных расширений для данного типа (модуль или плагин)
foreach ($extensions as $key => $val) { // Перебираем все расширения
if (in_array($key, $installed_exts)) { // Если расширение установлено
$tmp[$key] = $val; // Добавляем его в временный массив
}
}
$extensions = $tmp; // Перезаписываем оригинальный массив установленных расширений
}
// Find missing extensions
$extlist = count($extensions) > 0 ? "ct_code NOT IN('" . implode("','", array_keys($extensions)) . "')" : '1'; // Формируем SQL-условие для поиска отсутствующих расширений
$sql = $db->query("SELECT * FROM $db_core WHERE $extlist AND ct_plug = $ctplug"); // Выполняем запрос к базе данных для поиска расширений, которых нет в списке
foreach ($sql->fetchAll() as $row) { // Перебираем результаты запроса
if ($type == 'module' && in_array($row['ct_code'], array('admin', 'message', 'users'))) { // Если тип расширения — модуль и это одно из исключений (admin, message, users)
continue; // Пропускаем эти расширения
}
$extensions[$row['ct_code']] = [ // Добавляем расширение в массив
'Code' => $row['ct_code'], // Код расширения
'Name' => $row['ct_title'], // Название расширения
'Version' => $row['ct_version'], // Версия расширения
'Category' => 'misc-ext', // Категория расширения
'NotFound' => true, // Флаг, что расширение не найдено
];
}
if ($type == 'plug' && $sort == 'cat') { // Если тип расширения — плагин и сортировка по категории
uasort($extensions, 'cot_extension_catcmp'); // Сортируем расширения по категории с использованием функции сравнения cot_extension_catcmp
} else { // Если сортировка не по категории
ksort($extensions); // Сортируем расширения по ключам (по коду расширения)
}
$cnt_extp = count($extensions); // Получаем количество расширений
$cnt_parts = 0; // Инициализируем переменную для подсчета частей (разделов)
$prev_cat = ''; // Инициализируем переменную для хранения предыдущей категории
/* === Hook - Part1 : Set === */ // Заголовок, указывающий на начало первого этапа хука для плагинов
$extp = cot_getextplugins("admin.extensions.$type.list.loop"); // Получение плагинов для указанного типа расширений из хука
/* ===== */ // Завершение первого этапа хука
$i = 1; // Инициализация счетчика для перебора расширений
foreach ($extensions as $code => $info) { // Начало цикла по всем расширениям
if ( // Условие для сортировки по категории, только если сортировка установлена на 'cat' и тип расширения - плагин
$sort === 'cat'
&& $type === ExtensionsDictionary::TYPE_PLUGIN
&& $prev_cat !== $info['Category'] // Проверка, если категория отличается от предыдущей
) {
// Рендеринг заголовка категории
$t->assign(
'ADMIN_EXTENSIONS_CAT_TITLE', // Название категории для отображения
Cot::$L['ext_cat_' . $info['Category']] ?? $info['Category'] // Получение перевода категории, если он существует, иначе используем саму категорию
);
$t->parse('MAIN.DEFAULT.SECTION.ROW.ROW_CAT'); // Парсинг шаблона для вывода категории
// Присваиваем новую категорию в переменную для дальнейшей проверки
$prev_cat = $info['Category']; // Обновление переменной $prev_cat с текущей категорией
}
$exists = !isset($info['NotFound']); // Проверка, существует ли ключ 'NotFound' в информации о расширении, определяет, найдено ли расширение
$isInstalled = $extensionsService->isInstalled($code, $type, true); // Проверка, установлено ли расширение
if (!empty($info['Error'])) { // Если существует ошибка в информации о расширении
$t->assign([ // Присваиваем данные для отображения ошибки
'ADMIN_EXTENSIONS_X_ERR' => $code, // Код расширения с ошибкой
'ADMIN_EXTENSIONS_ERROR_MSG' => $info['Error'], // Сообщение об ошибке
]);
$t->parse('MAIN.DEFAULT.ROW.ROW_ERROR_EXT'); // Парсинг шаблона для вывода ошибки
$t->parse('MAIN.DEFAULT.ROW'); // Парсинг строки для вывода расширения с ошибкой
} else { // Если ошибок нет
$totalactive = isset($totalactives[$code]) ? $totalactives[$code] : 0; // Получаем количество активных экземпляров расширения, если оно есть
$totalinstalled = isset($totalinstalleds[$code]) ? $totalinstalleds[$code] : 0; // Получаем количество установленных экземпляров расширения, если оно есть
$cnt_parts += $totalinstalled; // Увеличиваем общий счетчик установленных расширений
if (!isset($installed_vers[$code])) { // Если версия расширения не установлена
$part_status = 3; // Статус части - 3, что означает отсутствие версии
$info['Partscount'] = '?'; // Количество частей для этого расширения неизвестно
} else { // Если версия расширения установлена
$info['Partscount'] = $totalinstalled; // Устанавливаем количество частей как количество установленных экземпляров
if (!$exists) { // Если расширение не найдено
$part_status = 4; // Статус части - 4, что означает, что расширение отсутствует
} elseif ($totalinstalled > $totalactive && $totalactive > 0) { // Если установлено больше экземпляров, чем активно, и есть активные экземпляры
$part_status = 2; // Статус части - 2, что означает частичную активацию
} elseif ($totalactive == 0 && $totalinstalled > 0) { // Если нет активных экземпляров, но есть установленные
$part_status = 0; // Статус части - 0, что означает, что расширение не активно
} else { // В остальных случаях
$part_status = 1; // Статус части - 1, что означает полную активацию
}
}
$totalConfig = !empty($totalConfigs[$type][$code]) ? $totalConfigs[$type][$code] : 0; // Получаем количество конфигураций для расширения
$ent_code = isset($cfgentries[$code]) ? $cfgentries[$code] : 0; // Получаем количество записей конфигурации для расширения
$hasStructure = in_array($code, $extensionsWithStructure, true); // Проверяем, имеет ли расширение структуру, используя строгую проверку
if ($type === ExtensionsDictionary::TYPE_MODULE) { // Если тип расширения - модуль
$arg = 'mod'; // Устанавливаем аргумент как 'mod' для модуля
} else { // Если тип расширения - плагин
$arg = 'pl'; // Устанавливаем аргумент как 'pl' для плагина
}
$installed_ver = $installed_vers[$code] ?? ''; // Получаем установленную версию расширения, если она существует, иначе пустая строка
$params = cot_get_extensionparams($code, $type === ExtensionsDictionary::TYPE_MODULE); // Получаем параметры расширения (имя, описание и другие данные)
$rightsUrl = null; // Инициализируем переменную для URL прав доступа
Cot::$L['info_name'] = Cot::$L['info_desc'] = Cot::$L['info_notes'] = ''; // Очищаем значения переменных для имени, описания и заметок
$langFile = cot_langfile($code, $type); // Получаем путь к языковому файлу расширения
if (!empty($langFile) ?? file_exists($langFile)) { // Если языковой файл существует
include $langFile; // Подключаем языковой файл
}
$t->assign([ // Присваиваем переменные для отображения информации о расширении
'ADMIN_EXTENSIONS_DETAILS_URL' => cot_url('admin', "m=extensions&a=details&$arg=$code"), // URL для страницы деталей расширения
'ADMIN_EXTENSIONS_NAME' => htmlspecialchars($params['name']), // Имя расширения
'ADMIN_EXTENSIONS_TYPE' => $type === ExtensionsDictionary::TYPE_MODULE
? Cot::$L['Module'] // Если это модуль, то выводим "Module"
: Cot::$L['Plugin'], // Если это плагин, то выводим "Plugin"
'ADMIN_EXTENSIONS_CODE_X' => $code, // Код расширения
'ADMIN_EXTENSIONS_NOTES' => $params['notes'], // Заметки по расширению
'ADMIN_EXTENSIONS_DESCRIPTION' => $params['desc'], // Описание расширения
'ADMIN_EXTENSIONS_ICON' => $params['icon'], // Иконка расширения
'ADMIN_EXTENSIONS_EDIT_URL' => cot_url('admin', "m=config&n=edit&o=$type&p=$code"), // URL для редактирования расширения
'ADMIN_EXTENSIONS_TOTALCONFIG' => $totalConfig, // Общее количество конфигураций для расширения
'ADMIN_EXTENSIONS_PARTSCOUNT' => $info['Partscount'], // Количество частей расширения
'ADMIN_EXTENSIONS_STATUS' => $status[$part_status], // Статус расширения
'ADMIN_EXTENSIONS_VERSION' => $info['Version'], // Версия расширения
'ADMIN_EXTENSIONS_VERSION_INSTALLED' => $installed_ver, // Установленная версия расширения
'ADMIN_EXTENSIONS_VERSION_COMPARE' => version_compare($info['Version'], $installed_ver), // Сравнение версий расширения
'ADMIN_EXTENSIONS_RIGHTS_URL' => $extensionsService->getRightsUrl($code, $type), // URL для прав доступа к расширению
'ADMIN_EXTENSIONS_ADMIN_URL' => $extensionsService->getAdminPageUrl($code, $type), // URL для административной страницы расширения
'ADMIN_EXTENSIONS_JUMPTO_URL' => $extensionsService->getPublicPageUrl($code, $type), // URL для публичной страницы расширения
'ADMIN_EXTENSIONS_STRUCTURE_URL' => $hasStructure
? cot_url('admin', ['m' => 'structure', 'n' => $code]) // URL для структуры, если она существует
: '',
//'ADMIN_EXTENSIONS_ODDEVEN' => cot_build_oddeven($i), // Пример для парности, не используется в коде
]);
if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Если включен режим совместимости
$t->assign([ // Присваиваем старые данные для совместимости
'ADMIN_EXTENSIONS_ICO' => $params['legacyIcon'], // Старый иконка расширения для совместимости
/** @deprecated in 0.9.26 */
'ADMIN_EXTENSIONS_JUMPTO_URL_TOOLS' => $extensionsService->getAdminPageUrl($code, $type), // Старый URL для инструментов расширения
'ADMIN_EXTENSIONS_JUMPTO_URL_STRUCT' => $hasStructure
? cot_url('admin', ['m' => 'structure', 'n' => $code]) // Старый URL для структуры расширения
: '',
]);
}
/* === Hook - Part2 : Include === */
foreach ($extp as $pl) { // Для каждого плагина в хуке
include $pl; // Включаем плагин
}
/* ===== */
$t->parse('MAIN.DEFAULT.SECTION.ROW'); // Парсинг строки для отображения данных о расширении
$i++; // Увеличиваем счетчик для следующих итераций
$t->assign(array( // Присваиваем переменные для отображения данных о расширении
'ADMIN_EXTENSIONS_SECTION_TITLE' => $type == 'module' ? Cot::$L['Modules'] : Cot::$L['Plugins'], // Заголовок секции: если это модуль, то "Modules", иначе "Plugins"
'ADMIN_EXTENSIONS_CNT_EXTP' => $cnt_extp // Количество расширений
));
$t->parse('MAIN.DEFAULT.SECTION'); // Парсинг секции расширений
}
$t->parse('MAIN.DEFAULT'); // Парсинг основной секции
break; // Завершаем выполнение текущего кейса в switch
cot_display_messages($t); // Отображаем сообщения (если есть) через шаблон
/* === Hook === */
foreach (cot_getextplugins('admin.extensions.tags') as $pl) { // Для каждого плагина в хуке 'admin.extensions.tags'
include $pl; // Включаем плагин
}
/* ===== */
$t->parse('MAIN'); // Парсинг основного шаблона
$adminMain = $t->text('MAIN'); // Получаем HTML-контент основного шаблона и сохраняем в переменную
Комментарии (0)
Автор контента
Оффлайн
Administrator
Последняя авторизация: 05.07.2026 18:32
- Страница размещена: 28.01.2025 16:16
- Последнее обновление: 28.01.2025 17:21