Файл extensions.php в Cotonti
Файл extensions.php в системной папке Cotonti CMF имеет основное назначение управлять расширениями системы. В частности, его функциональность охватывает операции, связанные с добавлением, удалением, обновлением и получением информации о расширениях (модулях и плагинах). Также он выполняет регистрационные действия для модулей и плагинов в ядре системы и работает с метаинформацией расширений, получаемой из их заголовков.
Основные действия, которые реализует код:
- Чтение и анализ заголовков расширений с помощью регулярных выражений, чтобы извлечь метаинформацию.
- Регистрация новых расширений в базе данных.
- Обновление и удаление расширений.
- Управление связями расширений с хуками (например, добавление или удаление привязок плагинов к определённым хук-пунктам).
- Обработка информации о категориях и зависимости расширений (модули и плагины).
Стиль PHP, который используется в данном файле, можно охарактеризовать как стандартный для программирования в Cotonti CMF:
- Используются глобальные переменные, например,
$db, для работы с базой данных. - Код имеет строгую структуру с ясным разделением функциональности на отдельные функции.
- Активно используется обработка ошибок с использованием конструкций
try-catchдля работы с транзакциями в базе данных. - Применяются регулярные выражения и манипуляции с текстом для извлечения данных из файлов.
- Используются стандартные средства работы с базой данных, такие как методы
$db->insert(),$db->delete(), и$db->update(). - Для улучшения читаемости и предотвращения ошибок работы с файлами используется конструкция
@fopen()с проверкой на успешное открытие файла.
Также заметно, что код активно использует транзакции для обеспечения целостности данных при добавлении расширений и их привязок к хукам.
Вот список всех функций в файле extensions.php:
-
cot_infoget
Функция извлекает информацию из заголовков COT файлов. -
cot_extension_add
Функция для регистрации расширения в базе данных. -
cot_extension_catcmp
Функция сравнивает два расширения по коду категории. -
cot_extension_installed
Функция проверяет, установлено ли расширение. (Помечена как устаревшая.) -
cot_extension_type
Функция возвращает тип расширения (модуль или плагин). (Помечена как устаревшая.) -
cot_extension_list_info
Функция возвращает массив с метаинформацией всех расширений в указанной директории. -
cot_extension_remove
Функция удаляет расширение из базы данных. -
cot_extension_update
Функция обновляет версию расширения в базе данных. -
cot_plugin_add
Функция добавляет плагин или его части в реестр хуков. -
cot_plugin_remove
Функция удаляет плагин или его части из реестра хуков.
Это все функции, которые реализованы в файле extensions.php.
/**
* Plugin and Module Management API
*
* @package API - Extensions
* @copyright (c) Cotonti Team
* @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
*/
// API для управления плагинами и модулями
use cot\extensions\ExtensionsControlService; // Подключение класса для управления расширениями
use cot\extensions\ExtensionsDictionary; // Подключение словаря расширений
use cot\extensions\ExtensionsService; // Подключение сервиса расширений
defined('COT_CODE') or die('Wrong URL'); // Проверка на правильность обращения (если не задан правильный код, выполнение прекращается)
// Requirements
require_once cot_incfile('auth'); // Подключение файла для работы с авторизацией
require_once cot_incfile('configuration'); // Подключение файла для работы с конфигурацией
require_once cot_langfile('admin', 'core'); // Подключение языкового файла для админки
/** * Значение, возвращаемое функцией cot_extension_install() при обновлении, * если нечего обновлять */ const COT_EXT_NOTHING_TO_UPDATE = 2; // Значение для случая, когда обновление не требуется /** * Приоритет выполнения части плагина по умолчанию */ const COT_PLUGIN_DEFAULT_ORDER = 10; // Стандартный приоритет выполнения частей плагина /** * Эти части ($name.$part.php) являются зарезервированными обработчиками без хуков */ $cot_ext_ignore_parts = ['configure', 'install', 'setup', 'uninstall']; // Массив зарезервированных частей плагина
/**
* Применяет пользовательские SQL и PHP патчи из указанной директории. Сообщения об ошибках и успехах
* выводятся через стандартное API сообщений в процессе выполнения.
*
* @param string $directory Путь к директории
* @param string $from_ver Текущая версия, с которой начинать патчинг
* @param string $sql_pattern Шаблон имени файла для SQL патча (PCRE)
* @param string $php_pattern Шаблон имени файла для PHP патча (PCRE)
* @return string|bool Функция возвращает TRUE, если нет патчей для применения,
* FALSE, если произошла ошибка при патчинге, или строку, содержащую номер версии последнего примененного патча, если патчинг прошел успешно.
*/
function cot_apply_patches(
$directory,
$from_ver,
$sql_pattern = 'patch_([\w\.\-\_]+)\.(sql)', // Шаблон для файлов SQL патчей
$php_pattern = 'patch_([\w\.\-\_]+)\.(inc)' // Шаблон для файлов PHP патчей
)
{
global $L, $Ls, $cfg, $R, $db;
// Ищем новые патчи
$dp = opendir($directory); // Открытие директории для чтения
$delta = []; // Массив для хранения патчей
while ($f = readdir($dp)) { // Чтение файлов из директории
if (
preg_match('#^' . $sql_pattern . '$#', $f, $mt) // Проверка на соответствие шаблону SQL
|| preg_match('#^' . $php_pattern . '$#', $f, $mt) // Проверка на соответствие шаблону PHP
) {
$type = $mt[2] == 'sql' ? 'sql' : 'php'; // Определение типа патча (sql или php)
$ver = $mt[1]; // Извлечение версии из имени файла
if (version_compare($ver, $from_ver) > 0 && !isset($delta[$ver][$type])) { // Проверка, что версия больше текущей
$delta[$ver][$type] = $directory . '/' . $f; // Добавляем патч в массив
}
}
}
closedir($dp); // Закрытие директории
if (count($delta) == 0) { // Если нет новых патчей
return true; // Возвращаем TRUE, так как патчей для применения нет
}
// Применяем патчи по порядку версий
uksort($delta, 'version_compare'); // Сортируем массив патчей по версии
$max_ver = $from_ver; // Инициализируем максимальную версию как текущую
static $executed = []; // Статическая переменная для хранения уже примененных патчей
foreach ($delta as $key => $val) { // Проходим по всем найденным патчам
if (isset($val['sql']) && !in_array($val['sql'], $executed)) { // Если есть SQL патч и он еще не применен
$error = Cot::$db->runScript(file_get_contents($val['sql'])); // Выполняем SQL патч
$executed[] = $val['sql']; // Добавляем патч в список примененных
if (empty($error)) { // Если ошибки нет
cot_message(cot_rc('ext_patch_applied',
array('f' => $val['sql'], 'msg' => 'OK'))); // Выводим сообщение об успешном применении
} else { // Если произошла ошибка
cot_error(cot_rc('ext_patch_error', array('f' => $val['sql'], 'msg' => $error))); // Выводим сообщение об ошибке
return false; // Возвращаем FALSE, так как произошла ошибка
}
}
if (isset($val['php']) && !in_array($val['php'], $executed)) { // Если есть PHP патч и он еще не применен
$ret = include $val['php']; // Подключаем PHP патч
$executed[] = $val['php']; // Добавляем патч в список примененных
if ($ret !== false) { // Если патч выполнен успешно
$msg = $ret == 1 ? 'OK' : $ret; // Определяем сообщение (если ret равно 1 - успех)
cot_message(cot_rc('ext_patch_applied', array('f' => $val['php'], 'msg' => $msg))); // Выводим сообщение об успешном применении
} else { // Если патч не выполнен
cot_error(cot_rc('ext_patch_error', array('f' => $val['php'], 'msg' => $L['Error']))); // Выводим сообщение об ошибке
return false; // Возвращаем FALSE, так как произошла ошибка
}
}
$max_ver = $key; // Обновляем максимальную версию
}
return $max_ver; // Возвращаем версию последнего примененного патча
}
/**
* Проверяет, выполнены ли все зависимости для выбранного расширения. Это означает,
* что все необходимые модули и плагины уже установлены или выбраны для установки.
*
* Сообщения о неудовлетворенных требованиях выводятся через систему ошибок и сообщений.
*
* @param string $name Код расширения
* @param bool $is_module TRUE для модулей, FALSE для плагинов
* @param array $selected_modules Список модулей, выбранных для установки
* @param array $selected_plugins Список плагинов, выбранных для установки
* @return bool TRUE, если все зависимости выполнены, или FALSE в противном случае
*/
function cot_extension_dependencies_statisfied($name, $is_module = false,
$selected_modules = array(), $selected_plugins = array())
{
global $cfg, $L;
$path = $is_module ? $cfg['modules_dir'] . "/$name" : $cfg['plugins_dir'] . "/$name"; // Путь к расширению в зависимости от его типа
$ret = true; // Инициализируем переменную для проверки
// Получаем список зависимостей
$info = cot_infoget("$path/$name.setup.php", 'COT_EXT'); // Загружаем информацию о расширении
$required_modules = empty($info['Requires_modules']) ? array() // Если нет требуемых модулей, создаем пустой массив
: explode(',', $info['Requires_modules']); // Разбиваем строку с модулями на массив
$required_modules = array_map('trim', $required_modules); // Убираем лишние пробелы из элементов массива
$required_plugins = empty($info['Requires_plugins']) ? array() // Если нет требуемых плагинов, создаем пустой массив
: explode(',', $info['Requires_plugins']); // Разбиваем строку с плагинами на массив
$required_plugins = array_map('trim', $required_plugins); // Убираем лишние пробелы из элементов массива
// Проверяем каждую зависимость
foreach ($required_modules as $req_ext) { // Для каждого требуемого модуля
if (!empty($req_ext) && !in_array($req_ext, $selected_modules) // Если модуль не пустой и не выбран для установки
&& !cot_extension_installed($req_ext)) { // И если модуль не установлен
cot_error(cot_rc('ext_dependency_error', array( // Выводим ошибку о зависимости
'name' => $name,
'type' => $is_module ? $L['Module'] : $L['Plugin'], // Тип расширения (модуль или плагин)
'dep_type' => $L['Module'], // Тип зависимости (модуль)
'dep_name' => $req_ext // Имя требуемого модуля
)));
$ret = false; // Устанавливаем результат в false, так как зависимость не выполнена
}
}
foreach ($required_plugins as $req_ext) { // Для каждого требуемого плагина
if (!empty($req_ext) && !in_array($req_ext, $selected_plugins) // Если плагин не пустой и не выбран для установки
&& !cot_extension_installed($req_ext)) { // И если плагин не установлен
cot_error(cot_rc('ext_dependency_error', array( // Выводим ошибку о зависимости
'name' => $name,
'type' => $is_module ? $L['Module'] : $L['Plugin'], // Тип расширения (модуль или плагин)
'dep_type' => $L['Plugin'], // Тип зависимости (плагин)
'dep_name' => $req_ext // Имя требуемого плагина
)));
$ret = false; // Устанавливаем результат в false, так как зависимость не выполнена
}
}
return $ret; // Возвращаем результат проверки (TRUE, если все зависимости выполнены)
}
/**
* Устанавливает или обновляет расширение Cotonti: модуль или плагин.
* Сообщения, выводимые во время установки, могут быть получены через стандартный
* интерфейс сообщений Cotonti.
*
* @param string $extensionCode Код модуля (или плагина)
* @param bool $isModule TRUE для модулей, FALSE для плагинов
* @param bool $update Выполнить обновление, а не новую установку
* @param bool $force_update Принудительное обновление расширения, даже если версия не изменилась
* @return bool Статус операции
* @global Cache $cache
*
* @todo переместить в ExtensionControlService или создать отдельный ExtensionSetupService
*/
function cot_extension_install($extensionCode, $isModule = false, $update = false, $force_update = false)
{
global $cfg, $L, $R, $cache, $usr, $db_auth, $db_config, $db_users,
$db_core, $cot_groups, $cot_ext_ignore_parts, $db, $db_x, $env;
/** @deprecated in 0.9.24 for backward compatibility */
$is_module = $isModule; // @deprecated в 0.9.24 для обеспечения совместимости с предыдущими версиями
/** @deprecated in 0.9.24 for backward compatibility */
$name = $extensionCode; // @deprecated в 0.9.24 для обеспечения совместимости с предыдущими версиями
$path = $isModule ? Cot::$cfg['modules_dir'] . "/$extensionCode" : Cot::$cfg['plugins_dir'] . "/$extensionCode"; // Определение пути к модулю или плагину в зависимости от типа расширения
// Отправка начального сообщения
if ($update) { // Если выполняется обновление
cot_message(cot_rc('ext_updating', array(
'type' => $isModule ? Cot::$L['Module'] : Cot::$L['Plugin'], // Указание типа расширения (модуль или плагин)
'name' => $extensionCode, // Имя расширения
)));
} else { // Если выполняется установка
cot_message(cot_rc('ext_installing', array(
'type' => $isModule ? $L['Module'] : $L['Plugin'], // Указание типа расширения (модуль или плагин)
'name' => $extensionCode, // Имя расширения
)));
}
// Проверка наличия файла настройки и тегов
$setup_file = $path . "/$extensionCode.setup.php"; // Путь к файлу настройки расширения
if (!file_exists($setup_file)) { // Если файл настройки не найден
cot_error(cot_rc('ext_setup_not_found', array('path' => $setup_file))); // Вывод ошибки
return false; // Возвращаем false, если файл не найден
}
$old_ext_format = false; // Переменная для проверки старого формата расширения
$info = cot_infoget($setup_file, 'COT_EXT'); // Попытка получить информацию о расширении в новом формате
if (!$info && cot_plugin_active('genoa')) { // Если информация не найдена и активирован плагин Genoa
// Пытаемся загрузить информацию в старом формате
$info = cot_infoget($setup_file, 'SED_EXTPLUGIN'); // Попытка получить информацию в старом формате
if ($info) {
$old_ext_format = true; // Если информация найдена в старом формате, устанавливаем флаг
}
}
if ($info === false) { // Если информация не найдена
cot_error('ext_invalid_format'); // Вывод ошибки о неверном формате расширения
return false; // Возвращаем false, если формат неверен
}
Глобальные переменные:
$cfg: глобальный массив конфигурации, который содержит параметры конфигурации системы, такие как пути к директориям, настройки базы данных и прочее.$L: глобальный массив, содержащий локализованные строки (переводы) для разных языков, используемых на сайте.$R: глобальный массив, который может использоваться для хранения различных ресурсов, таких как шаблоны, изображения, стили и скрипты.$cache: объект или массив для работы с кешем данных, используется для хранения и извлечения временных данных.$usr: глобальный массив или объект, содержащий информацию о текущем пользователе, например, его идентификатор, статус и разрешения.$db_auth: глобальная переменная для работы с данными аутентификации, например, для проверки учетных записей пользователей.$db_config: глобальная переменная для работы с конфигурационными данными базы данных.$db_users: глобальная переменная для работы с данными пользователей в базе данных.$db_core: глобальная переменная для работы с основными данными, такими как таблицы пользователей, групп, и другие ключевые данные.$cot_groups: глобальная переменная для работы с группами пользователей на сайте.$cot_ext_ignore_parts: массив, содержащий части расширений, которые должны быть проигнорированы (например, установочные или конфигурационные файлы).$db: глобальная переменная, представляющая подключение к базе данных.$db_x: глобальная переменная для работы с таблицами базы данных, связана с функциональностью расширений.$env: глобальная переменная, представляющая окружение текущего запроса или сеанса.
// Проверка версии
$res = Cot::$db->query('SELECT ct_version FROM ' . Cot::$db->core . ' WHERE ct_code = ?', $extensionCode);
if ($res->rowCount() == 1) {
$current_ver = $res->fetchColumn(); // Извлекаем текущую версию расширения из базы данных
$res->closeCursor(); // Закрываем курсор, так как данные извлечены
if ($update) {
// Если выполняется обновление
if (version_compare($current_ver, $info['Version']) == 0 && !$force_update) {
// Если текущая версия уже совпадает с той, что указана в setup файле и не требуется принудительное обновление
cot_message(cot_rc('ext_up2date', array(
'type' => $isModule ? Cot::$L['Module'] :Cot::$L['Plugin'],
'name' => $extensionCode
))); // Отправляем сообщение, что расширение актуально
return COT_EXT_NOTHING_TO_UPDATE; // Возвращаем константу, указывающую, что обновление не требуется
}
} else {
// Если это не обновление, а новая установка
cot_clear_messages(); // Очищаем все текущие сообщения
cot_error(cot_rc('ext_already_installed', array('name' => $extensionCode))); // Выводим ошибку, что расширение уже установлено
return false; // Возвращаем false, так как расширение уже установлено
}
}
$registeredParts = []; // Инициализация пустого массива для хранения зарегистрированных частей расширения
if ($update) { // Если выполняется обновление
$query = $query = Cot::$db->query( // Выполнение SQL-запроса
'SELECT * FROM ' . Cot::$db->plugins . ' WHERE pl_code = :code', // Запрос для получения данных расширения по коду
['code' => $extensionCode] // Параметр запроса с кодом расширения
);
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(); // Закрытие курсора после выполнения запроса
// Безопасное удаление существующих привязок
$bindings_cnt = cot_plugin_remove($extensionCode); // Удаление привязок плагина
cot_message(cot_rc('ext_bindings_uninstalled', array('cnt' => $bindings_cnt))); // Отправка сообщения о том, сколько привязок было удалено
}
// Установка частей хука и привязок
$hookBindings = []; // Инициализация массива для хранения привязок хуков
$dp = opendir($path); // Открытие директории расширения
while ($f = readdir($dp)) { // Чтение файлов в директории
if (
preg_match("#^$extensionCode(\.([\w\.]+))?.php$#", $f, $mt) // Проверка, что имя файла соответствует шаблону расширения
&& (!isset($mt[2]) || !in_array($mt[2], $cot_ext_ignore_parts)) // Проверка, что часть не игнорируется
) {
$part_info = cot_infoget($path . "/$f", 'COT_EXT'); // Получение информации о части из файла
if (!$part_info && cot_plugin_active('genoa')) { // Если информация не получена, пытаемся загрузить в старом формате
$part_info = cot_infoget($path . "/$f", 'SED_EXTPLUGIN');
}
if ($part_info) { // Если информация получена
if (empty($part_info['Hooks'])) { // Если хук не задан, используем дефолтное значение
$hooks = $isModule ? ['module'] : ['standalone'];
} else {
$hooks = explode(',', $part_info['Hooks']); // Разделяем хуки по запятой
$hooks = is_array($hooks) ? array_map('trim', $hooks) : array(); // Очищаем пробелы
}
if (empty($part_info['Order'])) { // Если порядок не задан, используем дефолтный
$order = COT_PLUGIN_DEFAULT_ORDER;
} else {
$order = array_map('trim', explode(',', $part_info['Order'])); // Разделяем порядок по запятой
if (count($order) == 1 || count($order) < count($hooks)) { // Если порядок один, применяем его ко всем хукам
$order = (int) $order[0];
}
}
$i = 0;
foreach ($hooks as $hook) { // Для каждого хука
$hookBinding = [ // Создаём привязку для хука
'part' => !isset($mt[2]) ? 'main' : $mt[2], // Определяем часть (основная или по имени)
'file' => $f, // Файл, к которому относится хук
'hook' => $hook, // Имя хука
'order' => isset($order[$i]) ? (int) $order[$i] : $order, // Порядок хука
];
if (isset($registeredParts[$hookBinding['part']])) { // Если часть уже зарегистрирована
$hookBinding['active'] = $registeredParts[$hookBinding['part']]['pl_active']; // Устанавливаем активность
}
$hookBindings[] = $hookBinding; // Добавляем привязку к списку
++$i;
}
}
}
}
closedir($dp); // Закрытие директории
$bindings_cnt = cot_plugin_add($hookBindings, $extensionCode, $info['Name'], $isModule); // Добавление привязок плагина
cot_message(cot_rc('ext_bindings_installed', ['cnt' => $bindings_cnt])); // Сообщение о количестве установленных привязок
// Установка конфигурации
$info_cfg = cot_infoget($setup_file, 'COT_EXT_CONFIG'); // Получение конфигурации расширения из setup файла
if (!$info_cfg && cot_plugin_active('genoa')) { // Если конфигурация не найдена и активен плагин 'genoa'
// Пытаемся загрузить конфигурацию в старом формате
$info_cfg = cot_infoget($setup_file, 'SED_EXTPLUGIN_CONFIG');
}
$options = cot_config_parse($info_cfg, $isModule); // Разбор конфигурации с учетом модуля или плагина
if ($update) { // Если обновление расширения
// Получаем дифференциальную конфигурацию
if (cot_config_update($extensionCode, $options, $isModule) > 0) { // Обновляем конфигурацию
cot_message('ext_config_updated'); // Сообщение об успешном обновлении конфигурации
}
} elseif (count($options) > 0) { // Если конфигурация не пуста
if (cot_config_add($extensionCode, $options, $isModule)) { // Добавляем новую конфигурацию
cot_message('ext_config_installed'); // Сообщение об успешной установке конфигурации
} else { // Если произошла ошибка при установке конфигурации
cot_error('ext_config_error'); // Сообщение об ошибке при установке конфигурации
return false; // Возвращаем false, чтобы остановить дальнейшее выполнение
}
}
// Установка конфигурации структуры, если она присутствует
$info_cfg = cot_infoget($setup_file, 'COT_EXT_CONFIG_STRUCTURE'); // Получение конфигурации структуры из setup файла
if ($info_cfg) { // Если конфигурация структуры найдена
$options = cot_config_parse($info_cfg, $isModule); // Разбор конфигурации структуры с учетом модуля или плагина
if ($update) { // Если обновление расширения
if (cot_config_update($extensionCode, $options, $isModule, '__default') > 0) { // Обновляем конфигурацию структуры по умолчанию
// Обновление всех вложенных категорий
$type = $isModule ? 'module' : 'plug'; // Определяем тип: модуль или плагин
$res = $db->query("SELECT DISTINCT config_subcat FROM $db_config
WHERE config_owner = '$type' AND config_cat = '$extensionCode'
AND config_subcat != '' AND config_subcat != '__default'"); // Получаем список всех подкатегорий
$cat_list = $res->fetchAll(PDO::FETCH_COLUMN, 0); // Извлекаем подкатегории
foreach ($cat_list as $cat) { // Для каждой подкатегории
cot_config_update($extensionCode, $options, $isModule, $cat); // Обновляем конфигурацию для подкатегории
}
cot_message('ext_config_struct_updated'); // Сообщение об успешном обновлении конфигурации структуры
}
} elseif (count($options) > 0) { // Если конфигурация не пуста
if (cot_config_add($extensionCode, $options, $isModule, '__default')) { // Добавляем новую конфигурацию структуры
cot_message('ext_config_struct_installed'); // Сообщение об успешной установке конфигурации структуры
} else { // Если произошла ошибка при установке конфигурации структуры
cot_error('ext_config_struct_error'); // Сообщение об ошибке при установке конфигурации структуры
return false; // Возвращаем false, чтобы остановить дальнейшее выполнение
}
}
}
// Установка / Обновление аутентификации
if (!isset($info['Auth_guests'])) { // Если в информации не указана аутентификация для гостей
$info['Auth_guests'] = ''; // Устанавливаем значение по умолчанию
}
if (!isset($info['Lock_guests'])) { // Если в информации не указаны блокировки для гостей
$info['Lock_guests'] = ''; // Устанавливаем значение по умолчанию
}
if (!isset($info['Auth_members'])) { // Если в информации не указана аутентификация для пользователей
$info['Auth_members'] = ''; // Устанавливаем значение по умолчанию
}
if (!isset($info['Lock_members'])) { // Если в информации не указаны блокировки для пользователей
$info['Lock_members'] = ''; // Устанавливаем значение по умолчанию
}
if ($update) { // Если это обновление
// Обновляем только блокировки аутентификации
if ($isModule) { // Если это модуль
$auth_code = $extensionCode; // Код аутентификации для модуля
$auth_option = 'a'; // Опция для аутентификации
} else { // Если это плагин
$auth_code = 'plug'; // Код аутентификации для плагина
$auth_option = $extensionCode; // Опция для аутентификации
}
$lock_guests = cot_auth_getvalue($info['Lock_guests']); // Получаем блокировку для гостей
$db->update($db_auth, array('auth_rights_lock' => $lock_guests), "
auth_code = '$auth_code' AND auth_option = '$auth_option'
AND (auth_groupid = " . COT_GROUP_GUESTS
. ' OR auth_groupid = ' . COT_GROUP_INACTIVE . ')'); // Обновляем блокировку для гостей и неактивных пользователей
$lock_members = cot_auth_getvalue($info['Lock_members']); // Получаем блокировку для пользователей
$ingore_groups = implode(',', array(
COT_GROUP_GUESTS,
COT_GROUP_INACTIVE,
COT_GROUP_BANNED,
COT_GROUP_SUPERADMINS
)); // Игнорируем группы: гости, неактивные, заблокированные и супер администраторы
$db->update($db_auth, array('auth_rights_lock' => $lock_members),
"auth_code = '$auth_code' AND auth_option = '$auth_option' AND auth_groupid NOT IN ($ingore_groups)"); // Обновляем блокировку для остальных групп
cot_message('ext_auth_locks_updated'); // Сообщение о том, что блокировки аутентификации обновлены
} else { // Если это установка
// Устанавливаем аутентификацию
$insert_rows = array(); // Массив для вставки данных аутентификации
foreach ($cot_groups as $v) { // Для каждой группы
$v['skiprights'] = isset($v['skiprights']) ? $v['skiprights'] : false; // Проверяем, нужно ли пропускать права
if (!$v['skiprights']) { // Если не нужно пропускать права
if ($v['id'] == COT_GROUP_GUESTS || $v['id'] == COT_GROUP_INACTIVE) { // Если группа - гости или неактивные пользователи
$ins_auth = cot_auth_getvalue($info['Auth_guests']); // Получаем значение аутентификации для гостей
$ins_lock = cot_auth_getvalue($info['Lock_guests']); // Получаем значение блокировки для гостей
if ($ins_auth > 128 || $ins_lock < 128) { // Если аутентификация превышает 128 или блокировка меньше 128
$ins_auth = ($ins_auth > 127) ? $ins_auth - 128 : $ins_auth; // Корректируем значение аутентификации
$ins_lock = 128; // Устанавливаем значение блокировки для гостей
}
} elseif ($v['id'] == COT_GROUP_BANNED) { // Если группа - заблокированные пользователи
$ins_auth = 0; // Аутентификация для заблокированных - 0
$ins_lock = 255; // Блокировка для заблокированных - 255
} elseif ($v['id'] == COT_GROUP_SUPERADMINS) { // Если группа - супер администраторы
$ins_auth = 255; // Аутентификация для супер администраторов - 255
$ins_lock = 255; // Блокировка для супер администраторов - 255
} else { // Для остальных групп
$ins_auth = cot_auth_getvalue($info['Auth_members']); // Получаем значение аутентификации для пользователей
$ins_lock = cot_auth_getvalue($info['Lock_members']); // Получаем значение блокировки для пользователей
}
if ($isModule) { // Если это модуль
$insert_rows[] = array( // Добавляем данные для вставки
'auth_groupid' => $v['id'],
'auth_code' => $extensionCode,
'auth_option' => 'a',
'auth_rights' => $ins_auth,
'auth_rights_lock' => $ins_lock,
'auth_setbyuserid' => $usr['id']
);
} else { // Если это плагин
$insert_rows[] = array( // Добавляем данные для вставки
'auth_groupid' => $v['id'],
'auth_code' => 'plug',
'auth_option' => $extensionCode,
'auth_rights' => $ins_auth,
'auth_rights_lock' => $ins_lock,
'auth_setbyuserid' => $usr['id']
);
}
}
}
if ($db->insert($db_auth, $insert_rows)) { // Если данные успешно вставлены в базу
$db->update($db_users, array('user_auth' => ''), "user_auth != ''"); // Очищаем поле user_auth для всех пользователей, у которых оно не пустое
cot_message('ext_auth_installed'); // Сообщение об успешной установке аутентификации
}
}
$new_ver = ''; // Инициализация переменной для новой версии
if ($update) { // Если это обновление
// Находим и применяем патчи
if (file_exists("$path/setup")) { // Если существует папка с патчами
$new_ver = cot_apply_patches("$path/setup", $current_ver); // Применяем патчи и получаем новую версию
}
if (version_compare($info['Version'], $new_ver) > 0 || $new_ver === true) { // Если новая версия больше текущей или патчи применены успешно
$new_ver = $info['Version']; // Устанавливаем версию из информации об расширении
}
} else { // Если это установка
if (file_exists($path . "/setup/$extensionCode.install.sql")) { // Если существует SQL-скрипт для установки
// Выполняем SQL-скрипт установки
$sql_err = $db->runScript(
file_get_contents("$path/setup/$extensionCode.install.sql")); // Запускаем скрипт
if (empty($sql_err)) { // Если ошибок нет
cot_message(cot_rc('ext_executed_sql', array('ret' => 'OK'))); // Сообщение об успешном выполнении SQL-скрипта
} else { // Если есть ошибки
cot_error(cot_rc('ext_executed_sql', array('ret' => $sql_err))); // Сообщение об ошибках
return false; // Возвращаем false
}
}
$install_handler = $old_ext_format ? $setup_file : $path . "/setup/$extensionCode.install.php"; // Определяем путь к PHP-обработчику установки
if ($old_ext_format) { // Если используется старый формат
global $action;
$action = 'install'; // Устанавливаем действие как 'install'
}
if (file_exists($install_handler)) { // Если существует файл обработчика установки
// Выполняем PHP-обработчик установки
$envtmp = $env; // Сохраняем текущее состояние переменной $env
$env = array( // Устанавливаем параметры окружения для установки
'ext' => $extensionCode,
'location' => $extensionCode,
'type' => ($isModule) ? 'module' : 'plug' // Определяем тип расширения
);
$ret = include $install_handler; // Подключаем и выполняем файл обработчика
$env = $envtmp; // Восстанавливаем исходное состояние переменной $env
if ($ret !== false) { // Если выполнение обработчика прошло успешно
$msg = $ret == 1 ? 'OK' : $ret; // Устанавливаем сообщение в зависимости от результата
cot_message(cot_rc('ext_executed_php', array('ret' => $msg))); // Сообщение о выполнении PHP-обработчика
} else { // Если выполнение обработчика завершилось с ошибкой
cot_error(cot_rc('ext_executed_php',
array('ret' => $msg ? $msg : $L['Error']))); // Сообщение об ошибке
return false; // Возвращаем false
}
}
}
// Регистрируем информацию о версии
if ($update) { // Если это обновление
cot_extension_update($extensionCode, $new_ver, !$isModule); // Обновляем информацию о расширении
ExtensionsControlService::getInstance()->checkIsActive($extensionCode); // Проверяем, активировано ли расширение
cot_message(cot_rc('ext_updated', array( // Отправляем сообщение об успешном обновлении
'type' => $isModule ? $L['Module'] : $L['Plugin'], // Тип расширения (модуль или плагин)
'name' => $extensionCode, // Имя расширения
'ver' => $new_ver // Новая версия
)));
/* === Hook === */
foreach (cot_getextplugins('extension.update.done') as $pl) { // Применяем хуки после обновления расширения
include $pl; // Подключаем и выполняем хук
}
/* ===== */
} else { // Если это установка
cot_extension_add($extensionCode, $info['Name'], $info['Version'], !$isModule); // Регистрируем новое расширение
/* === Hook === */
foreach (cot_getextplugins('extension.install.done') as $pl) { // Применяем хуки после установки расширения
include $pl; // Подключаем и выполняем хук
}
/* ===== */
}
// Очистка
cot_auth_reorder(); // Перераспределение прав доступа
$cache && $cache->clear(); // Очистка кэша, если он активирован
конец функции cot_extension_install
return true; }
код ниже выполняет удаление расширения (модуля или плагина), включая очистку конфигураций, привязок, структуры, выполнение SQL-скриптов, запуск PHP-обработчиков, удаление расширения из основной таблицы и очистку кэша.
/**
* Удаляет расширение и все его данные
* @param string $code Код расширения
* @param bool $isModule TRUE для модулей, FALSE для плагинов
* @global CotDB $db
* @global Cache $cache
*/
function cot_extension_uninstall($code, $isModule = false)
{
global $cfg, $db_auth, $db_config, $db_users, $db_updates, $cache, $db, $db_x, $db_plugins, $cot_plugins,
$cot_plugins_enabled, $cot_modules, $env, $structure, $db_structure, $L, $R;
$path = $isModule ? $cfg['modules_dir'] . "/$code" : $cfg['plugins_dir'] . "/$code"; // Определяем путь к расширению
// Отправляем начальное сообщение
cot_message(cot_rc('ext_uninstalling', array(
'type' => $isModule ? Cot::$L['Module'] : Cot::$L['Plugin'], // Тип расширения (модуль или плагин)
'name' => $code // Имя расширения
)));
// Удаляем привязки плагина
cot_plugin_remove($code);
// Удаляем данные авторизации и конфигурации
if ($isModule) {
Cot::$db->delete($db_config, "config_owner = 'module' AND config_cat = '$code'"); // Удаляем конфигурацию модуля
Cot::$db->delete($db_auth, "auth_code = '$code'"); // Удаляем права доступа для модуля
} else {
Cot::$db->delete($db_config, "config_owner = 'plug' AND config_cat = '$code'"); // Удаляем конфигурацию плагина
Cot::$db->delete($db_auth, "auth_code = 'plug' AND auth_option = '$code'"); // Удаляем права доступа для плагина
}
cot_message('ext_auth_uninstalled'); // Отправляем сообщение об удалении прав доступа
cot_message('ext_config_uninstalled'); // Отправляем сообщение об удалении конфигурации
// Удаляем структуру расширения
if ($isModule && isset($structure[$code])) {
$db->delete($db_structure, "structure_area = ?", $code); // Удаляем структуру для модуля
unset($structure[$code]); // Удаляем структуру из массива
}
// Запускаем SQL-скрипт, если он есть
if (file_exists($path . "/setup/$code.uninstall.sql")) {
$sql_err = $db->runScript(
file_get_contents("$path/setup/$code.uninstall.sql")); // Выполняем SQL-скрипт
if (empty($sql_err)) {
cot_message(cot_rc('ext_executed_sql', ['ret' => 'OK'])); // Отправляем сообщение об успешном выполнении SQL
} else {
cot_error(cot_rc('ext_executed_sql', ['ret' => $sql_err])); // Отправляем сообщение об ошибке в SQL
}
}
// Запускаем обработчик удаления
if (cot_plugin_active('genoa') && cot_infoget($path . "/$code.setup.php", 'SED_EXTPLUGIN')) {
global $action;
$action = 'uninstall'; // Устанавливаем действие как 'uninstall'
$uninstall_handler = $path . "/$code.setup.php"; // Указываем путь к обработчику удаления
} else {
$uninstall_handler = $path . "/setup/$code.uninstall.php"; // Указываем путь к установочному скрипту для плагина
}
if (file_exists($uninstall_handler)) {
$envtmp = $env;
$env = [
'ext' => $code, // Устанавливаем переменные окружения для расширения
'location' => $code,
'type' => ($isModule) ? ExtensionsDictionary::TYPE_MODULE : ExtensionsDictionary::TYPE_PLUGIN,
];
$ret = include $uninstall_handler; // Выполняем обработчик
$env = $envtmp;
if ($ret !== false) {
cot_message(cot_rc('ext_executed_php', ['ret' => $ret])); // Отправляем сообщение о выполнении PHP-скрипта
} else {
cot_error(cot_rc('ext_executed_php', ['ret' => Cot::$L['Error']])); // Отправляем сообщение об ошибке в PHP-скрипте
}
}
// Убираем расширение из основной таблицы
cot_extension_remove($code, !$isModule);
$sql = $db->query("SELECT pl_code, pl_file, pl_hook, pl_module FROM $db_plugins
WHERE pl_active = 1 ORDER BY pl_hook ASC, pl_order ASC"); // Получаем все активные плагины
$cot_plugins = array();
if ($sql->rowCount() > 0) {
while ($row = $sql->fetch()) {
$cot_plugins[$row['pl_hook']][] = $row; // Заполняем массив с плагинами по хук-ключу
}
$sql->closeCursor();
}
if (!$isModule) {
unset($cot_plugins_enabled[$code]); // Удаляем плагин из списка активных плагинов
} else {
unset($cot_modules[$code]); // Удаляем модуль из списка активных модулей
}
/* === Hook === */
foreach (cot_getextplugins('extension.uninstall.done') as $pl) { // Выполняем хуки после удаления расширения
include $pl;
}
/* ===== */
// Очищаем кэш
$db->update($db_users, array('user_auth' => ''), "user_auth != ''"); // Сбрасываем кэш прав доступа пользователей
$cache && $cache->clear(); // Очищаем кэш, если он включен
}
/**
* Парсит заголовок PHPDoc из файла в массив
*
* @param string $filename Путь к PHP файлу
* @return array Ассоциативный массив, содержащий содержимое PHPDoc. Массив будет
* пустым, если PHPDoc не найден
*/
function cot_file_phpdoc($filename)
{
$res = array(); // Инициализация пустого массива для хранения результатов
$data = file_get_contents($filename); // Чтение содержимого файла в переменную $data
// Проверка на наличие блока PHPDoc в файле с использованием регулярного выражения
if (preg_match('#^/\*\*(.*?)^\s\*/#ms', $data, $mt))
{
$phpdoc = preg_split('#\r?\n\s\*\s@#', $mt[1]); // Разделение содержимого PHPDoc по строкам с использованием @ как разделителя
$cnt = count($phpdoc); // Получение количества элементов в массиве $phpdoc
if ($cnt > 0) // Если в массиве есть элементы
{
$res['description'] = trim(preg_replace('#\r?\n\s\*\s?#', '', $phpdoc[0]));
// Очищаем описание (первую строку) от лишних символов и сохраняем его в ключ 'description'
for ($i = 1; $i < $cnt; $i++) // Начинаем цикл с 1, чтобы пропустить описание
{
$delim = mb_strpos($phpdoc[$i], ' '); // Находим позицию первого пробела в строке, это разделитель ключа и значения
$key = mb_substr($phpdoc[$i], 0, $delim); // Извлекаем ключ (часть до пробела)
// Извлекаем значение (всё, что после пробела) и очищаем от лишних символов
$contents = trim(preg_replace('#\r?\n\s\*\s?#', '', mb_substr($phpdoc[$i], $delim + 1)));
$res[$key] = $contents; // Добавляем ключ и значение в ассоциативный массив $res
}
}
}
return $res; // Возвращаем ассоциативный массив с содержимым PHPDoc
}
Разбор:
-
Функция
cot_file_phpdoc— предназначена для парсинга комментариев в формате PHPDoc из указанного файла и возврата содержимого в виде ассоциативного массива. -
Чтение файла — содержимое файла считывается с помощью
file_get_contents($filename)и сохраняется в переменной$data. -
Регулярное выражение — с помощью
preg_matchпроверяется наличие блока PHPDoc в начале файла. Регулярное выражение ищет начало комментария с/**и конец с*/. Весь текст между ними сохраняется в переменную$mt. -
Разбиение PHPDoc — содержимое блока PHPDoc разбивается на строки с использованием
preg_split, разделяя строки, содержащие теги, такие как@param,@returnи другие. -
Обработка каждой строки PHPDoc — для каждой строки:
- Извлекается ключ (например,
param,return), который находится до первого пробела. - С помощью регулярного выражения очищается описание от лишних символов и сохраняется в массив с соответствующим ключом.
- Извлекается ключ (например,
-
Возвращение результата — возвращается ассоциативный массив с ключами и значениями, соответствующими данным из блока PHPDoc.
Функция полезна для получения метаинформации о функциях, классах или методах, описанных в комментариях PHPDoc.
/**
* Извлекает информацию из заголовков файлов COT
*
* @param string $file Путь к файлу
* @param string $limiter Название тега
* @param int $maxsize Максимальный размер заголовка
* @return array Массив с данными блока или FALSE в случае ошибки
*/
function cot_infoget($file, $limiter = 'COT_EXT', $maxsize = 32768)
{
$result = []; // Инициализация пустого массива для хранения результатов
// Структура данных по умолчанию
if ($limiter == 'COT_EXT' || $limiter == 'SED_EXTPLUGIN') {
$result = [
'Code' => '', // Код расширения
'Name' => '', // Название расширения
'Description' => '', // Описание расширения
'Category' => '', // Категория расширения
'Version' => '', // Версия расширения
'Date' => '', // Дата создания расширения
'Author' => '', // Автор расширения
'Copyright' => '', // Авторские права
'Notes' => '', // Заметки
'Auth_members' => '', // Доступ для зарегистрированных пользователей
'Lock_members' => '', // Ограничения для зарегистрированных пользователей
'Auth_guests' => '', // Доступ для гостей
'Lock_guests' => '', // Ограничения для гостей
];
// Если тег COT_EXT, добавляем дополнительные поля
if ($limiter == 'COT_EXT') {
$result['Requires_modules'] = ''; // Модули, которые требуются
$result['Requires_plugins'] = ''; // Плагины, которые требуются
$result['Recommends_modules'] = ''; // Рекомендуемые модули
$result['Recommends_plugins'] = ''; // Рекомендуемые плагины
}
}
$fp = @fopen($file, 'r'); // Открытие файла на чтение в режиме r (без создания файла, если его нет)
if ($fp) { // Если файл успешно открыт
// Формирование ограничителей начала и конца блока на основе тега
$limiter_begin = '[BEGIN_' . $limiter . ']';
$limiter_end = '[END_' . $limiter . ']';
$data = fread($fp, $maxsize); // Чтение данных из файла с ограничением по размеру $maxsize
$begin = mb_strpos($data, $limiter_begin); // Нахождение позиции начала блока
$end = mb_strpos($data, $limiter_end); // Нахождение позиции конца блока
if ($end > $begin && $begin > 0) { // Если конец блока найден и его начало корректно
// Извлекаем данные между ограничителями
$lines = mb_substr($data, $begin + 8 + mb_strlen($limiter),
$end - $begin - mb_strlen($limiter) - 8);
$lines = explode("\n", $lines); // Разделяем данные на строки
foreach ($lines as $line) { // Для каждой строки
$line = ltrim($line, " */"); // Убираем начальные символы пробела, звездочки или косой черты
$linex = preg_split('/\s*\=\s*/', trim($line), 2); // Разделяем строку по символу "=" на ключ и значение
if ($linex[0]) { // Если есть ключ
$result[$linex[0]] = isset($linex[1]) ? $linex[1] : ''; // Сохраняем ключ и его значение в массив
}
}
} else { // Если блок не найден
$result = false; // Возвращаем false
}
} else { // Если файл не открыт
$result = false; // Возвращаем false
}
@fclose($fp); // Закрытие файла (с suppress оператором для игнорирования ошибок)
return $result; // Возвращаем массив с данными или false в случае ошибки
}
Разбор:
-
Функция
cot_infoget— предназначена для извлечения данных из заголовков файлов Cotonti, которые находятся между тегами, указанными в параметре$limiter. Эта функция может быть полезна для получения информации о расширениях или плагинах. -
Параметры функции:
$file— путь к файлу, из которого нужно извлечь информацию.$limiter— тег, который определяет начало и конец блока, который нужно извлечь (по умолчанию 'COT_EXT').$maxsize— максимальный размер данных, которые могут быть прочитаны из файла.
-
Структура данных по умолчанию — в зависимости от значения
$limiter, создается структура массива для хранения данных о расширении. -
Чтение данных из файла — файл открывается для чтения, и данные считываются с ограничением по размеру, заданному параметром
$maxsize. -
Поиск блоков данных — данные между тегами
[BEGIN_COT_EXT]и[END_COT_EXT]извлекаются из файла. Если блок найден, данные обрабатываются. -
Обработка строк — каждая строка в блоке разбивается по символу "=", и результат сохраняется в ассоциативный массив.
-
Закрытие файла — файл закрывается после чтения.
-
Возвращение результатов — возвращается массив с данными, если блок найден, или
false, если произошла ошибка.
/**
* Регистрирует расширение в ядре
*
* @param string $name Название расширения (код)
* @param string $title Название
* @param string $version Номер версии в формате A.B.C
* @param bool $is_plug Является ли это плагином
* @return bool TRUE в случае успеха, FALSE в случае ошибки
* @global CotDB $db Объект базы данных
*/
function cot_extension_add($name, $title, $version = '1.0.0', $is_plug = false)
{
global $db, $db_core; // Использование глобальных переменных для доступа к объекту базы данных и к основной таблице базы данных
// Выполняем вставку данных о расширении в таблицу базы данных
$res = $db->insert($db_core, array(
'ct_code' => $name, // Код расширения
'ct_title' => $title, // Название расширения
'ct_version' => $version, // Версия расширения
'ct_plug' => (int) $is_plug // Преобразуем значение флага плагина в целое число (0 или 1)
));
// Возвращаем TRUE, если вставка данных в базу данных прошла успешно, иначе FALSE
return $res > 0;
}
Разбор:
-
Функция
cot_extension_add— предназначена для регистрации нового расширения (или плагина) в ядре системы. -
Параметры функции:
$name— код расширения (уникальное название расширения).$title— название расширения (например, "Мой плагин").$version— версия расширения, по умолчанию задано значение '1.0.0'.$is_plug— флаг, указывающий, является ли расширение плагином. Если это плагин, то значениеtrue, если нет —false.
-
Глобальные переменные:
$db— объект базы данных, через который выполняются операции с БД.$db_core— имя таблицы, в которую будет произведена вставка данных.
-
Вставка данных — функция вызывает метод
insertобъекта$db, который добавляет новую запись в таблицу базы данных$db_core. Вставляются данные о расширении (код, название, версия и флаг плагина). -
Возвращаемое значение — если операция вставки прошла успешно (результат больше 0), возвращается
TRUE, иначе —FALSE.
/**
* Сравнивает две записи информации об расширениях по коду категории.
* Расширения, установленные после установки, всегда идут последними.
*
* @param array $ext1 Информация о расширении 1
* @param array $ext2 Информация о расширении 2
* @return int Результат сравнения: 0 — если элементы одинаковы, 1 или -1 — если элементы разные
*/
function cot_extension_catcmp($ext1, $ext2)
{
global $L; // Глобальная переменная для доступа к локализованным строкам
// Если категория первого расширения существует в локализованных строках, заменяем ее на локализованную версию
if (isset($L['ext_cat_' . $ext1['Category']]))
{
$ext1['Category'] = $L['ext_cat_' . $ext1['Category']];
}
// Если категория второго расширения существует в локализованных строках, заменяем ее на локализованную версию
if (isset($L['ext_cat_' . $ext2['Category']]))
{
$ext2['Category'] = $L['ext_cat_' . $ext2['Category']];
}
// Если категории двух расширений одинаковые
if ($ext1['Category'] == $ext2['Category'])
{
// Если названия расширений одинаковые, возвращаем 0 (значения равны)
if ($ext1['Name'] == $ext2['Name'])
{
return 0;
}
else
{
// Если названия расширений разные, возвращаем 1 или -1 в зависимости от лексикографического сравнения
return ($ext1['Name'] > $ext2['Name']) ? 1 : -1;
}
}
else
{
// Если категории разные, то расширение с "большей" категорией (или если категория 'post-install') идет позже
return ($ext1['Category'] > $ext2['Category'] || $ext1['Category'] == 'post-install') ? 1 : -1;
}
}
Разбор:
-
Функция
cot_extension_catcmp— предназначена для сравнения двух расширений по категории и имени. В результате этого сравнения расширения сортируются в нужном порядке. -
Параметры функции:
$ext1и$ext2— массивы с информацией о расширениях, которые будут сравниваться.
-
Локализация категорий:
- Переменная
$Lсодержит локализованные строки для категорий расширений. Если категория расширения существует в этом массиве, она заменяется на локализованное название.
- Переменная
-
Сравнение категорий:
- Если категории расширений одинаковы, то сравниваются их имена. Если имена одинаковы, возвращается 0 (элементы равны).
- Если имена разные, возвращается 1 или -1 в зависимости от того, какое имя лексикографически больше.
-
Сравнение категорий, если они разные:
- Если категории расширений разные, то расширение с "большей" категорией (в соответствии с лексикографическим порядком) или расширение с категорией
'post-install'будет располагаться после другого.
- Если категории расширений разные, то расширение с "большей" категорией (в соответствии с лексикографическим порядком) или расширение с категорией
/**
* Проверяет, установлено ли расширение
*
* @param string $extensionCode Код расширения
* @return bool TRUE, если расширение установлено, иначе FALSE
* @deprecated Эта функция устарела
* @see ExtensionsService::isInstalled() Используйте этот метод вместо текущего
*/
function cot_extension_installed($extensionCode)
{
// Если код расширения пустой, возвращаем FALSE
if (empty($extensionCode)) {
return false;
}
// Используем сервис ExtensionsService для проверки, установлено ли расширение
return ExtensionsService::getInstance()->isInstalled($extensionCode);
}
Разбор:
-
Функция
cot_extension_installed— проверяет, установлено ли расширение с заданным кодом. Это устаревшая функция, и рекомендуется использовать методExtensionsService::isInstalled(). -
Параметр:
$extensionCode— код расширения, которое нужно проверить на установку.
-
Логика работы:
- Если код расширения пустой, функция возвращает
false, так как проверка не может быть выполнена. - Если код расширения не пустой, используется класс
ExtensionsService, методisInstalled()для выполнения проверки. Этот метод возвращаетtrue, если расширение установлено, иfalse, если нет.
- Если код расширения пустой, функция возвращает
-
Депрецированный статус:
- Функция помечена как устаревшая (
@deprecated), и рекомендуется использовать вместо нее более современный методExtensionsService::isInstalled().
- Функция помечена как устаревшая (
/**
* Returns installed extension type: 'module' if extension is a module,
* 'plug' if extension is a plugin or FALSE if extension is not installed.
*
* @param string $name Module code
* @return mixed
* @global CotDB $db
* @deprecated
* @see ExtensionsService::getType()
*/
function cot_extension_type($name)
{
global $db, $db_core;
$res = $db->query("SELECT ct_plug FROM $db_core WHERE ct_code = ?", $name);
if ($res->rowCount() == 0)
{
return false;
}
$is_plug = (int) $res->fetchColumn();
return $is_plug ? 'plug' : 'module';
}
Разбор:
-
Функция
cot_extension_type— проверяет тип расширения по его коду (модуль или плагин). -
Параметр:
$name— код расширения (модуля или плагина), для которого нужно определить тип.
-
Логика работы:
- Выполняется SQL-запрос к базе данных для получения значения поля
ct_plugиз таблицы расширений ($db_core). Это поле указывает, является ли расширение плагином или модулем. - Если расширение не найдено в базе (нет строки с таким кодом), функция возвращает
false. - Если расширение найдено, то проверяется значение поля
ct_plug:- Если это плагин (значение поля равно 1), возвращается строка
'plug'. - Если это модуль (значение поля равно 0), возвращается строка
'module'.
- Если это плагин (значение поля равно 1), возвращается строка
- Выполняется SQL-запрос к базе данных для получения значения поля
-
Депрецированный статус:
- Функция помечена как устаревшая (
@deprecated), и рекомендуется использовать вместо нее более современный методExtensionsService::getType().
- Функция помечена как устаревшая (
/**
* Возвращает массив, содержащий метаинформацию для всех расширений в каталоге
*
* @param string $dir Каталог для поиска расширений
* @return array Массив с кодами расширений и информацией о них
*/
function cot_extension_list_info($dir)
{
$ext_list = array(); // Массив для хранения информации о расширениях
clearstatcache(); // Очищаем кэш статистики файлов, чтобы обновленные данные были корректными
$dp = opendir($dir); // Открываем каталог для чтения
// Перебираем все файлы и каталоги в указанном каталоге
while ($f = readdir($dp))
{
$path = $dir . '/' . $f; // Формируем полный путь к текущему элементу
// Проверяем, что это не скрытая папка (начинающаяся с точки),
// это действительно каталог и в нем есть файл $f.setup.php
if ($f[0] != '.' && is_dir($path) && file_exists("$path/$f.setup.php"))
{
// Загружаем метаинформацию о расширении из файла $f.setup.php
$info = cot_infoget("$path/$f.setup.php", 'COT_EXT');
// Если метаинформация не загружена, пробуем загрузить в старом формате для плагинов
if (!$info && cot_plugin_active('genoa')) {
$info = cot_infoget("$path/$f.setup.php", 'SED_EXTPLUGIN');
}
// Если информация не найдена, используем значения по умолчанию
if ($info == false) {
// Не удалось загрузить блок информации
// Используем данные по умолчанию
$info = array(
'Code' => $f, // Код расширения
'Name' => $f, // Название расширения (по умолчанию совпадает с кодом)
'Description' => '', // Описание
'Category' => '', // Категория
'Version' => '', // Версия
'Date' => '', // Дата
'Author' => '', // Автор
'Copyright' => '', // Авторские права
'Notes' => '', // Примечания
'Auth_members' => '', // Права для участников
'Lock_members' => '', // Блокировка для участников
'Auth_guests' => '', // Права для гостей
'Lock_guests' => '', // Блокировка для гостей
'Requires_modules' => '', // Требуемые модули
'Requires_plugins' => '', // Требуемые плагины
'Recommends_modules' => '', // Рекомендуемые модули
'Recommends_plugins' => '' // Рекомендуемые плагины
);
}
// Если категория не указана, задаем значение по умолчанию
if (empty($info['Category'])) {
$info['Category'] = 'misc-ext'; // Устанавливаем категорию как 'misc-ext'
}
// Добавляем информацию о расширении в массив
$ext_list[$f] = $info;
}
}
closedir($dp); // Закрываем каталог
return $ext_list; // Возвращаем массив с информацией о расширениях
}
Разбор:
-
Функция
cot_extension_list_info— собирает информацию о всех расширениях в указанном каталоге и возвращает эту информацию в виде ассоциативного массива. -
Параметр:
$dir— путь к каталогу, в котором нужно искать расширения.
-
Алгоритм работы:
- Очищается кэш статистики файлов с помощью
clearstatcache(), чтобы убедиться, что файлы и каталоги будут проверены заново. - Открывается указанный каталог с помощью
opendir(). - Перебираются все элементы в каталоге с помощью
readdir(). Для каждого элемента проверяется:- Это не скрытая папка (не начинается с точки).
- Это действительно каталог.
- В каталоге существует файл с именем
$f.setup.php.
- Если файл с метаинформацией найден, вызывается функция
cot_infoget()для извлечения информации из него.- Если информация не была загружена, пробуется старый формат для плагинов, если активирован плагин "genoa".
- Если не удается получить информацию, используется массив с данными по умолчанию.
- Если категория расширения не указана, она устанавливается как
'misc-ext'. - В массив
$ext_listдобавляется информация о расширении. - Закрывается каталог с помощью
closedir().
- Очищается кэш статистики файлов с помощью
-
Возвращаемое значение:
- Массив
$ext_list, где ключами являются коды расширений, а значениями — ассоциативные массивы с информацией о расширениях.
- Массив
/**
* Удаляет модуль из ядра
*
* @param string $name Название модуля
* @return bool Возвращает true, если модуль был удален успешно, иначе false
* @global CotDB $db Объект базы данных
*/
function cot_extension_remove($name)
{
global $db, $db_core; // Получаем доступ к объекту базы данных и таблице ядра
// Выполняем запрос на удаление записи в таблице ядра с кодом модуля, равным $name
return $db->delete($db_core, "ct_code = '$name'"); // Удаляем запись с кодом расширения $name
}
Разбор:
-
Функция
cot_extension_remove— удаляет модуль из базы данных ядра системы. -
Параметр:
$name— название (код) модуля, который нужно удалить.
-
Алгоритм работы:
- С помощью глобальной переменной
$dbвыполняется запрос на удаление записи из таблицы ядра, которая хранит информацию о модулях. - Удаляется запись, где поле
ct_codeсоответствует значению$name.
- С помощью глобальной переменной
-
Возвращаемое значение:
- Возвращает результат выполнения операции удаления:
true, если запись успешно удалена.false, если произошла ошибка при удалении.
- Возвращает результат выполнения операции удаления:
/**
* Обновляет номер версии модуля в реестре
*
* @param string $name Название модуля
* @param string $version Новая строка версии
* @return bool Возвращает true, если версия была обновлена успешно, иначе false
* @global CotDB $db Объект базы данных
*/
function cot_extension_update($name, $version)
{
global $db, $db_core; // Получаем доступ к объекту базы данных и таблице ядра
// Выполняем запрос на обновление версии модуля в таблице ядра для модуля с кодом $name
return $db->update($db_core, array('ct_version' => $version), "ct_code = '$name'"); // Обновляем поле версии для модуля $name
}
Разбор:
-
Функция
cot_extension_update— обновляет номер версии модуля в базе данных ядра системы. -
Параметры:
$name— название (код) модуля, версию которого нужно обновить.$version— новая версия модуля в виде строки.
-
Алгоритм работы:
- С помощью глобальной переменной
$dbвыполняется запрос на обновление поляct_versionв таблице ядра, где код модуля равен$name. - Обновляется только версия модуля, другие поля остаются без изменений.
- С помощью глобальной переменной
-
Возвращаемое значение:
- Возвращает результат выполнения операции обновления:
true, если версия была обновлена успешно.false, если произошла ошибка при обновлении.
- Возвращает результат выполнения операции обновления:
/**
* Регистрирует плагин или модуль в реестре хуков
*
* Пример:
* <code>
* $hook_bindings = array(
* array(
* 'part' => 'rss', // Часть плагина
* 'hook' => 'rss.main', // Хук, с которым связан плагин
* 'order' => 20 // Порядок выполнения
* ),
* array(
* 'part' => 'header', // Часть плагина
* 'hook' => 'header.tags', // Хук для заголовков
* )
* );
*
* cot_plugin_add($hook_bindings, 'test', 'Test plugin', false);
* </code>
*
* @param array $hook_bindings Маппинг привязки хуков
* @param string $code Название модуля или плагина (код)
* @param string $title Название модуля или плагина
* @param bool $isModule TRUE для модулей, FALSE для плагинов
* @return int Количество добавленных записей
* @global CotDB $db Объект базы данных
*/
function cot_plugin_add($hook_bindings, $code, $title, $isModule = false)
{
// Если название плагина пустое, устанавливаем его равным коду
if (empty($title)) {
$title = $code;
}
// Массив для добавляемых строк в таблицу
$insertRows = [];
// Проходим по каждой привязке хука
foreach ($hook_bindings as $binding) {
// Устанавливаем активность хука по умолчанию в 1 (активен)
$active = 1;
// Если в привязке указано 'active' и оно равно 0, то деактивируем хук
if (isset($binding['active']) && !$binding['active']) {
$active = 0;
}
// Добавляем строку для вставки в массив
$insertRows[] = [
'pl_hook' => $binding['hook'], // Хук
'pl_code' => $code, // Код плагина или модуля
'pl_part' => $binding['part'], // Часть плагина
'pl_title' => $title, // Название плагина или модуля
'pl_file' => empty($binding['file']) ? "$code/$code.{$binding['part']}.php" : $code . '/' . $binding['file'], // Путь к файлу
'pl_order' => $binding['order'], // Порядок выполнения
'pl_active' => $active, // Активность хука
'pl_module' => (int) $isModule // Тип: 1 — модуль, 0 — плагин
];
}
// Начинаем транзакцию базы данных
Cot::$db->beginTransaction();
try {
// Вставляем записи в таблицу хуков плагинов
$result = Cot::$db->insert(Cot::$db->plugins, $insertRows);
// Если все прошло успешно, подтверждаем транзакцию
Cot::$db->commit();
} catch (Exception $e) {
// Если произошла ошибка, откатываем транзакцию
Cot::$db->rollBack();
return 0; // Возвращаем 0 в случае ошибки
}
// Возвращаем количество добавленных записей
return $result;
}
Разбор:
-
Функция
cot_plugin_add— используется для регистрации плагинов или модулей в системе, а точнее — в реестре хуков. Хуки — это механизмы для расширения функционала системы, которые позволяют подключать и управлять плагинами и модулями. -
Параметры:
$hook_bindings— массив, который содержит информацию о привязке плагина или модуля к хука. В нем указываются:part— часть плагина (например, 'rss', 'header').hook— сам хук (например, 'rss.main', 'header.tags').order— порядок выполнения.active(необязательно) — активен ли плагин (1 — активен, 0 — не активен).file(необязательно) — путь к файлу плагина для данной части.
$code— уникальный код плагина или модуля.$title— название плагина или модуля.$isModule— если значение равноtrue, то это модуль, еслиfalse— плагин.
-
Алгоритм работы:
- Если название плагина не указано, оно будет равно коду.
- Для каждой привязки хука создается запись в массиве
$insertRowsс необходимыми полями (название, путь к файлу, активность и т. д.). - Затем начинается транзакция в базе данных для вставки данных.
- В случае ошибки транзакция откатывается.
- Если вставка прошла успешно, то транзакция коммитится, и возвращается количество добавленных записей.
-
Возвращаемое значение:
- Количество записей, успешно добавленных в базу данных.
- Если возникла ошибка при добавлении записей, возвращается
0.
/**
* Удаляет плагин или одну из его частей из реестра хуков
*
* @param string $name Название модуля или плагина
* @param int $binding_id ID привязки, которую нужно удалить, или 0 для удаления всех привязок
* @return int Количество удалённых привязок
* @global CotDB $db Объект базы данных
*/
function cot_plugin_remove($name, $binding_id = 0)
{
global $db, $db_plugins;
// Строим условие для поиска привязки по коду плагина
$condition = "pl_code = '$name'";
// Если передан идентификатор привязки, добавляем его в условие
if ($binding_id > 0) {
$condition .= " AND pl_id = $binding_id";
}
// Выполняем удаление из таблицы хуков плагинов и возвращаем количество удалённых записей
return $db->delete($db_plugins, $condition);
}
Разбор:
-
Функция
cot_plugin_remove— используется для удаления плагина или его части (привязки) из реестра хуков. Хуки позволяют плагинам и модулям взаимодействовать с основным функционалом системы. -
Параметры:
$name— код плагина или модуля, который нужно удалить.$binding_id— идентификатор привязки, которую нужно удалить. Если передать0, то удалятся все привязки для данного плагина.
-
Алгоритм работы:
- Строится условие для поиска привязок с данным кодом плагина (
pl_code = '$name'). - Если передан ID привязки (
$binding_id > 0), то условие расширяется для удаления конкретной привязки с этим ID. - Выполняется удаление записи из таблицы
db_pluginsс использованием условия$condition. - Возвращается количество удалённых привязок.
- Строится условие для поиска привязок с данным кодом плагина (
-
Возвращаемое значение:
- Функция возвращает количество удалённых привязок из базы данных.
Таким образом, данная функция помогает удалять как все привязки плагина, так и конкретную привязку по её ID из реестра хуков.
Комментарии (0)
Автор контента
Оффлайн
Administrator
Последняя авторизация: 05.07.2026 18:32
- Страница размещена: 26.01.2025 12:19
- Последнее обновление: 26.01.2025 13:06