Файл configuration.php в Cotonti

Файл /system/configuration.php в Cotonti

Файл configuration.php в Cotonti CMF играет ключевую роль в управлении конфигурационными параметрами системы. Он содержит набор функций для работы с конфигурационными значениями и их обработки. Рассмотрим основные моменты, которые можно выделить из кода:

  1. Импорт конфигурационных значений: Функции, такие как cot_config_import, используются для получения и фильтрации значений конфигурации из различных источников (например, из глобальных массивов $_POST, $_GET, и других). Они обеспечивают безопасный способ импорта данных, применяя фильтры и дополнительные правила обработки.

  2. Обновление конфигурационных значений: Функция cot_config_update_options отвечает за обновление значений конфигурации в базе данных. Она позволяет фильтровать и валидировать входные данные, используя как стандартные, так и кастомные фильтры. Это позволяет системным администраторам и пользователям менять параметры конфигурации через интерфейс, который потом обновляется в базе данных.

  3. Генерация HTML элементов для конфигурации: Функция cot_config_input генерирует соответствующие HTML-элементы (такие как текстовые поля, выпадающие списки, радиокнопки и другие) для ввода и отображения конфигурационных значений в админ-панели. Этот процесс адаптируется под тип данных, заданный в конфигурации.

  4. Заголовки и подсказки для конфигурационных опций: Функции cot_config_titles и cot_config_selecttitles отвечают за отображение заголовков и подсказок для различных параметров конфигурации. Они используют локализованные строки для отображения информации на разных языках.

  5. Обработка кастомных и динамических фильтров: В коде предусмотрены возможности для применения кастомных фильтров через динамическое выполнение функций (например, с помощью call_user_func_array). Это даёт гибкость при работе с различными типами данных, которые могут быть уникальными для каждого сайта или расширения.

В целом, этот файл служит центральным местом для обработки, обновления и отображения конфигурационных значений, что позволяет системам и плагинам гибко настраиваться через админ-панель или другие интерфейсы.

Назначение файла: Этот файл отвечает за управление конфигурацией системы или плагинов. Он облегчает изменение настроек, контроль за правильностью данных и отображение соответствующих элементов управления на сайте.

 

/**
 * Configuration Management API
 * 
 * @package API - Configuration
 * @copyright (c) Cotonti Team
 * @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
 */
defined('COT_CODE') or die('Wrong URL'); // Проверка, что файл был вызван корректно, иначе выводится ошибка и завершение работы

/**
 * Generic text configuration. Is displayed as textarea. Contains text.
 * Is used by default.
 */
const COT_CONFIG_TYPE_TEXT = 0; // Константа для текстовой конфигурации, отображаемой как поле ввода (textarea), используется по умолчанию

/**
 * A string, max length is 255 chars. Is displayed as a single line of input.
 * The list of variants is ignored for this type.
 */
const COT_CONFIG_TYPE_STRING = 1; // Константа для строковой конфигурации, максимальная длина 255 символов, отображается как поле ввода одной строки

/**
 * Selection from the list of possible variants. Is displayed as a dropdown.
 */
const COT_CONFIG_TYPE_SELECT = 2; // Константа для выбора из списка возможных вариантов, отображаемого в виде выпадающего списка

/**
 * Radio yes/no selection.
 */
const COT_CONFIG_TYPE_RADIO = 3; // Константа для выбора радио-кнопок "да/нет"

/**
 * Callback function type
 */
const COT_CONFIG_TYPE_CALLBACK = 4; // Константа для типа конфигурации с функцией обратного вызова

/**
 * Hidden config. It is actually a text string, but it is not displayed anywhere
 */
const COT_CONFIG_TYPE_HIDDEN = 5; // Константа для скрытой конфигурации, которая представляет собой строку текста, но не отображается нигде

/**
 * Visual separator/fieldset
 */
const COT_CONFIG_TYPE_SEPARATOR = 6; // Константа для визуального разделителя или области формы

/**
 * Integer range
 */
const COT_CONFIG_TYPE_RANGE = 7; // Константа для диапазона целых чисел

/**
 * Custom type.
 */
const COT_CONFIG_TYPE_CUSTOM = 8; // Константа для пользовательского типа конфигурации

 

/**
 * Генерирует поле ввода для целого числа
 *
 * @param array $cfg_var Данные конфигурационной переменной
 * @param string $min Минимально допустимое значение, полученное из параметров обратного вызова
 * @param string $max Максимально допустимое значение, полученное из параметров обратного вызова
 * @return string Код поля ввода
 */
function cot_config_type_int($cfg_var, $min='', $max='')
{
	$name = $cfg_var['config_name']; // Получаем имя конфигурационной переменной
	$value = $cfg_var['config_value']; // Получаем значение конфигурационной переменной

	if (!empty($min) && !empty($max)){ // Если заданы минимальное и максимальное значения
		$placeholder = "$min - $max"; // Заполняем подсказку диапазоном значений
	} elseif(!empty($min)) { // Если задано только минимальное значение
		$placeholder = cot_rc('adm_int_min', array('value'=>$min)); // Подсказка для минимального значения
	} elseif(!empty($min)) { // Этот блок дублирует условие выше, вероятно, ошибка (мин не проверяется дважды)
		$placeholder = cot_rc('adm_int_max', array('value'=>$max)); // Подсказка для максимального значения
	}

	return cot_inputbox('text', $name, $value, array('placeholder' => $placeholder )); // Генерируем HTML-элемент ввода с подсказкой
}

 

/**
 * Фильтрует значение как целое число в пределах от Min до Max.
 * Используется как функция обратного вызова для фильтрации пользовательского ввода типа конфигурации
 * @see также тип COT_CONFIG_TYPE_CUSTOM
 *
 * @param string $new_value Значение, введённое пользователем
 * @param array $cfg_var Данные конфигурационной переменной
 * @param string $min Минимально допустимое значение, полученное из параметров обратного вызова
 * @param string $max Максимально допустимое значение, полученное из параметров обратного вызова
 * @param bool $skip_warnings Если установлено, предупреждения не отображаются
 * @return int|NULL Отфильтрованное целое значение или NULL, если значение не может быть отфильтровано / недопустимо
 */
