Файл Resources.php в Cotonti

файл предоставляет методы для добавления внешних и встроенных стилей и скриптов в заголовок и подвал страницы

Основное назначение файла Resources.php в системной папке Cotonti CMF — это управление ресурсами, такими как CSS, JavaScript файлы, и их интеграция в страницы сайта. Этот файл предоставляет методы для добавления внешних и встроенных стилей и скриптов в заголовок и подвал страницы, а также для обработки псевдонимов ресурсов и минификации кода.

Суть содержания кода:

  1. Ресурсы для страницы: Файл содержит методы для добавления ссылок на стили и скрипты (функции linkFile, linkFileFooter), которые могут быть размещены в различных частях страницы (заголовок или подвал), а также встроенных стилей и скриптов с использованием методов embed и embedFooter.

  2. Минификация: Методы, такие как minify, обеспечивают минификацию кода, сокращая его для уменьшения времени загрузки страницы.

  3. Псевдонимы ресурсов: Методы setAlias и getAlias позволяют работать с псевдонимами ресурсов, заменяя длинные или повторяющиеся пути на короткие и удобные для использования в коде.

  4. Проверка добавленных файлов: Функция isFileAdded позволяет проверить, был ли уже добавлен файл в ресурсный список, предотвращая дублирование.

  5. Управление порядком загрузки: Ресурсы можно добавлять с определенным порядковым номером (параметр order), что позволяет контролировать порядок их вставки в HTML.

Характеристика стиля PHP:

  • Объектно-ориентированный стиль: Код использует статические методы (например, static::linkFile, static::$alias) для работы с ресурсами. Это указывает на использование объектно-ориентированного подхода, где ресурсы инкапсулируются в классе и доступны через статические вызовы.

  • Гибкость и расширяемость: Использование псевдонимов (через setAlias и getAlias) позволяет гибко управлять путями к ресурсам, а механизмы минификации и добавления файлов с заданным порядком (сортировка через ksort) повышают расширяемость кода.

  • Качество и безопасность: Есть проверки на существование файлов перед их добавлением (file_exists), а также возможность управления перезаписью ресурсов (canReWrite). Это помогает избежать ошибок и нежелательных перезаписей.

  • Чистота и читаемость: Код хорошо структурирован с комментариями, которые объясняют назначение каждой функции и детали их работы. Однако, можно было бы улучшить документацию, добавив больше подробностей по функционалу каждого метода.

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

 

defined('COT_CODE') or die('Wrong URL');  // Проверка, что код был вызван из системы Cotonti, иначе завершение выполнения с сообщением об ошибке.

 /**
 * Cotonti Resource control class
 *
 * @package API - Resources
 * @copyright (c) Cotonti Team
 * @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
 */
class Resources  // Объявление класса Resources, который будет отвечать за управление ресурсами в системе Cotonti
{
    /**
     * @var array predefined aliases
     */
    protected static $alias = array (  // Массив, который хранит предустановленные алиасы для различных ресурсов.
        '@jQuery' => 'js/jquery.min.js',  // Алиас для jQuery, который указывает на путь к файлу js/jquery.min.js

        '@ckeditor' => 'plugins/ckeditor/lib/ckeditor.js',  // Алиас для CKEditor, указывающий на путь к файлу ckeditor.js

        '@ckeditorPreset.js' => 'plugins/ckeditor/presets/ckeditor.default.set.js',  // Алиас для набора пресетов CKEditor

        '@bootstrap.js' => 'lib/bootstrap/js/bootstrap.min.js',  // Алиас для Bootstrap JS, указывающий на путь к файлу bootstrap.min.js
        '@bootstrap.css' => 'lib/bootstrap/css/bootstrap.min.css',  // Алиас для Bootstrap CSS, указывающий на путь к файлу bootstrap.min.css
        '@bootstrapTheme.css' => null  // Неопределённое значение для темы Bootstrap. Место для настройки по желанию.
    );

