Файл extensions.php в Cotonti

Файл extensions.php в системной папке Cotonti CMF имеет основное назначение управлять расширениями системы. В частности, его функциональность охватывает операции, связанные с добавлением, удалением, обновлением и получением информации о расширениях (модулях и плагинах). Также он выполняет регистрационные действия для модулей и плагинов в ядре системы и работает с метаинформацией расширений, получаемой из их заголовков.

Основные действия, которые реализует код:

  1. Чтение и анализ заголовков расширений с помощью регулярных выражений, чтобы извлечь метаинформацию.
  2. Регистрация новых расширений в базе данных.
  3. Обновление и удаление расширений.
  4. Управление связями расширений с хуками (например, добавление или удаление привязок плагинов к определённым хук-пунктам).
  5. Обработка информации о категориях и зависимости расширений (модули и плагины).

Стиль PHP, который используется в данном файле, можно охарактеризовать как стандартный для программирования в Cotonti CMF:

  • Используются глобальные переменные, например, $db, для работы с базой данных.
  • Код имеет строгую структуру с ясным разделением функциональности на отдельные функции.
  • Активно используется обработка ошибок с использованием конструкций try-catch для работы с транзакциями в базе данных.
  • Применяются регулярные выражения и манипуляции с текстом для извлечения данных из файлов.
  • Используются стандартные средства работы с базой данных, такие как методы $db->insert(), $db->delete(), и $db->update().
  • Для улучшения читаемости и предотвращения ошибок работы с файлами используется конструкция @fopen() с проверкой на успешное открытие файла.

Также заметно, что код активно использует транзакции для обеспечения целостности данных при добавлении расширений и их привязок к хукам.

 

Вот список всех функций в файле extensions.php:

  1. cot_infoget
    Функция извлекает информацию из заголовков COT файлов.

  2. cot_extension_add
    Функция для регистрации расширения в базе данных.

  3. cot_extension_catcmp
    Функция сравнивает два расширения по коду категории.

  4. cot_extension_installed
    Функция проверяет, установлено ли расширение. (Помечена как устаревшая.)

  5. cot_extension_type
    Функция возвращает тип расширения (модуль или плагин). (Помечена как устаревшая.)

  6. cot_extension_list_info
    Функция возвращает массив с метаинформацией всех расширений в указанной директории.

  7. cot_extension_remove
    Функция удаляет расширение из базы данных.

  8. cot_extension_update
    Функция обновляет версию расширения в базе данных.

  9. cot_plugin_add
    Функция добавляет плагин или его части в реестр хуков.

  10. 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
}

Разбор:

  1. Функция cot_file_phpdoc — предназначена для парсинга комментариев в формате PHPDoc из указанного файла и возврата содержимого в виде ассоциативного массива.

  2. Чтение файла — содержимое файла считывается с помощью file_get_contents($filename) и сохраняется в переменной $data.

  3. Регулярное выражение — с помощью preg_match проверяется наличие блока PHPDoc в начале файла. Регулярное выражение ищет начало комментария с /** и конец с */. Весь текст между ними сохраняется в переменную $mt.

  4. Разбиение PHPDoc — содержимое блока PHPDoc разбивается на строки с использованием preg_split, разделяя строки, содержащие теги, такие как @param, @return и другие.

  5. Обработка каждой строки PHPDoc — для каждой строки:

    • Извлекается ключ (например, param, return), который находится до первого пробела.
    • С помощью регулярного выражения очищается описание от лишних символов и сохраняется в массив с соответствующим ключом.
  6. Возвращение результата — возвращается ассоциативный массив с ключами и значениями, соответствующими данным из блока 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 в случае ошибки
}

Разбор:

  1. Функция cot_infoget — предназначена для извлечения данных из заголовков файлов Cotonti, которые находятся между тегами, указанными в параметре $limiter. Эта функция может быть полезна для получения информации о расширениях или плагинах.

  2. Параметры функции:

    • $file — путь к файлу, из которого нужно извлечь информацию.
    • $limiter — тег, который определяет начало и конец блока, который нужно извлечь (по умолчанию 'COT_EXT').
    • $maxsize — максимальный размер данных, которые могут быть прочитаны из файла.
  3. Структура данных по умолчанию — в зависимости от значения $limiter, создается структура массива для хранения данных о расширении.

  4. Чтение данных из файла — файл открывается для чтения, и данные считываются с ограничением по размеру, заданному параметром $maxsize.

  5. Поиск блоков данных — данные между тегами [BEGIN_COT_EXT] и [END_COT_EXT] извлекаются из файла. Если блок найден, данные обрабатываются.

  6. Обработка строк — каждая строка в блоке разбивается по символу "=", и результат сохраняется в ассоциативный массив.

  7. Закрытие файла — файл закрывается после чтения.

  8. Возвращение результатов — возвращается массив с данными, если блок найден, или 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;
}