function cot_config_type_int_filter($new_value, $cfg_var, $min = '', $max = '', $skip_warnings = false)
{
	$not_filtered = $new_value; // Сохраняем исходное значение, введённое пользователем
	$var_name = $cfg_var['config_name']; // Получаем имя конфигурационной переменной
	list($title, $hint) = cot_config_titles($var_name, $cfg_var['config_text']); // Получаем название и подсказку для конфигурационной переменной

    $fix_msg = ''; // Сообщение о фиксированном значении
    $not_num = false; // Флаг для проверки, является ли значение числом

	// Проверяем, является ли введённое значение числом
	if (!is_numeric($new_value)) {
		$not_num = true; // Если не число, устанавливаем флаг
	} else {
		$new_value = floor($new_value); // Округляем значение до целого
		if (!empty($min) && $new_value < $min) { // Если значение меньше минимального
			$new_value = $min; // Устанавливаем минимальное значение
			$fix_msg = '. '.cot_rc('adm_set') . cot_rc('adm_int_min', array('value' => $min)); // Сообщение о применении минимального значения
		}
		if (!empty($max) && $new_value > $max) { // Если значение больше максимального
			$new_value = $max; // Устанавливаем максимальное значение
			$fix_msg = '. ' . cot_rc('adm_set') . cot_rc('adm_int_max', array('value' => $max)); // Сообщение о применении максимального значения
		}
	}
	// Уведомление для пользователя о неправильном значении
	$invalid_value_msg = cot_rc('adm_invalid_input', array('value' => $not_filtered, 'field_name' => $title )); 
	if (!$skip_warnings && ($fix_msg || $not_num)) { // Если не пропущены предупреждения и есть ошибка или фиксированное значение
        cot_message($invalid_value_msg . $fix_msg, $not_num ? 'error' : 'warning', $var_name); // Выводим сообщение об ошибке или предупреждение
    }

	return $not_num ? null : (int) $new_value; // Если значение не числовое, возвращаем NULL, иначе возвращаем целое значение
}

 

/**
 * Регистрирует несколько конфигурационных записей за один раз.
 *
 * Пример:
 * <code>
 * $config_options = array(
 *     array(
 *         'name' => 'disable_test', // Название опции
 *         'type' => COT_CONFIG_TYPE_RADIO, // Тип опции
 *         'default' => '0' // Значение по умолчанию
 *     ),
 *     array(
 *         'name' => 'test_selection', // Название опции
 *         'type' => COT_CONFIG_TYPE_SELECT, // Тип опции
 *         'default' => '20', // Значение по умолчанию
 *         'variants' => '5,10,15,20,25,30,35,40,50' // Возможные значения для SELECT
 *     ),
 *     array(
 *         'name' => 'test_value', // Название опции
 *         'type' => COT_CONFIG_TYPE_STRING, // Тип опции
 *         'default' => 'something' // Значение по умолчанию
 *     ),
 *     array(
 *         'name' => 'not_visible', // Название опции
 *         'type' => COT_CONFIG_TYPE_HIDDEN, // Тип опции
 *         'default' => 'test23' // Значение по умолчанию
 *     )
 * );
 *
 * cot_config_add('test', $config_options, 'module'); // Регистрируем конфигурацию
 * </code>
 *
 * @param string $name Название расширения (код)
 * @param array $options Ассоциативный массив конфигурационных записей.
 * Каждая запись массива имеет следующие ключи:
 * 'name' => Название опции, буквенно-цифровое, с разрешёнными знаками _
 * Должно быть уникальным для модуля/плагина
 * 'type' => Тип опции, см. константы COT_CONFIG_TYPE_*
 * 'default' => Значение по умолчанию, по умолчанию пустая строка
 * 'variants' => Список возможных значений через запятую (без пробелов),
 * Только для опций типа SELECT.
 * 'order' => Строка, определяющая позицию опции в списке,
 * Например, '04'. Или будет автоматически присвоена, если не указана
 * 'text' => Текстовое описание. Обычно опускается и хранится в языковых файлах
 * @param mixed $is_module Флаг, указывающий, является ли это конфигурацией модуля или плагина
 * @param string $category Код категории структуры. Только для конфигурационных опций по категориям
 * @param string $donor Название расширения для внедрения конфигурации от одного расширения в другое
 * @return bool Статус операции
 * @global CotDB $db
 */
function cot_config_add($name, $options, $is_module = false, $category = '', $donor = '')
{
	global $db, $cfg, $db_config;
	$cnt = count($options); // Получаем количество опций
	if (is_bool($is_module)) // Проверяем, является ли $is_module булевым значением
	{
		$type = $is_module ? 'module' : 'plug'; // Если $is_module истина, тип 'module', иначе 'plug'
	}
	else
	{
		$type = !in_array($is_module, array('plug', 'core')) ? 'module' : $is_module; // Если $is_module не 'plug' или 'core', тип 'module'
	}
	// Проверяем аргументы
	if (!$cnt) // Если количество опций равно 0, возвращаем false
	{
		return false;
	}
	// Строим SQL-запрос
	$option_set = array(); // Массив для хранения конфигурационных записей
	for ($i = 0; $i < $cnt; $i++) // Проходим по всем опциям
	{
		$opt = $options[$i]; // Получаем текущую опцию
		$option_set[] = array( // Добавляем опцию в массив
			'config_owner' => $type, // Владелец конфигурации
			'config_cat' => $name, // Категория конфигурации
			'config_subcat' => $category, // Подкатегория конфигурации
			'config_order' => isset($opt['order']) ? $opt['order'] : str_pad($i, 2, 0, STR_PAD_LEFT), // Порядок конфигурации
			'config_name' => $opt['name'], // Название конфигурации
			'config_type' => (int) $opt['type'], // Тип конфигурации
			'config_value' => isset($opt['default']) ? $opt['default'] : '', // Значение конфигурации по умолчанию
			'config_default' => isset($opt['default']) ? $opt['default'] : '', // Значение по умолчанию
			'config_variants' => isset($opt['variants']) ? $opt['variants'] : '', // Возможные варианты значений
			'config_text' => isset($opt['text']) ? $opt['text'] : '', // Текстовое описание конфигурации
			'config_donor' => $donor // Расширение-донора для конфигурации
		);
	}

	$ins_cnt = $db->insert($db_config, $option_set); // Выполняем вставку в базу данных
	return $ins_cnt == $cnt; // Возвращаем результат операции
}

 

/**
 * Внедряет заданные опции в конфигурацию модуля, если их там ещё нет.
 * Используется плагинами, которые расширяют поведение модуля и нуждаются в настройках для конкретного модуля или категории.
 *
 * @global array $cfg Конфигурация
 * @param string $module_name Код целевого модуля
 * @param array $options Массив внедряемых опций, описанных в cot_config_add()
 * @param bool $into_struct Флаг, указывающий, что конфигурационные опции должны быть внедрены в конфигурацию категорий модуля, а не в конфигурацию самого модуля
 * @param string $donor Название расширения для внедрения конфигурации от одного расширения в другое
 * @return int Количество опций, которые были действительно внедрены
 * @see cot_config_add()
 */