    // ==== predefined alias constants ====
    const jQuery = '@jQuery';  // Константа для алиаса jQuery
    const bootstrap = '@bootstrap.js';  // Константа для алиаса Bootstrap JS
    const ckeditor = '@ckeditor';  // Константа для алиаса CKEditor
    // ==== /predefined alias constants ====
/**
 * @var array Resources Registry
 */
protected static $registry = [];  // Массив для регистрации ресурсов, которые могут быть использованы в различных частях системы Cotonti.

/**
 * @var array footer Resources Registry
 */
protected static $footerRc = [];  // Массив для хранения ресурсов, которые будут загружены в подвал страницы (footer).

/**
 * @var array header Resources Registry
 */
protected static $headerRc = [];  // Массив для хранения ресурсов, которые будут загружены в заголовок страницы (header).

protected static $addedFiles = array();  // Массив для хранения файлов, которые уже были добавлены в систему.

protected static $skip_minification = false;  // Переменная, которая указывает, нужно ли пропускать процесс минимизации файлов (например, для JS или CSS).

protected static $cacheOn = false;  // Переменная, которая указывает, включен ли кэш в системе.

protected static $consolidate = false;  // Переменная, которая указывает, нужно ли объединять ресурсы (например, несколько файлов JS или CSS в один).

protected static $isAdmin = false;  // Переменная, которая проверяет, является ли текущий пользователь администратором.

protected static $minify = false;  // Переменная, которая указывает, нужно ли минимизировать ресурсы (JS, CSS).

/**
 * @var bool header.php executed?
 */
protected static $headerComplete = false;  // Переменная, которая указывает, был ли выполнен файл header.php.

private static $htmlCleanupEnabled = false;  // Переменная для включения или отключения очистки HTML-кода.

/**
 * @var string $dir Resources cache dir
 */
protected static $dir = '';  // Переменная для хранения пути к директории кэша для ресурсов.

public static function __init()
{
    // Проверка, если константа COT_HEADER_COMPLETE определена, то ставим значение $headerComplete в true.
	if (defined('COT_HEADER_COMPLETE')) {
        static::$headerComplete = true;
    }

    // Устанавливаем значение переменной $cacheOn из конфигурации Cotonti.
	static::$cacheOn = Cot::$cfg['cache'];

    // Преобразуем настройку конфигурации для объединения ресурсов в булев тип и сохраняем её.
	static::$consolidate = (bool) Cot::$cfg['headrc_consolidate'];

    // Устанавливаем путь к директории для кэшированных ресурсов.
	static::$dir = Cot::$cfg['cache_dir'] . '/assets/';

    // Проверка, является ли текущий пользователь администратором.
	static::$isAdmin = defined('COT_ADMIN');

    // Устанавливаем значение минимизации ресурсов из конфигурации.
	static::$minify = (bool) Cot::$cfg['headrc_minify'];

    // Включаем очистку HTML-кода, если это указано в конфигурации и если пользователь не является администратором.
    static::$htmlCleanupEnabled = (bool) Cot::$cfg['html_cleanup'] && !static::$isAdmin;

    // Если нужно объединять ресурсы, проверяем, включен ли кэш и разрешена ли эта опция, а также не является ли пользователь администратором.
	static::$consolidate = static::$cacheOn && static::$consolidate && !static::$isAdmin;

    // Если объединение ресурсов включено, создаём директорию для кэширования ресурсов, если она ещё не существует.
	if (static::$consolidate) {
        if (!file_exists(static::$dir)) {
            mkdir(static::$dir, Cot::$cfg['dir_perms'], true);  // Создаём директорию с нужными правами доступа.
        }
	}
}
/**
 * Добавляет файл JS/CSS в реестр ресурсов для последующей консолидации с другими
 * такими ресурсами и сохранения в кэш.
 *
 * Рекомендуется использовать файлы вместо встроенного кода и использовать этот метод
 * вместо Resources::addEmbed(). Используйте этот способ для любых статических JavaScript или
 * CSS файлов.
 *
 * Не размещайте приватные данные в ресурсных файлах — это небезопасно. Если вам действительно нужно это,
 * используйте прямой вывод вместо этого.
 *
 * @param string $path Путь к файлу *.js или *.css
 * @param string $type Тип ресурса
 * @param int $order Номер приоритета
 * @param string $scope Область использования ресурса. Область — это селектор домена, где используется ресурс. Допустимые области:
 *        'global' - глобально для всего сайта, будет включен везде, это самая статичная и постоянная область;
 *        'guest' - только для незарегистрированных посетителей;
 *        'user' - только для зарегистрированных пользователей;
 *        'group_123' - для участников конкретной группы (maingrp), в этом примере для группы с id=123.
 *        Рекомендуется использовать область 'global', когда это возможно, так как это дает наилучшие возможности кэширования.
 * @return bool Возвращает TRUE, если успешно, или FALSE, если файл не найден
 * @throws Exception
 */
public static function addFile($path, $type = '', $order = 50, $scope = 'global')
{
    // Если header.php уже был выполнен, пытаемся добавить файл в футер
	if (static::$headerComplete) { 
        return Resources::linkFileFooter($path, $type, $order); // Возвращаем результат добавления в футер
    }

    // Разделяем путь по символу "?", если он присутствует (для параметров в URL)
	$tmp = explode('?', $path); // Разделяем строку пути
	$fileName = $tmp[0]; // Извлекаем имя файла без параметров

    // Проверяем, был ли файл уже добавлен
	if (in_array($fileName, static::$addedFiles)) return false; // Если файл уже добавлен, возвращаем false

    // Если файл начинается с символа '@', используем алиас для замены
	if (mb_strpos($fileName, '@') === 0) { 
		$fileName = static::$alias[$fileName]; // Заменяем на соответствующий алиас
	} elseif (
        mb_strpos($fileName, 'http://') === false
        && mb_strpos($fileName, 'https://') === false
        && mb_strpos($fileName, '//') !== 0
    ) {
        // Если это локальный файл, проверяем его существование
		if (!file_exists($fileName)) { 
			throw new Exception('Resource file «' . $fileName . '» not exists'); // Выбрасываем исключение, если файл не найден
		}
	}

    // Если тип ресурса не задан, определяем его по расширению файла
	if (empty($type)) { 
        $type = preg_match('#\.(min\.)?(js|css)$#', mb_strtolower($fileName), $m) ? $m[2] : 'js'; // Определяем тип по расширению файла
    }

    // Добавляем файл в список уже добавленных
	static::$addedFiles[] = $tmp[0]; // Добавляем имя файла в список добавленных файлов

    // Если включена консолидация и минимизация ресурсов, и файл не минимизирован
	if (
        static::$consolidate
        && static::$minify
        && !static::$skip_minification
        && mb_strpos($fileName, '.min.') === false
        && mb_strpos($fileName, '.pack.') === false
    ) {
        // Минимизируем файл и сохраняем его в кэш
		if ($fileName != '') { 
			$bname = ($type == 'css') ? str_replace('/', '._.', $fileName) : basename($fileName) . '.min'; // Формируем имя файла
			$content = file_get_contents($fileName); // Читаем содержимое файла
			if($content == '' || $content === false) return false; // Если файл пустой или не удалось прочитать, возвращаем false
			$code = static::minify($content, $type); // Минимизируем содержимое
			$path = static::$dir . $bname; // Путь для сохранения минимизированного файла
			file_put_contents($path, $code); // Сохраняем минимизированный файл
		}
	}

    // Если консолидация включена и кэширование активно, добавляем файл в реестр ресурсов
	if (static::$consolidate && static::$cacheOn && !static::$isAdmin) { 
		static::$registry[$type][$scope][$order][] = $path; // Добавляем файл в реестр
	} else {
        // В противном случае добавляем файл в список файлов
		static::$registry[$type]['files'][$scope][$order][] = $path; // Добавляем файл в реестр файлов
	}

    // Добавляем дополнительные файлы, связанные с этим
	foreach (static::additionalFiles($tmp[0]) as $file) { 
		static::addFile($file, '', $order, $scope); // Рекурсивно добавляем дополнительные файлы
	}

    // Возвращаем успешный результат
	return true; // Возвращаем true, если файл успешно добавлен
}
protected static function additionalFiles($file)
{
    $ret = array(); // Создаём пустой массив для хранения дополнительных файлов

    switch ($file) // Проводим проверку на конкретный файл
    {
        case '@bootstrap.js': 
            $ret[] = '@bootstrap.css'; // Если это '@bootstrap.js', добавляем '@bootstrap.css'
            $ret[] = '@bootstrapTheme.css'; // Добавляем '@bootstrapTheme.css'
            break;

        case '@ckeditor': 
            $ret[] = '@ckeditorPreset.js'; // Если это '@ckeditor', добавляем '@ckeditorPreset.js'
            break;
    }

    return $ret; // Возвращаем массив дополнительных файлов
}
/**
 * Вставляет фрагмент встроенного кода в реестр ресурсов CSS/JS для хедера.
 *
 * Настоятельно рекомендуется использовать файлы для CSS/JS, когда это возможно,
 * и вызывать функцию Resources::AddFile() для них, а не встраивать код
 * на страницу с использованием этой функции. Эта функция должна использоваться для
 * динамически генерируемого кода, который не может быть сохранён в статических файлах.
 *
 * @param string $identifier Алфавитно-цифровой идентификатор для фрагмента, используемый для управления обновлениями и т.д.
 * @param string $code Встроенный код стилей или скрипта
 * @param string $scope Область ресурса. Смотрите описание этого параметра в документации Resources::AddFile().
 * @param string $type Тип ресурса: 'js' или 'css'
 * @param int $order Приоритет порядка
 *
 * @return bool Эта функция всегда возвращает TRUE
 * @see Resources::AddFile()
 */
public static function addEmbed($code, $type = 'js', $order = 50, $scope = 'global', $identifier = '')
{
    // header.php выполнен. Пытаемся добавить код в footer
    if (static::$headerComplete) { 
        static::embedFooter($code, $type, $order); // Если header.php уже выполнен, добавляем код в footer
    }

    // Если используется консолидация и минификация, сохраняем в файл
    if (static::$consolidate && static::$cacheOn && !static::$isAdmin) { 
        if (!$identifier) { 
            $identifier = md5($code . $type); // Если идентификатор не задан, генерируем его из хеша кода и типа
        }
        // Сохраняем как файл
        $path = static::$dir . $identifier . '.' . $type; // Формируем путь для сохранения файла
        if (!file_exists($path) || md5($code) != md5_file($path)) { 
            // Если файл не существует или его хеш не совпадает с хешем нового кода
            if (static::$minify && !static::$skip_minification) { 
                $code = static::minify($code, $type); // Минифицируем код, если это требуется
            }
            file_put_contents($path, $code); // Записываем код в файл
        }
        static::$registry[$type][$scope][$order][] = $path; // Добавляем путь к файлу в реестр
    } else { 
        $separator = !static::$htmlCleanupEnabled ? "\n" : ' '; // Определяем разделитель в зависимости от настроек очистки HTML
        if ($type === 'js') { 
            $code = trim($code); // Убираем лишние пробелы с начала и конца кода
            $last = (substr($code, -1)); 
            if ($last !== ';') { 
                $separator = ";" . $separator; // Добавляем точку с запятой в конец, если её нет
            }
        }
        if (!isset(static::$registry[$type]['embed'])) { 
            static::$registry[$type]['embed'] = []; // Если раздела для встраиваемых ресурсов ещё нет, создаём его
        }
        if (!isset(static::$registry[$type]['embed'][$scope][$order])) { 
            static::$registry[$type]['embed'][$scope][$order] = ''; // Если для указанного порядка нет значения, создаём его
        }
        static::$registry[$type]['embed'][$scope][$order] .= $code . $separator; // Добавляем код в реестр
    }

    return true; // Функция всегда возвращает true
}

public static function render()
{
    global $theme, $cot_rc_html;

    if (!isset($cot_rc_html[$theme]) || !static::$consolidate) { 
        $cot_rc_html = static::consolidate(); // Если нет консолидации или ресурсы ещё не собраны, вызываем метод для консолидации
    }

    $ret = ''; 
    $pass = true; 
    if (is_array($cot_rc_html) && isset($cot_rc_html[$theme])) { 
        foreach ($cot_rc_html[$theme] as $scope => $html) { 
            switch ($scope) { 
                case 'global': 
                    $pass = true; // Для глобальных ресурсов всегда разрешаем добавление
                    break; 
                case 'guest': 
                    $pass = Cot::$usr['id'] == 0; // Для гостей проверяем, что пользователь не авторизован
                    break; 
                case 'user': 
                    $pass = Cot::$usr['id'] > 0; // Для зарегистрированных пользователей проверяем, что пользователь авторизован
                    break; 
                default: 
                    $parts = explode('_', $scope); 
                    $pass = count($parts) == 2 && $parts[0] == 'group' && $parts[1] == Cot::$usr['maingrp']; // Для группы проверяем, что группа совпадает с основной группой пользователя
            }
            if ($pass) { 
                $ret = $html . $ret; // Если условие проходит, добавляем HTML в результат
            }
        }
    }

    // Теперь собираем ресурсы, которые не должны быть минифицированы
    if (!is_array(static::$headerRc)) { 
        return $ret; // Если нет ресурсов для хедера, возвращаем результат
    }

    // CSS должен идти первым
    ksort(static::$headerRc); 
    foreach (static::$headerRc as $type => $data) { 
        if (!empty(static::$headerRc[$type]) && is_array(static::$headerRc[$type])) { 
            ksort(static::$headerRc[$type]); 
            foreach (static::$headerRc[$type] as $order => $htmlArr) { 
                foreach ($htmlArr as $key => $path) { 
                    if (mb_strpos($type, '_embed') !== false) { 
                        $ret .= $path; // Для встроенных ресурсов добавляем путь
                        if (!static::$htmlCleanupEnabled) { 
                            $ret .= "\n"; // Если очистка HTML отключена, добавляем новую строку
                        }
                    } else { 
                        if (mb_strpos($path, '@') === 0) { 
                            $path = static::$alias[$path]; // Если путь начинается с алиаса, заменяем на реальный путь
                            if (empty($path)) { 
                                continue; // Если путь пустой, пропускаем
                            }
                        }
                        $ret .= cot_rc("code_rc_{$type}_file", ['url' => $path]); // Добавляем путь через функцию cot_rc
                        if (!static::$htmlCleanupEnabled) { 
                            $ret .= "\n"; // Если очистка HTML отключена, добавляем новую строку
                        }
                    }
                }
            }
        }
    }
    static::$headerComplete = true; // Отмечаем, что хедер завершён

    return trim($ret); // Возвращаем итоговый результат
}


}

 