Разбор:

  1. Функция cot_extension_add — предназначена для регистрации нового расширения (или плагина) в ядре системы.

  2. Параметры функции:

    • $name — код расширения (уникальное название расширения).
    • $title — название расширения (например, "Мой плагин").
    • $version — версия расширения, по умолчанию задано значение '1.0.0'.
    • $is_plug — флаг, указывающий, является ли расширение плагином. Если это плагин, то значение true, если нет — false.
  3. Глобальные переменные:

    • $db — объект базы данных, через который выполняются операции с БД.
    • $db_core — имя таблицы, в которую будет произведена вставка данных.
  4. Вставка данных — функция вызывает метод insert объекта $db, который добавляет новую запись в таблицу базы данных $db_core. Вставляются данные о расширении (код, название, версия и флаг плагина).

  5. Возвращаемое значение — если операция вставки прошла успешно (результат больше 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;
	}
}

Разбор:

  1. Функция cot_extension_catcmp — предназначена для сравнения двух расширений по категории и имени. В результате этого сравнения расширения сортируются в нужном порядке.

  2. Параметры функции:

    • $ext1 и $ext2 — массивы с информацией о расширениях, которые будут сравниваться.
  3. Локализация категорий:

    • Переменная $L содержит локализованные строки для категорий расширений. Если категория расширения существует в этом массиве, она заменяется на локализованное название.
  4. Сравнение категорий:

    • Если категории расширений одинаковы, то сравниваются их имена. Если имена одинаковы, возвращается 0 (элементы равны).
    • Если имена разные, возвращается 1 или -1 в зависимости от того, какое имя лексикографически больше.
  5. Сравнение категорий, если они разные:

    • Если категории расширений разные, то расширение с "большей" категорией (в соответствии с лексикографическим порядком) или расширение с категорией '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);
}

Разбор:

  1. Функция cot_extension_installed — проверяет, установлено ли расширение с заданным кодом. Это устаревшая функция, и рекомендуется использовать метод ExtensionsService::isInstalled().

  2. Параметр:

    • $extensionCode — код расширения, которое нужно проверить на установку.
  3. Логика работы:

    • Если код расширения пустой, функция возвращает false, так как проверка не может быть выполнена.
    • Если код расширения не пустой, используется класс ExtensionsService, метод isInstalled() для выполнения проверки. Этот метод возвращает true, если расширение установлено, и false, если нет.
  4. Депрецированный статус:

    • Функция помечена как устаревшая (@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';
}

Разбор:

  1. Функция cot_extension_type — проверяет тип расширения по его коду (модуль или плагин).

  2. Параметр:

    • $name — код расширения (модуля или плагина), для которого нужно определить тип.
  3. Логика работы:

    • Выполняется SQL-запрос к базе данных для получения значения поля ct_plug из таблицы расширений ($db_core). Это поле указывает, является ли расширение плагином или модулем.
    • Если расширение не найдено в базе (нет строки с таким кодом), функция возвращает false.
    • Если расширение найдено, то проверяется значение поля ct_plug:
      • Если это плагин (значение поля равно 1), возвращается строка 'plug'.
      • Если это модуль (значение поля равно 0), возвращается строка 'module'.
  4. Депрецированный статус:

    • Функция помечена как устаревшая (@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; // Возвращаем массив с информацией о расширениях
}

Разбор:

  1. Функция cot_extension_list_info — собирает информацию о всех расширениях в указанном каталоге и возвращает эту информацию в виде ассоциативного массива.

  2. Параметр:

    • $dir — путь к каталогу, в котором нужно искать расширения.
  3. Алгоритм работы:

    • Очищается кэш статистики файлов с помощью clearstatcache(), чтобы убедиться, что файлы и каталоги будут проверены заново.
    • Открывается указанный каталог с помощью opendir().
    • Перебираются все элементы в каталоге с помощью readdir(). Для каждого элемента проверяется:
      • Это не скрытая папка (не начинается с точки).
      • Это действительно каталог.
      • В каталоге существует файл с именем $f.setup.php.
    • Если файл с метаинформацией найден, вызывается функция cot_infoget() для извлечения информации из него.
      • Если информация не была загружена, пробуется старый формат для плагинов, если активирован плагин "genoa".
    • Если не удается получить информацию, используется массив с данными по умолчанию.
    • Если категория расширения не указана, она устанавливается как 'misc-ext'.
    • В массив $ext_list добавляется информация о расширении.
    • Закрывается каталог с помощью closedir().
  4. Возвращаемое значение:

    • Массив $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
}