function cot_config_implant($module_name, $options, $into_struct, $donor)
{
	global $cfg; // Используем глобальный массив конфигурации

	$category = $into_struct ? '__default' : ''; // Если флаг $into_struct установлен, то категория будет '__default', иначе пустая строка
	$add_options = array(); // Массив для хранения опций, которые нужно добавить

	foreach ($options as $opt) // Проходим по всем опциям
	{
		// Проверяем, нужно ли добавлять опцию в конфигурацию
		if (!$into_struct && !isset($cfg[$module_name][$opt['name']]) || $into_struct && !isset($cfg[$module_name]['cat___default'][$opt['name']]))
		{
			$add_options[] = $opt; // Добавляем опцию в массив, если её нет в конфигурации
		}
	}

	// Внедряем опции с помощью функции cot_config_add
	return cot_config_add($module_name, $add_options, 'module', $category, $donor);
}
/**
 * Проверяет, есть ли уже внедрённые записи конфигурации.
 *
 * @param string $acceptor Имя модуля-акцептора
 * @param string $donor Имя расширения-донора
 * @return bool TRUE, если найдено внедрение записей конфигурации, FALSE если нет
 * @global CotDB $db
 */
function cot_config_implanted($acceptor, $donor)
{
	global $db, $db_config; // Используем глобальные переменные базы данных и таблицы конфигурации
	// Выполняем SQL-запрос, чтобы проверить, есть ли записи с данным владельцем, категорией и донором
	return $db->query("SELECT COUNT(*) FROM $db_config WHERE config_owner = 'module' AND config_cat = ? AND config_donor = ?", array($acceptor, $donor))->fetchColumn() > 0;
}

 

/**
 * Загружает структуру конфигурации из базы данных в массив
 *
 * @param string $name Код расширения
 * @param mixed $is_module TRUE, если это модуль, FALSE, если плагин
 * @param string $category Код категории структуры. Только для опций конфигурации, относящихся к категории
 * @param string $donor Имя расширения для внедрения конфигурации из расширения в расширение
 * @return array Структура опций конфигурации
 * @see cot_config_add()
 * @global CotDB $db
 */
function cot_config_load($name, $is_module = false, $category = '', $donor = '')
{
	global $db, $db_config; // Используем глобальные переменные базы данных и таблицы конфигурации
	$options = array(); // Массив для хранения опций конфигурации

	// Определяем тип конфигурации (модуль или плагин)
	if (is_bool($is_module))
	{
		$type = $is_module ? 'module' : 'plug'; // Если это логическое значение, присваиваем 'module' или 'plug'
	}
	else
	{
		$type = !in_array($is_module, array('plug', 'core')) ? 'module' : $is_module; // Если это строка, то выбираем 'module' или указанное значение
	}

	// Формируем SQL-запрос для извлечения конфигурационных данных
	$query = "SELECT config_name, config_type, config_value,
			config_default, config_variants, config_order
		FROM $db_config WHERE config_owner = ? AND config_cat = ? AND config_subcat = ? AND config_donor = ?";
	$params = array($type, $name, $category, $donor); // Параметры для запроса

	$res = $db->query($query, $params); // Выполняем запрос
	while ($row = $res->fetch()) // Проходим по всем строкам результата
	{
		// Добавляем данные каждой строки в массив $options
		$options[] = array(
			'name' => $row['config_name'], // Имя опции
			'type' => $row['config_type'], // Тип опции
			'order' => $row['config_order'], // Порядок опции
			'value' => $row['config_value'], // Текущее значение
			'default' => $row['config_default'], // Значение по умолчанию
			'variants' => $row['config_variants'] // Возможные варианты для SELECT
		);
	}
	$res->closeCursor(); // Закрываем курсор результата

	return $options; // Возвращаем массив опций конфигурации
}

 

/**
 * Обновляет свойства конфигурационной карты в базе данных для заданных опций
 *
 * @param string $name Код расширения
 * @param array $options Записи конфигурации
 * @param bool|string $isModule TRUE, если модуль, FALSE, если плагин
 * @param string $category Код категории структуры. Только для опций конфигурации, относящихся к категории
 * @param string $donor Имя расширения для внедрения конфигурации из расширения в расширение
 * @return int Количество обновленных записей
 * @global CotDB $db
 */
function cot_config_modify($name, $options, $isModule = false, $category = '', $donor = '')
{
	global $db_config; // Используем глобальную переменную для таблицы конфигурации

	// Определяем тип конфигурации (модуль или плагин)
	if (is_bool($isModule)) {
		$type = $isModule ? 'module' : 'plug'; // Если логическое значение, присваиваем 'module' или 'plug'
	} else {
		$type = !in_array($isModule, array('plug', 'core')) ? 'module' : $isModule; // Если строковое значение, то выбираем 'module' или указанный тип
	}
	$affected = 0; // Переменная для подсчета количества обновленных записей

	// Условие для SQL-запроса
	$where = 'config_owner = ? AND config_cat = ? AND config_name = ? AND config_donor = ?';

	// Если категория не пуста, добавляем условие для категории
	if (!empty($category)) {
		$where .= ' AND config_subcat = ?';
	}

	// Проходим по всем переданным опциям
	foreach ($options as $opt) {
		$config_name = (string) $opt['name']; // Получаем имя конфигурации
		unset($opt['name']); // Убираем имя из массива опций
		$opt_row = array(); // Массив для хранения обновленных данных

		// Перебираем ключи и значения в текущей опции
		foreach ($opt as $key => $val) {
			$opt_row['config_' . $key] = $val; // Добавляем данные с префиксом 'config_'
		}

		// Формируем параметры для SQL-запроса
		$params = empty($category) ?
            array($type, $name, $config_name, $donor) : array($type, $name, $config_name, $donor, $category);

		// Выполняем обновление и увеличиваем счетчик обновленных записей
		$affected += Cot::$db->update($db_config, $opt_row, $where, $params);
	}

	// Возвращаем количество обновленных записей
	return $affected;
}

 

/**
 * Разбирает массив записей конфигурации файла установки в представление в виде массива
 *
 * @param array $info_cfg Записи конфигурации файла установки
 * @return array Опции конфигурации
 */