/**
 * Consolidate all resources and make single file
 */
protected static function consolidate()
{
    global $cot_rc_html, $theme;

    // Если нужно собирать и ужимать, делаем это
    if (!is_array(static::$registry)) { 
        return false; // Если нет реестра ресурсов, возвращаем false
    }

    // CSS должен идти первым
    ksort(static::$registry); 

    // Строим вывод хедера
    $cot_rc_html[$theme] = [];

    // Консолидация ресурсов
    if (static::$cacheOn && static::$consolidate && !static::$isAdmin) { 
        clearstatcache(); // Очищаем кеш файлов

        foreach (static::$registry as $type => $scope_data) { 
            // Консолидация
            foreach ($scope_data as $scope => $ordered_files) { 
                ksort($ordered_files); // Сортируем файлы по порядку
                $target_path = static::$dir . $scope . '.' . $theme . '.' . $type; // Формируем путь к конечному файлу

                $files = []; 
                foreach ($ordered_files as $order => $o_files) { 
                    $files = array_merge($files, $o_files); // Объединяем файлы
                }
                $files = array_unique($files); // Убираем дубли

                foreach ($files as $key => $file) { 
                    if (mb_strpos($file, '@') === 0) { 
                        $tmp = static::$alias[$file]; 
                        if (empty($tmp)) { 
                            unset($files[$key]); // Если путь пустой, убираем файл из списка
                        } else { 
                            $files[$key] = $tmp; // Заменяем алиас на реальный путь
                        }
                    }
                }

                $code = ''; 
                $modified = false; 
                $fileTime = 0;

                if (!file_exists($target_path)) { 
                    // Просто создаем новый кеш-файл
                    $file_list = $files; 
                    $modified = true; // Отмечаем, что файл изменён
                } else { 
                    $fileTime = filemtime($target_path); // Получаем время последнего изменения файла

                    // Загружаем список файлов, уже закешированных
                    $file_list = unserialize(file_get_contents("{$target_path}.idx"));
                    $file_list = !empty($file_list) ? $file_list : []; // Если список пустой, инициализируем как пустой массив

                    // Проверяем присутствие или время модификации каждого файла
                    foreach ($files as $path) { 
                        if (!in_array($path, $file_list) || filemtime($path) >= $fileTime) { 
                            $modified = true; // Если файл изменён или не найден в списке, помечаем его как изменённый
                            break; 
                        }
                    }
                }

                if ($modified) { 
                    // Пересоздаём кеш
                    $current_path = str_replace('\\', '/', realpath('.')); 
                    foreach ($files as $path) { 
                        // Получаем содержимое файла и удаляем BOM
                        $file_code = str_replace(pack('CCC', 0xef, 0xbb, 0xbf), '', file_get_contents($path));

                        if ($type == 'css') { 
                            if (strpos($path, '._.') !== false) { 
                                // Восстанавливаем оригинальный путь к файлу
                                $path = str_replace('._.', '/', basename($path)); 
                            }
                            if ($path[0] === '/') { 
                                $path = mb_substr($path, 1); // Убираем ведущий слэш из пути
                            }
                            $file_path = str_replace('\\', '/', dirname(realpath($path))); 
                            $relative_path = str_replace($current_path, '', $file_path); 
                            if ($relative_path[0] === '/') { 
                                $relative_path = mb_substr($relative_path, 1); // Убираем ведущий слэш из относительного пути
                            }
                            // Применяем CSS импорты
                            if (
                                preg_match_all(
                                    '#@import\s+url\((\'|")?([^\'")]+)\1?\);#i',
                                    $file_code,
                                    $mt,
                                    PREG_SET_ORDER
                                )
                            ) { 
                                foreach ($mt as $m) { 
                                    if (preg_match('#^https?://#i', $m[2])) { 
                                        $filename = $m[2]; 
                                    } else { 
                                        $filename = empty($relative_path) ? $m[2] : $relative_path . '/' . $m[2]; 
                                    }
                                    $file_code = str_replace($m[0], file_get_contents($filename), $file_code); // Заменяем импорт на содержимое
                                }
                            }
                            // Исправляем URL
                            if (preg_match_all(
                                '#\burl\((\'|")?([^\)"\']+)\1?\)#i',
                                $file_code,
                                $mt,
                                PREG_SET_ORDER)
                            ) { 
                                foreach ($mt as $m) { 
                                    $fileFullName = trim(empty($relative_path) ? $m[2] : $relative_path . '/' . $m[2]); 
                                    $tmp = explode('?', $fileFullName); 
                                    $fileName = $tmp[0]; 

                                    $fileName = str_replace($current_path, '', str_replace('\\', '/', realpath($fileName))); 
                                    if (!$fileName) { 
                                        continue; 
                                    }

                                    if ($fileName[0] === '/') { 
                                        $fileName = mb_substr($fileName, 1); 
                                    }
                                    if (!empty($tmp[1])) { 
                                        $fileName .= '?' . $tmp[1]; 
                                    }
                                    $file_code = str_replace($m[0], 'url("' . $fileName . '")', $file_code); // Заменяем URL на правильный путь
                                }
                            }
                        }
                        $separator = "\n"; 
                        if ($type == 'js') { 
                            $file_code = trim($file_code); 
                            $last = (substr($file_code, -1)); 
                            if ($last != ';') { 
                                $separator = ";\n"; 
                            }
                        }
                        $code .= $file_code . $separator; // Добавляем содержимое файла в итоговый код
                    }

                    file_put_contents($target_path, $code); // Записываем результат в файл
                    if (Cot::$cfg['gzip']) { 
                        file_put_contents("$target_path.gz", gzencode($code)); // Если включена сжатие, записываем сжатую версию
                    }
                    file_put_contents("$target_path.idx", serialize($files)); // Сохраняем список файлов в индекс

                    $fileTime = filemtime($target_path); // Обновляем время последней модификации файла
                }

                $rcUrl = "rc.php?rc=$scope.$theme.$type&nc=" . $fileTime; // Формируем URL для ресурса

                if (empty($cot_rc_html[$theme][$scope])) { 
                    $cot_rc_html[$theme][$scope] = ''; 
                }
                $cot_rc_html[$theme][$scope] .= cot_rc("code_rc_{$type}_file", ['url' => $rcUrl]); // Добавляем ссылку на ресурс
                if (!static::$htmlCleanupEnabled) { 
                    $cot_rc_html[$theme][$scope] .= "\n"; 
                }
            }
        }
        // Сохраняем вывод
        static::$cacheOn && Cot::$cache && Cot::$cache->db->store('cot_rc_html', $cot_rc_html); 
    } else { 
        $log = []; // Лог путей, чтобы избежать дублирования
        foreach (static::$registry as $type => $resData) { 
            if (!empty(static::$registry[$type]['files']) && is_array(static::$registry[$type]['files'])) { 
                foreach (static::$registry[$type]['files'] as $scope => $scope_data) { 
                    ksort($scope_data); 
                    foreach ($scope_data as $order => $files) { 
                        foreach ($files as $file) { 
                            if (!in_array($file, $log)) { 
                                $fileName = $file; 
                                if (mb_strpos($file, '@') === 0) { 
                                    $fileName = static::$alias[$file]; 
                                    if (empty($fileName)) { 
                                        continue; 
                                    }
                                }
                                if (empty($cot_rc_html[$theme][$scope])) { 
                                    $cot_rc_html[$theme][$scope] = ''; 
                                }
                                $cot_rc_html[$theme][$scope] .= cot_rc(
                                    "code_rc_{$type}_file",
                                    ['url' => $fileName]
                                ); 
                                if (!static::$htmlCleanupEnabled) { 
                                    $cot_rc_html[$theme][$scope] .= "\n"; 
                                }
                                $log[] = $file; // Добавляем файл в лог
                            }
                        }
                    }
                }
            }
            if (!empty(static::$registry[$type]['embed']) && is_array(static::$registry[$type]['embed'])) { 
                foreach (static::$registry[$type]['embed'] as $scope => $scope_data) { 
                    ksort($scope_data); 
                    foreach ($scope_data as $order => $code) { 
                        if (empty($cot_rc_html[$theme][$scope])) { 
                            $cot_rc_html[$theme][$scope] = ''; 
                        }
                        $cot_rc_html[$theme][$scope] .= cot_rc("code_rc_{$type}_embed", ['code' => $code]); // Добавляем встроенный код
                        if (!static::$htmlCleanupEnabled) { 
                            $cot_rc_html[$theme][$scope] .= "\n"; 
                        }
                    }
                }
            }
        }
    }
    return $cot_rc_html; // Возвращаем финальный результат
}

 