Разбор:

  1. Функция cot_extension_remove — удаляет модуль из базы данных ядра системы.

  2. Параметр:

    • $name — название (код) модуля, который нужно удалить.
  3. Алгоритм работы:

    • С помощью глобальной переменной $db выполняется запрос на удаление записи из таблицы ядра, которая хранит информацию о модулях.
    • Удаляется запись, где поле ct_code соответствует значению $name.
  4. Возвращаемое значение:

    • Возвращает результат выполнения операции удаления:
      • 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
}

Разбор:

  1. Функция cot_extension_update — обновляет номер версии модуля в базе данных ядра системы.

  2. Параметры:

    • $name — название (код) модуля, версию которого нужно обновить.
    • $version — новая версия модуля в виде строки.
  3. Алгоритм работы:

    • С помощью глобальной переменной $db выполняется запрос на обновление поля ct_version в таблице ядра, где код модуля равен $name.
    • Обновляется только версия модуля, другие поля остаются без изменений.
  4. Возвращаемое значение:

    • Возвращает результат выполнения операции обновления:
      • 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;
}

 

Разбор:

  1. Функция cot_plugin_add — используется для регистрации плагинов или модулей в системе, а точнее — в реестре хуков. Хуки — это механизмы для расширения функционала системы, которые позволяют подключать и управлять плагинами и модулями.

  2. Параметры:

    • $hook_bindings — массив, который содержит информацию о привязке плагина или модуля к хука. В нем указываются:
      • part — часть плагина (например, 'rss', 'header').
      • hook — сам хук (например, 'rss.main', 'header.tags').
      • order — порядок выполнения.
      • active (необязательно) — активен ли плагин (1 — активен, 0 — не активен).
      • file (необязательно) — путь к файлу плагина для данной части.
    • $code — уникальный код плагина или модуля.
    • $title — название плагина или модуля.
    • $isModule — если значение равно true, то это модуль, если false — плагин.
  3. Алгоритм работы:

    • Если название плагина не указано, оно будет равно коду.
    • Для каждой привязки хука создается запись в массиве $insertRows с необходимыми полями (название, путь к файлу, активность и т. д.).
    • Затем начинается транзакция в базе данных для вставки данных.
    • В случае ошибки транзакция откатывается.
    • Если вставка прошла успешно, то транзакция коммитится, и возвращается количество добавленных записей.
  4. Возвращаемое значение:

    • Количество записей, успешно добавленных в базу данных.
    • Если возникла ошибка при добавлении записей, возвращается 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);
}

Разбор:

  1. Функция cot_plugin_remove — используется для удаления плагина или его части (привязки) из реестра хуков. Хуки позволяют плагинам и модулям взаимодействовать с основным функционалом системы.

  2. Параметры:

    • $name — код плагина или модуля, который нужно удалить.
    • $binding_id — идентификатор привязки, которую нужно удалить. Если передать 0, то удалятся все привязки для данного плагина.
  3. Алгоритм работы:

    • Строится условие для поиска привязок с данным кодом плагина (pl_code = '$name').
    • Если передан ID привязки ($binding_id > 0), то условие расширяется для удаления конкретной привязки с этим ID.
    • Выполняется удаление записи из таблицы db_plugins с использованием условия $condition.
    • Возвращается количество удалённых привязок.
  4. Возвращаемое значение:

    • Функция возвращает количество удалённых привязок из базы данных.

Таким образом, данная функция помогает удалять как все привязки плагина, так и конкретную привязку по её ID из реестра хуков.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

40 минут чтения Administrator

Комментарии (0)

Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям

Автор контента

Administrator

Оффлайн

Administrator

Последняя авторизация: 05.07.2026 18:32

  • Страница размещена: 26.01.2025 12:19
  • Последнее обновление: 26.01.2025 13:06

Похожие страницы

Файл admin.extensions.php в Cotonti CMF
1 Файл "admin.extensions.php" в движке Cotonti CMF является важным компонентом административной части системы,
Файл extensions.php в Cotonti
2 Файл "extensions.php" в системе Cotonti CMF выполняет роль конфигурационного файла, содержащего список
HTML-шаблон admin.extensions.tpl в Cotonti
3 Описание файла шаблона admin.extensions.tpl в Cotonti CMF Файл шаблона admin.extensions.tpl, расположенный в