function cot_config_parse($info_cfg)
{
	$options = array(); // Массив для хранения опций конфигурации
	if (is_array($info_cfg)) // Проверяем, является ли переданный параметр массивом
	{
		foreach ($info_cfg as $i => $x) // Перебираем элементы массива конфигурации
		{
			$line = explode(':', $x); // Разделяем строку на части по символу ":"
			$line[1] = trim($line[1]); // Убираем пробелы вокруг второго элемента
			if (is_array($line) && !empty($line[1]) && !empty($i)) // Проверяем, что строка правильно разделена
			{
				// В зависимости от типа конфигурации, присваиваем соответствующее значение
				switch ($line[1])
				{
					case 'string': // Тип конфигурации string
						$line['Type'] = COT_CONFIG_TYPE_STRING;
						break;
					case 'select': // Тип конфигурации select
						$line['Type'] = COT_CONFIG_TYPE_SELECT;
						break;
					case 'radio': // Тип конфигурации radio
						$line['Type'] = COT_CONFIG_TYPE_RADIO;
						break;
					case 'callback': // Тип конфигурации callback
						$line['Type'] = COT_CONFIG_TYPE_CALLBACK;
						break;
					case 'hidden': // Тип конфигурации hidden
						$line['Type'] = COT_CONFIG_TYPE_HIDDEN;
						break;
					case 'separator': // Тип конфигурации separator
						$line['Type'] = COT_CONFIG_TYPE_SEPARATOR;
						break;
					case 'range': // Тип конфигурации range
						$line['Type'] = COT_CONFIG_TYPE_RANGE;
						break;
					case 'custom': // Тип конфигурации custom
						$line['Type'] = COT_CONFIG_TYPE_CUSTOM;
						break;
					default: // Если тип не найден, по умолчанию текстовый тип
						$line['Type'] = COT_CONFIG_TYPE_TEXT;
						break;
				}
				// Добавляем опцию в массив конфигураций
				$options[] = array(
					'name' => $i, // Имя опции
					'order' => trim($line[0]), // Порядок опции (убираем пробелы)
					'type' => $line['Type'], // Тип опции
					'variants' => $line[2], // Возможные значения
					'default' => $line[3], // Значение по умолчанию
					'text' => trim($line[4]) // Описание опции
				);
			}
		}
	}
	return $options; // Возвращаем массив с опциями конфигурации
}

 

/**
 * Отменяет регистрацию опции(й) конфигурации.
 *
 * @param string $name Код расширения
 * @param mixed $is_module Флаг, указывающий, является ли конфигурация для модуля или плагина
 * @param mixed $option Имя одной опции конфигурации в виде строки.
 * Или передайте массив имен опций, чтобы удалить их сразу. Если пусто или не указано,
 * все опции выбранного модуля/плагина будут удалены.
 * @param string $category Код категории структуры. Только для опций конфигурации, относящихся к категориям
 * @param string $donor Имя расширения для внедрения конфигурации из одного расширения в другое
 * @return int Количество удалённых опций
 * @global CotDB $db
 */
function cot_config_remove($name, $is_module = false, $option = '', $category = '', $donor = null)
{
	global $db, $db_config;

	// Определяем тип конфигурации: модуль или плагин
	if (is_bool($is_module))
	{
		$type = $is_module ? 'module' : 'plug'; // Если $is_module равно true, выбираем 'module', иначе 'plug'
	}
	else
	{
		$type = !in_array($is_module, array('plug', 'core')) ? 'module' : $is_module; // Если тип не 'plug' или 'core', выбираем 'module'
	}

	// Формируем базовое условие для удаления, выбирая конфигурацию по типу и названию
	$where = "config_owner = '$type' AND config_cat = " . $db->quote($name); // Условие для владельца конфигурации и категории
	if (!empty($category))
	{
		$where .= " AND config_subcat = " . $db->quote($category); // Если категория не пуста, добавляем условие для подкатегории
	}
	if (!is_null($donor))
	{
		$where .= " AND config_donor = " . $db->quote($donor); // Если donor задан, добавляем условие для имени расширения
	}

	// Если передан массив опций, строим условие для нескольких опций
	if (is_array($option))
	{
		$cnt = count($option); // Считаем количество опций в массиве
		if ($cnt == 1)
		{
			$option = $option[0]; // Если массив состоит из одной опции, выбираем её
		}
		else
		{
			$where .= " AND config_name IN ("; // Строим условие для нескольких опций
			for ($i = 0; $i < $cnt; $i++)
			{
				if ($i > 0)
					$where .= ','; // Добавляем запятую между опциями
				$where .= $db->quote($option[$i]); // Добавляем каждую опцию в условие
			}
			$where .= ')';
			unset($option); // Убираем переменную $option, так как мы её обработали
		}
	}
	// Если передана одна опция, добавляем её в условие
	if (!empty($option))
	{
		$where .= " AND config_name = " . $db->quote($option); // Условие для одной опции
	}

	// Выполняем удаление записей и возвращаем количество удалённых опций
	return $db->delete($db_config, $where); // Удаляем записи из таблицы конфигураций
}

 

/**
 * Обновляет значения конфигурации
 *
 * Пример:
 * <code>
 * $config_values = array(
 *     'disable_test' => '0',
 *     'hidden_test' => 'test45',
 * );
 *
 * cot_config_set('test', $config_values, true);
 * </code>
 *
 * @param string $name Название расширения, к которому принадлежит конфигурация
 * @param array $options Массив параметров в виде 'имя параметра' => 'значение параметра'
 * @param bool|string $isModule Флаг, указывающий, является ли это конфигурацией для модуля или плагина
 * @param string $category Код категории структуры. Только для конфигурационных опций на основе категорий
 * @return int Количество обновленных записей
 * @global CotDB $db
 */