/**
 * Render footer resources
 */
public static function renderFooter()
{
    // Проверяем, является ли $footerRc массивом
    if (!is_array(static::$footerRc)) {
        return false; // Если нет, возвращаем false
    }

    // CSS должен идти первым
    ksort(static::$footerRc); 
    $ret = ''; 

    // Проходим по типам ресурсов в $footerRc
    foreach (static::$footerRc as $type => $data) {
        // Проверяем, есть ли данные для текущего типа и является ли это массивом
        if (!empty(static::$footerRc[$type]) && is_array(static::$footerRc[$type])) {
            ksort(static::$footerRc[$type]); // Сортируем ресурсы внутри типа

            // Проходим по каждому ресурсу в массиве
            foreach (static::$footerRc[$type] as $order => $htmlArr) {
                // Проходим по каждому элементу массива
                foreach ($htmlArr as $key => $path) {
                    // Если это встроенный код (embed), добавляем его напрямую
                    if (mb_strpos($type, '_embed') !== false) {
                        $ret .= $path; 
                        if (!static::$htmlCleanupEnabled) { 
                            $ret .= "\n"; // Если очистка HTML не включена, добавляем перенос строки
                        }
                    } else { 
                        // Если это не встроенный код, проверяем алиас пути
                        if (mb_strpos($path, '@') === 0) {
                            $path = static::$alias[$path]; // Заменяем алиас на реальный путь
                            if ($path == '') { 
                                continue; // Если путь пустой, пропускаем его
                            }
                        }
                        // Добавляем ресурс в итоговый вывод
                        $ret .= cot_rc("code_rc_{$type}_file", ['url' => $path]);
                        if (!static::$htmlCleanupEnabled) { 
                            $ret .= "\n"; // Если очистка HTML не включена, добавляем перенос строки
                        }
                    }
                }
            }
        }
    }

    return trim($ret); // Убираем лишние пробелы в начале и в конце и возвращаем результат
}

 

/**
 * Удобный способ вывода ссылки на CSS/JS файл в шапке страницы
 *
 * @param string $path Путь/URL к стилям *.css или скрипту *.js
 * @param string $type
 * @param int $order
 * @return bool
 *
 * @throws Exception
 */
public static function linkFile($path, $type = '', $order = 50)
{
    // Если header.php уже выполнен, пытаемся добавить файл в футер
    if (static::$headerComplete) {
        return Resources::linkFileFooter($path, $type, $order);
    }

    $tmp = explode('?', $path); // Разделяем путь на основную часть и параметры
    $fileName = $tmp[0]; // Основное имя файла без параметров

    // Если файл уже был добавлен, выходим
    if (in_array($fileName, static::$addedFiles)) {
        return false;
    }

    // Если путь начинается с '@', заменяем его на соответствующий алиас
    if (mb_strpos($fileName, '@') === 0) {
        $fileName = static::$alias[$fileName];
    } elseif (
        mb_strpos($fileName, 'http://') === false
        && mb_strpos($fileName, 'https://') === false
        && mb_strpos($fileName, '//') !== 0
    ) {
        // Если файл не является абсолютным URL, проверяем его существование
        if (!file_exists($fileName)) {
            throw new Exception('Resource file «' . $fileName . '» not exists');
        }
    }

    // Если тип не указан, определяем его по расширению файла (css или js)
    if (empty($type)) {
        $type = preg_match('#\.(js|css)$#i', $fileName, $m) ? strtolower($m[1]) : 'js';
    }

    // Добавляем файл в список добавленных
    static::$addedFiles[] = $tmp[0];
    static::$headerRc[$type][$order][] = $path; // Добавляем путь в список ресурсов для вывода в header

    // Обрабатываем дополнительные файлы, если они есть
    foreach (static::additionalFiles($tmp[0]) as $file) {
        static::linkFile($file, '', $order); // Рекурсивно добавляем файлы
    }
}