function cot_config_set($name, $options, $isModule = false, $category = '')
{
	global $db_config; // Получаем доступ к глобальной переменной с настройками базы данных

	if (is_bool($isModule)) { // Проверка, является ли $isModule логическим значением
		$type = $isModule ? 'module' : 'plug'; // Если $isModule истинно, то это модуль, иначе плагин
	} else { 
		$type = !in_array($isModule, array('plug', 'core')) ? 'module' : $isModule; // Если $isModule не плагин или ядро, то это модуль
	}
	$upd_cnt = 0; // Инициализируем счетчик обновленных записей

	$where = 'config_owner = ? AND config_cat = ? AND config_name = ?'; // Начальная часть запроса для выбора конфигурации по владельцу, категории и имени
	if (!empty($category)) { // Если категория не пуста
		$where .= ' AND config_subcat = ?'; // Добавляем к запросу условие по подкатегории
		if ($category != '__default') { // Если категория не равна '__default'
			$default_options = cot_config_load($name, $isModule, '__default'); // Загружаем конфигурацию по умолчанию для указанного расширения
		}
		$structure_val = array(); // Инициализируем массив для значений структуры
	} else {
		$structure_val = cot_config_list($type, $name, '__default'); // Загружаем список конфигурации для модуля или плагина
	}

	$category_tmp = $category; // Сохраняем временно значение категории
	foreach ($options as $key => $val) { // Для каждого параметра в массиве опций
		if (isset($structure_val[$key]) && is_array($structure_val[$key])) { // Если параметр есть в структуре и он является массивом
			$where_sub = ' AND config_subcat = ?'; // Добавляем подкатегорию в условие
			$category = '__default'; // Устанавливаем категорию как '__default'
		} else { 
			$where_sub = ''; // Если параметр не массив, то подкатегория не нужна
			$category = $category_tmp; // Восстанавливаем исходное значение категории
		}
		if (empty($category) || $category == '__default' || $val != $default_options[$key]) { // Если категория пуста, категория по умолчанию или значение параметра отличается от дефолтного
			$params = empty($category) ? [$type, $name, (string) $key] : [$type, $name, (string) $key, $category]; // Формируем параметры для запроса
			$upd_cnt += Cot::$db->update($db_config, ['config_value' => $val], $where . $where_sub, $params); // Выполняем обновление в базе данных и увеличиваем счетчик
		}
	}

	return $upd_cnt; // Возвращаем количество обновленных записей
}

 

/**
 * Обновляет существующие конфигурационные карты, удаляя устаревшие опции, добавляя новые
 * опции и изменяя те, которые требуют обновления.
 *
 * @param string $name Код расширения
 * @param array $options Конфигурационные опции
 * @param bool $is_module TRUE для модулей, FALSE для плагинов
 * @param string $category Код категории структуры. Только для конфигураций на основе категорий
 * @param string $donor Имя расширения для внедрения конфигурации от одного расширения к другому
 * @return int Количество затронутых записей
 */
function cot_config_update($name, $options, $is_module = false, $category = '', $donor = '')
{
	$affected = 0; // Инициализация переменной для подсчета затронутых записей
	$old_options = cot_config_load($name, $is_module, $category, $donor); // Загружаем старые конфигурационные опции

	// Находим и удаляем опции, которых больше не существует
	$remove_opts = array(); // Массив для хранения опций, которые нужно удалить
	foreach ($old_options as $old_opt) // Проходим по старым опциям
	{
		$keep = false; // Флаг, указывающий, следует ли сохранять текущую опцию
		foreach ($options as $opt) // Проходим по новым опциям
		{
			if ($opt['name'] == $old_opt['name']) // Если имя опции совпадает с именем старой опции
			{
				$keep = true; // Устанавливаем флаг на true, если опция должна быть сохранена
				break; // Прерываем цикл
			}
		}
		if (!$keep && $old_opt['type'] != COT_CONFIG_TYPE_HIDDEN) // Если опцию не нужно сохранять и она не скрытая
		{
			$remove_opts[] = $old_opt['name']; // Добавляем имя опции в список на удаление
		}
	}
	if (count($remove_opts) > 0) // Если есть опции для удаления
	{
		$affected += cot_config_remove($name, $is_module, $remove_opts, $category, $donor); // Удаляем опции и увеличиваем счетчик
	}

	// Находим новые опции и опции, которые были изменены
	$new_options = array(); // Массив для новых опций
	$upd_options = array(); // Массив для измененных опций
	foreach ($options as $opt) // Проходим по новым опциям
	{
		$existed = false; // Флаг, указывающий, существует ли уже такая опция
		foreach ($old_options as $old_opt) // Проходим по старым опциям
		{
			if ($opt['name'] == $old_opt['name']) // Если имя новой опции совпадает с именем старой опции
			{
				$changed = array_diff($opt, $old_opt); // Находим различия между новой и старой опцией
				if (count($changed) > 0) // Если есть различия
				{
					// Значения для измененных опций сбрасываются на значение по умолчанию
					// только если тип и значение по умолчанию изменились
					if ($opt['type'] != $old_opt['type'] && $opt['default'] != $old_opt['default'])
					{
						$opt['value'] = $opt['default']; // Сбрасываем значение опции на значение по умолчанию
					}
					$upd_options[] = $opt; // Добавляем измененную опцию в массив для обновления
				}
				$existed = true; // Устанавливаем флаг, что опция существует
				break; // Прерываем цикл
			}
		}
		if (!$existed) // Если опция не существует
		{
			$new_options[] = $opt; // Добавляем опцию в массив новых опций
		}
	}
	if (count($new_options) > 0) // Если есть новые опции
	{
		$affected += cot_config_add($name, $new_options, $is_module, $category); // Добавляем новые опции и увеличиваем счетчик
	}
	if (count($upd_options) > 0) // Если есть измененные опции
	{
		$affected += cot_config_modify($name, $upd_options, $is_module, $category); // Обновляем измененные опции и увеличиваем счетчик
	}

	return $affected; // Возвращаем количество затронутых записей
}

 

/**
 * Сброс значения конфигурации
 *
 * @param string $name Имя расширения, к которому относится конфигурация
 * @param string $option Имя опции
 * @param mixed $is_module Флаг, указывающий, является ли конфигурация для модуля или плагина
 * @param string $category Код категории структуры. Только для конфигураций на основе категорий
 * @return int Количество обновленных записей
 * @global CotDB $db
 */