/**
 * Удобный способ добавления JavaScript или CSS файла в футер
 *
 * @param string $path Путь к JavaScript или CSS файлу
 * @param string $type
 * @param int $order
 * @return bool
 * @throws Exception
 */
public static function linkFileFooter($path, $type = '', $order = 50)
{
    $tmp = explode('?', $path); // Разделяем путь на основную часть и параметры
    $fileName = $tmp[0]; // Основное имя файла без параметров

    // Если файл уже был добавлен, выходим
    if (in_array($fileName, static::$addedFiles)) {
        return false;
    }

    // Если путь начинается с '@', заменяем его на соответствующий алиас
    if (mb_strpos($fileName, '@') === 0) {
        $fileName = static::$alias[$fileName];
    } elseif (
        mb_strpos($fileName, 'http://') === false
        && mb_strpos($fileName, 'https://') === false
        && mb_strpos($fileName, '//') !== 0
    ) {
        // Если файл не является абсолютным URL, проверяем его существование
        if (!file_exists($fileName)) {
            throw new Exception('Resource file «' . $fileName . '» not exists');
        }
    }

    // Если тип не указан, определяем его по расширению файла (css или js)
    if (empty($type)) {
        $type = preg_match('#\.(js|css)$#i', $fileName, $m) ? strtolower($m[1]) : 'js';
    }

    // Добавляем файл в список добавленных
    static::$addedFiles[] = $tmp[0];
    static::$footerRc[$type][$order][] = $path; // Добавляем путь в список ресурсов для вывода в footer

    // Обрабатываем дополнительные файлы, если они есть
    foreach (static::additionalFiles($tmp[0]) as $file) {
        $type = preg_match('#\.(js|css)$#i', $file, $m) ? strtolower($m[1]) : 'js';
        // Если это CSS и header еще не завершен, добавляем файл в header
        if ($type == 'css' && !static::$headerComplete) {
            static::linkFile($file, 'css', $order);
        } else {
            static::linkFileFooter($file, '', $order); // Иначе добавляем файл в footer
        }
    }
}

 

/**
 * Удобный способ вывода встроенного стиля/скрипта в шапке страницы
 *
 * Пример: Resources::embed(" alert('ssssss') ");
 * Пример: Resources::embed(" .blablabla {color: #000000} ", 'css');
 *
 * @param string $code Код стиля или скрипта
 * @param int $order Порядок вывода
 * @param string $type Тип ресурса: 'js' или 'css'
 * @param string $attr Атрибут для тега вывода
 */
public static function embed($code, $type = 'js', $order = 50, $attr = '')
{
    // Если header.php уже выполнен, пытаемся добавить код в футер
    if (static::$headerComplete) {
        Resources::embedFooter($code, $type, $order, $attr);
    }

    // Добавляем код стиля или скрипта в список ресурсов для вывода в header
    static::$headerRc[$type . '_embed'][$order][] = cot_rc(
        "code_rc_{$type}_embed",
        ['code' => $code, 'attr' => $attr]
    );
}

/**
 * Удобный способ вывода встроенного стиля/скрипта в футере страницы
 *
 * Пример: Resources::embedFooter(" alert('ssssss') ");
 *
 * @param string $code Код стиля или скрипта
 * @param string $type Тип ресурса: 'js' или 'css'
 * @param int $order Порядок вывода
 * @param string $attr Атрибут для тега вывода
 */