function cot_config_reset($name, $option, $is_module = false, $category = '')
{
	global $db, $db_config;

	// Определяем тип конфигурации, если флаг is_module является булевым
	if (is_bool($is_module))
	{
		$type = $is_module ? 'module' : 'plug'; // Если is_module true, то тип 'module', иначе 'plug'
	}
	else
	{
		$type = !in_array($is_module, array('plug', 'core')) ? 'module' : $is_module; // Если is_module не является 'plug' или 'core', то тип 'module'
	}

	// Если указана категория
	if (!empty($category))
	{
		// Удаляем запись конфигурации для заданной категории
		$db->delete($db_config, "config_name = ? AND config_owner = ? AND config_cat = ?
					AND config_subcat = ?", array($option, $type, $name, $category));
	}
	else
	{
		// Если категория не указана, сбрасываем значение конфигурации на значение по умолчанию
		$db->query("UPDATE $db_config SET config_value = config_default
			WHERE config_name = ? AND config_owner = ? AND config_cat = ? AND (config_subcat = '' OR config_subcat IS NULL OR config_subcat = '__default')", array($option, $type, $name));
	}
}

 

/**
 * Получает конфигурации из базы данных
 * @param string $owner Владелец ('core', 'plug', 'module')
 * @param string $cat Код расширения (страница, форумы и т. д.) или подтип ядра (меню, главное, производительность и т. д.)
 * @param string $subcat Категория для модулей, если она существует
 * @return array Массив с конфигурациями
 */
function cot_config_list($owner, $cat, $subcat = "")
{
	global $db, $db_config;

	// Формируем массив условий для выборки
	$where = array(
		'type' => "config_type != '" . COT_CONFIG_TYPE_HIDDEN . "'", // Исключаем конфигурации с типом COT_CONFIG_TYPE_HIDDEN
		'owner' => "config_owner = '" . $db->prep($owner) . "'", // Условие для владельца конфигурации
		'cat' => "config_cat = '" . $db->prep($cat) . "'", // Условие для категории конфигурации
		'subcat' => empty($subcat) ? "(config_subcat = '' OR config_subcat IS NULL OR config_subcat = '__default')" : "(config_subcat = '" . $db->prep($subcat) . "' OR config_subcat = '__default')" // Условие для подкатегории, если она существует
	);

	// Собираем все условия в строку
	$where_query = implode(" AND ", $where);

	// Пытаемся выбрать все строки, индексируя их по имени конфигурации
	$sql = $db->query("SELECT * FROM $db_config WHERE $where_query ORDER BY config_subcat ASC, config_order ASC, config_name ASC");
	$rs = $sql->fetchAll(PDO::FETCH_ASSOC); // Получаем все строки как ассоциативный массив
	$rowset = array(); // Массив для основной конфигурации
	$rowset_default = array(); // Массив для конфигурации по умолчанию

	// Перебираем все строки
	foreach ($rs as $row)
	{
		$keyx = $row['config_name']; // Ключ для текущей конфигурации

		// Если конфигурация по умолчанию
		if ($row['config_subcat'] == "__default")
		{
			$rowset_default[$keyx] = $row; // Добавляем в массив конфигурации по умолчанию
		}
		else
		{
			$rowset[$keyx] = $row; // Добавляем в основной массив конфигурации
		}
	}

	// Сливаем массивы для правильного отображения
	if (!empty($subcat))
	{
		// Если подкатегория задана, сливаем значения конфигураций по умолчанию с основной конфигурацией
		foreach ($rowset_default as $key => $row)
		{
			if (!empty($rowset[$key]))
			{
				$rowset[$key]['config_subdefault'] = $row['config_value']; // Добавляем значение по умолчанию в основную конфигурацию
			}
		}
		$rowset = array_merge($rowset_default, $rowset); // Сливаем массивы
	}
	else
	{
		// Если подкатегория не задана, просто объединяем основной массив и массив конфигураций по умолчанию
		$rowset = $rowset + $rowset_default;
	}

	unset($rs); // Освобождаем память от переменной с результатами запроса
	return $rowset; // Возвращаем результат
}

 

/**
 * Импортирует данные для значений конфигурации из внешнего источника
 *
 * @param string|array $name Имя значения или массив имен для списка значений
 * @param string $source Тип источника
 * @param string $filter Тип фильтра
 * @param string $defvalue Значение по умолчанию для отфильтрованных данных
 * @see cot_import()
 * @return mixed Отфильтрованное значение или массив значений
 */
function cot_config_import($name, $source = 'POST', $filter = 'NOC', $defvalue = null)
{
	global $cot_import_filters;

	// Если имя не указано, возвращаем null
	if (!$name) {
        return null;
    }

	// Если имя не является массивом, преобразуем его в массив
	if (!is_array($name)) {
		$name = array($name);
		$single_value = true; // Устанавливаем флаг, что значение одно
	}

	$res = array(); // Массив для хранения результатов
	// Проходим по каждому имени в массиве
	foreach ($name as $idx => $var_name) {
		// Определяем тип фильтра для текущего значения
		$filter_type = (is_array($filter)) ? ($filter[$var_name] ? $filter[$var_name] : ($filter[$idx] ? $filter[$idx] : 'NOC')) : $filter;

		// Импортируем значение без фильтра
		$not_filtered = cot_import($var_name, $source, 'NOC');
		// Импортируем значение с фильтром
		$value = cot_import($var_name, $source, $filter_type);

		// Дополнительная фильтрация по имени переменной
		if (
            !empty($cot_import_filters[$var_name]) &&
            is_array($cot_import_filters[$var_name]) &&
            sizeof($cot_import_filters[$var_name])
        ) {
			// Применяем фильтр для текущего значения
			$value = cot_import($value, 'DIRECT', $var_name);
		}

		// Если значение является некорректным
		if (is_null($value)) {
			// Оформляем ошибку с выводом значений
			$value_to_show = (in_array($filter_type, array('INT', 'NUM', 'TXT', 'ALP')))
				? htmlspecialchars(cot_cutstring(strip_tags($not_filtered), 15)) // Обрезаем строку до 15 символов
				: '';
			// Получаем заголовок для поля
			list($field_title) = cot_config_titles($var_name);
			// Сообщение об ошибке
			$error_msg = cot_rc('adm_invalid_input', array('value' => $value_to_show, 'field_name' => $field_title));

			// Если задано значение по умолчанию
			if (!is_null($defvalue)) {
				// Присваиваем значение по умолчанию, если оно задано
				$value = !is_array($defvalue) ? $defvalue : (isset($defvalue[$var_name]) ? $defvalue[$var_name] : (isset($defvalue[$idx]) ? $defvalue[$idx] : null));
				// Добавляем в сообщение информацию о значении по умолчанию
				$error_msg .= $value_to_show ? '. '.cot_rc('adm_set_default', htmlspecialchars(strip_tags($value))) : '';
			}

			// Выводим сообщение об ошибке
			cot_message($error_msg, 'error', $var_name);
		}

		// Добавляем значение в результат
		$res[$var_name] = $value;
	}

	// Если значение одно, возвращаем его, иначе возвращаем массив
	return $single_value ? $value : $res;
}

 

/**
 * Сохраняет обновленные значения конфигурации в базе данных
 *
 * @param string $name Имя расширения или раздела, к которому относится конфигурация
 * @param array $optionslist Список опций, возвращаемый функцией cot_config_list()
 * @param mixed $is_module Флаг, указывающий, является ли это конфигурацией модуля или плагина
 * @param string $update_new_only Обновлять только измененные значения
 * @param string $source Источник импортированных данных
 * @return boolean|number Количество обновленных значений
 */
function cot_config_update_options($name, &$optionslist, $is_module=false, $update_new_only = true, $source = 'POST')
{
	global $cot_import_filters;

	// Если optionslist не является массивом, возвращаем false
	if (!is_array($optionslist)) return false;

	$new_options = array(); // Массив для хранения новых опций

	// Проходим по всем опциям конфигурации
	foreach ($optionslist as $cfg_name => $cfg_var)
	{
		// Если это визуальный разделитель или поле без значения, пропускаем
		if ($cfg_var['config_type'] == COT_CONFIG_TYPE_SEPARATOR) continue;

		$filtered = FALSE; // Флаг для фильтрации
		$builtin_filter = FALSE; // Флаг для встроенной фильтрации

		// Получаем данные из источника (например, POST) без фильтрации
		$data = $raw_input = cot_import($cfg_name, $source, 'NOC');

		// Проверяем, если конфигурация имеет пользовательский тип
		$custom_type = ($cfg_var['config_type'] == COT_CONFIG_TYPE_CUSTOM)
			&& $cfg_var['config_variants']
			&& preg_match('#^(\w+)\((.*?)\)$#', $cfg_var['config_variants'], $mt);

		// Если пользовательский тип найден, пытаемся применить фильтрацию через пользовательскую функцию
		if ($custom_type)
		{
			$custom_func = $mt[1]; // Имя пользовательской функции
			$custom_filter_func = $custom_func . '_filter'; // Имя функции фильтрации

			// Если функция фильтрации существует
			if (function_exists($custom_filter_func))
			{
				$callback_params = preg_split('#\s*,\s*#', $mt[2]);

				// Преобразуем параметры, убирая кавычки
				if (count($callback_params) > 0 && !empty($callback_params[0]))
				{
					for ($i = 0; $i < count($callback_params); $i++)
					{
						$callback_params[$i] = str_replace(array("'", '"'), array('', ''), $callback_params[$i]);
					}
				}

				/**
				* Фильтрует значение с помощью пользовательской функции
				* @param string $data Значение, введенное пользователем
				* @param array $cfg_var Данные конфигурации
				*  ... другие параметры для функции
				* @return NULL|mixed Отфильтрованное значение или NULL, если значение не может быть отфильтровано.
				* @see cot_config_type_int_filter() как пример
				*/
				$filtered = call_user_func_array(
					$custom_filter_func,
					array_merge(array(&$raw_input, $cfg_var), $callback_params)
				);
			}
			else // Если пользовательской функции нет, пробуем встроенные фильтры
			{
				// Последняя часть имени функции может быть типом встроенного фильтра
				list($base_filter) = array_reverse(explode('_', strtoupper($custom_func)));

				// Проверяем, если это встроенный фильтр
				if (in_array(strtoupper($base_filter), array('INT', 'BOL', 'PSW', 'ALP', 'TXT', 'NUM'))
					|| sizeof($cot_import_filters[$base_filter])
					)
				{
					$filtered = cot_config_import($cfg_name, $source, $base_filter);
					$builtin_filter = true;
				}
			}
		}

		// Если фильтрация не прошла (значение не отфильтровано)
		if (is_null($filtered)) 
		{
			// Если это встроенная фильтрация, то присваиваем пустое значение
			$optionslist[$cfg_name]['config_value'] = $builtin_filter ? '' : $raw_input;
		}
		else
		{
			// Если фильтрация прошла успешно, присваиваем отфильтрованное значение
			if (false !== $filtered) $data = $filtered;

			// Если это массив, сериализуем его
			if (is_array($data)) $data = serialize($data);

			// Если данные изменились или не обновляем только новые, добавляем опцию для обновления
			if ($data != $cfg_var['config_value'] || !$update_new_only) 
				$new_options[$cfg_name] = $data;

			// Обновляем значение в списке опций
			$optionslist[$cfg_name]['config_value'] = $data;
		}
	}

	// Если есть новые опции для обновления, применяем их
	return (sizeof($new_options)) ? cot_config_set($name, $new_options, $is_module) : 0;
}

 

/**
 * Возвращает HTML-форму ввода для конфигурации
 * @param array $cfg_var Массив с параметрами конфигурационной переменной
 * @return string HTML-код для ввода данных конфигурации
 */
function cot_config_input($cfg_var)
{
	$name = $cfg_var['config_name']; // Имя конфигурационной переменной
	$type = $cfg_var['config_type']; // Тип конфигурационной переменной
	$value = $cfg_var['config_value']; // Значение конфигурационной переменной
	$options = $cfg_var['config_variants']; // Опции для переменной (если есть)
	$config_input = ''; // Переменная для хранения HTML-кода ввода
	$split_re = '#\s*,\s*#'; // Регулярное выражение для разделения опций по запятой

	// В зависимости от типа конфигурации формируем соответствующий HTML-код для ввода
	switch ($type) {
		case COT_CONFIG_TYPE_STRING:
			// Для строкового типа конфигурации создаем текстовое поле ввода
			$config_input = cot_inputbox('text', $name, $value);
			break;

		case COT_CONFIG_TYPE_SELECT:
			// Для типа SELECT создаем выпадающий список
			if (!empty($options)) {
				$params = preg_split($split_re, $options); // Разделяем опции по запятой
				$params_titles = cot_config_selecttitles($name, $params); // Получаем заголовки для опций
			}
			$config_input = (is_array($params)) ? cot_selectbox($value, $name, $params, $params_titles, false) : cot_inputbox('text', $name, $value);
			break;

		case COT_CONFIG_TYPE_RADIO:
			global $L;
			// Для типа RADIO создаем радиокнопки
			if (!empty($options)) {
				// Расширяем радиокнопки, используя список пользовательских значений
				$params = preg_split($split_re, $options);
				$params_titles = cot_config_selecttitles($name, $params);
				if (empty($value)) $value = $cfg_var['config_default']; // Если значение пустое, используем значение по умолчанию
			} else {
				// Старый стиль с двумя вариантами: "Да" и "Нет"
				$params = array(1, 0);
				$params_titles = array(Cot::$L['Yes'], Cot::$L['No']);
			}
			$config_input = cot_radiobox($value, $name, $params, $params_titles, '', ' ');
			break;

		case COT_CONFIG_TYPE_RANGE:
			// Для диапазона чисел создаем выпадающий список с заданным диапазоном значений
			$range = preg_split($split_re, $options); // Разделяем диапазон
			$params = range($range[0], $range[1], empty($range[2]) ? 1 : $range[2]); // Генерируем массив значений диапазона
			$config_input = cot_selectbox($value, $name, $params, $params, false);
			break;

		case COT_CONFIG_TYPE_CUSTOM:
			// Для пользовательских типов пытаемся вызвать соответствующую фильтрующую функцию
			if ((preg_match('#^(\w+)\((.*?)\)$#', $options, $mt) && function_exists($mt[1])))
			{
				$callback_params = preg_split($split_re, $mt[2]);
				if (count($callback_params) > 0 && !empty($callback_params[0]))
				{
					for ($i = 0; $i < count($callback_params); $i++)
					{
						$callback_params[$i] = str_replace(array("'", '"'), array('', ''), $callback_params[$i]);
					}
				}
				$config_input = call_user_func_array($mt[1], array_merge(array($cfg_var), $callback_params));
			}
			else
			{
				// Если функции нет, используем текстовое поле
				$config_input = cot_inputbox('text', $name, $value);
			}
			break;

		case COT_CONFIG_TYPE_CALLBACK:
			// Для типа CALLBACK вызываем функцию для получения значений
			if ((preg_match('#^(\w+)\((.*?)\)$#', $options, $mt) && function_exists($mt[1])))
			{
				$callback_params = preg_split($split_re, $mt[2]);
				if (count($callback_params) > 0 && !empty($callback_params[0]))
				{
					for ($i = 0; $i < count($callback_params); $i++)
					{
						$callback_params[$i] = str_replace("'", '', $callback_params[$i]);
						$callback_params[$i] = str_replace('"', '', $callback_params[$i]);
					}
					$params = call_user_func_array($mt[1], $callback_params);
				}
				else
				{
					$params = call_user_func($mt[1]);
				}

				// Проверяем, если это ассоциативный массив (значение => название)
				$assoc = (range( 0, count($params) -1 ) != array_keys( $params ));
				if ($assoc)
				{
					$assoc_titles = array_values($params);
					$params = array_keys($params);
				}
				$params_titles = cot_config_selecttitles($name, $params);
				if ($assoc && $params_titles == $params) $params_titles = $assoc_titles;

				$config_input = cot_selectbox($value, $name, $params, $params_titles, false);
			}
			break;

		case COT_CONFIG_TYPE_HIDDEN:
		case COT_CONFIG_TYPE_SEPARATOR:
			// Если тип скрытый или разделитель, не создаем форму ввода
			break;

		default :
			// По умолчанию используем текстовое поле для многострочного ввода
			$config_input = cot_textarea($name, $value, 8, 56);
			break;
	}

	return $config_input; // Возвращаем HTML-код для ввода
}

 

/**
 * Возвращает заголовок и подсказку для опции конфигурации
 * @param string $name Имя конфигурационной переменной
 * @param string $text Текст, который будет использоваться, если нет заголовка
 * @return array Массив с заголовком и подсказкой
 */
function cot_config_titles($name, $text = '')
{
	global $L; // Глобальный массив локализаций

    // Если подсказка для данной конфигурации не задана, инициализируем её пустой строкой
    if (!isset(Cot::$L['cfg_' . $name . '_hint'])) {
        Cot::$L['cfg_' . $name . '_hint'] = '';
    }
    
    // Проверяем, если заголовок конфигурации существует и это массив (с заголовком и подсказкой)
	if (isset(Cot::$L['cfg_' . $name]) && is_array(Cot::$L['cfg_' . $name])) {
        // Если подсказка не установлена, то берем её из массива (если она существует)
        Cot::$L['cfg_' . $name . '_hint'] = (isset(Cot::$L['cfg_' . $name][1]) && !isset(Cot::$L['cfg_' . $name . '_hint'])) ?
                Cot::$L['cfg_' . $name][1] : Cot::$L['cfg_' . $name . '_hint'];
        
        // Заголовок конфигурации устанавливаем как первый элемент массива
        Cot::$L['cfg_' . $name] = Cot::$L['cfg_' . $name][0];
	}

	// Если текст не пустой, то его экранируем (для безопасности), иначе используем имя конфигурации
	$text = !empty($text) ? htmlspecialchars($text) : $name;
    
    // Заголовок - это либо локализованное значение, либо текст, если локализации нет
	$title = isset(Cot::$L['cfg_' . $name]) ? Cot::$L['cfg_' . $name] : $text;

	// Возвращаем массив из заголовка и подсказки
	return array($title, Cot::$L['cfg_' . $name . '_hint']);
}

 

/**
 * Вспомогательная функция для генерации заголовков для выбора.
 * @param  string $name Текущее имя конфигурации
 * @param  array  $params Массив параметров конфигурации
 * @return array Заголовки для выбора
 */
function cot_config_selecttitles($name, $params)
{
    // Если заголовки параметров не определены, возвращаем оригинальный массив параметров
    if (!isset(Cot::$L['cfg_' . $name . '_params'])) {
        return $params;
    }

    // Загружаем локализованные параметры
    $langParam = Cot::$L['cfg_' . $name . '_params'];

    // Если локализованные параметры - это строка, преобразуем её в массив
    if (!is_array($langParam)) {
        $langParam = preg_split('#\s*,\s*#', $langParam);

        // Проверяем, если первый элемент выглядит как ассоциативный ключ:значение
        if (preg_match('#^[\w-]+\s*:#', $langParam[0])) {
            // Поддержка ассоциативных массивов
            $temp = [];
            foreach ($langParam as $item) {
                // Разбираем элементы в формате ключ:значение
                if (preg_match('/^(?P<key>[\w-]+)\s*:\s*(?P<value>.*)$/', $item, $matches)) {
                    $temp[$matches['key']] = $matches['value'];
                }
            }
            // Если есть ассоциативный массив, заменяем оригинальный
            if (count($temp) > 0) {
                $langParam = $temp;
            }
        }
    }

    // Массив для заголовков параметров
    $cfgParamsTitles = [];
    // Массив ключей локализованных параметров
    $langParamsKeys = array_keys($langParam);

    // Проверяем, если локализованные параметры - это числовой массив
    if (isset($langParamsKeys[0]) && is_numeric($langParamsKeys[0])) {
        // Если числовой массив, просто используем его
        $cfgParamsTitles = $langParam;

    } else {
        // Если ассоциативный массив, сопоставляем значения
        foreach ($params as $val) {
            if (isset($langParam[$val])) {
                // Если значение параметра есть в локализованных параметрах, добавляем его
                $cfgParamsTitles[] = $langParam[$val];
            } else {
                // Иначе добавляем оригинальное значение
                $cfgParamsTitles[] = $val;
            }
        }
    }

	// Возвращаем массив заголовков
	return $cfgParamsTitles;
}

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

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

Administrator

Оффлайн

Administrator

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

  • Страница размещена: 24.01.2025 11:11
  • Последнее обновление: 24.01.2025 11:47