public static function embedFooter($code, $type = 'js', $order = 50, $attr = '')
{
    // Добавляем код стиля или скрипта в список ресурсов для вывода в footer
    static::$footerRc[$type . '_embed'][$order][] = cot_rc("code_rc_{$type}_embed", array(
        'code' => $code,
        'attr' => $attr
    ));
}

/**
 * Функция минимизации JS/CSS кода
 *
 * @param string $code Код для минимизации
 * @param string $type Тип: 'js' или 'css'
 *
 * @return string Минифицированный код
 */
public static function minify($code, $type = 'js')
{
    if ($type == 'js') {
        require_once './lib/jsmin.php'; // Подключаем библиотеку для минимизации JS
        $code = JSMin::minify($code); // Минифицируем JS код
    } elseif ($type == 'css') {
        require_once './lib/cssmin.php'; // Подключаем библиотеку для минимизации CSS
        $code = minify_css($code); // Минифицируем CSS код
    }

    return $code; // Возвращаем минимизированный код
}

 

/**
 * Устанавливает псевдоним ресурса
 * @param string $newAlias Новый псевдоним
 * @param string $value Значение для псевдонима
 * @param bool   $canReWrite Разрешение на перезапись существующего псевдонима
 * @return bool Возвращает true, если псевдоним был установлен успешно, иначе false
 */
public static function setAlias($newAlias, $value = '', $canReWrite = false)
{
    // Если псевдоним пустой, возвращаем false
    if ($newAlias == '') {
        return false;
    }

    // Если псевдоним не начинается с '@', добавляем его в начало
    if (mb_strpos($newAlias, '@') === false) {
        $newAlias = '@' . $newAlias;
    }

    // Если перезапись не разрешена, а псевдоним уже существует, возвращаем false
    if (!$canReWrite && isset(static::$alias[$newAlias]) && static::$alias[$newAlias] !== null) {
        return false;
    }

    // Устанавливаем значение для псевдонима
    static::$alias[$newAlias] = $value;

    return true;
}

/**
 * Получить значение по псевдониму
 * @param string $aliasName Имя псевдонима
 * @return mixed|null Возвращает значение псевдонима или null, если он не найден
 */
public static function getAlias($aliasName)
{
    // Если имя псевдонима пустое, возвращаем null
    if ($aliasName == '') {
        return null;
    }

    // Если псевдоним не начинается с '@', добавляем его в начало
    if (mb_strpos($aliasName, '@') === false) {
        $aliasName = '@' . $aliasName;
    }

    // Если псевдоним не существует, возвращаем null
    if (!isset(static::$alias[$aliasName])) {
        return null;
    }

    // Возвращаем значение псевдонима
    return static::$alias[$aliasName];
}

/**
 * Проверяет, был ли файл уже добавлен
 *
 * Псевдонимы файлов не разрешаются. Они могут быть переопределены. Используйте псевдонимы, если это возможно.
 *
 * @param string $fileName Имя файла или его псевдоним
 * @return bool Возвращает true, если файл уже добавлен, иначе false
 */
public static function isFileAdded($fileName)
{
    // Проверяем, был ли файл уже добавлен
    if (in_array($fileName, static::$addedFiles)) {
        return true;
    }
    return false;
}

// Инициализация ресурсов
Resources::__init();

 

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

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

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

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

Administrator

Оффлайн

Administrator

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

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

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

Файл resources.rc.php в Cotonti
1 Файл resources.rc.php в системной папке Cotonti CMF выполняет роль ресурса для управления и хранения различных строк,
Файл admin.resources.php в Cotonti CMF
2 Основное назначение файла "admin.resources.php" в Cotonti CMF: Этот файл предоставляет ресурсы, связанные с
Файл page.resources.php в Cotonti
3 Файл "page.resources.php" в контексте движка Cotonti CMF служит для определения множества вспомогательных
Модуль "Users", - users.resources.php в Cotonti CMF
4 Файл "users.resources.php" является частью системы Cotonti CMF и находится в директории /modules/users/inc.