/mnt/web601/b3/14/57451114/htdocs/httpdocs/dynamic_theme_style.css.php
<?php
/*--------------------------------------------------------------------
dynamic_theme_style.css.php 2021-11-03
Gambio GmbH
http://www.gambio.de
Copyright (c) 2021 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
-------------------------------------------------------------------*/
/*
* DYNAMIC THEME STYLE
*
* This script will handle the creation and delivery of the requested theme CSS.
*
* OPTIONAL GET PARAMETERS
*
* - style_name: the currently active StyleEdit3 style name.
* - renew_cache: enforces the style cache renewal.
*
*/
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_CORE_ERROR & ~E_CORE_WARNING);
@date_default_timezone_set('Europe/Berlin');
require_once __DIR__ . '/GXMainComponents/ApplicationCss.inc.php';
$application = new Gambio\GX\ApplicationCss();
$application->run();
// Setup style required constants.
define('CACHE_FILENAME', '__dynamics.css');
define('DIR_PUBLISHED_THEME_PATH', StyleEditServiceFactory::service()->getPublishedThemePath() ?? 'public/theme');
define('DIR_FS_PUBLISHED_THEME_PATH', DIR_FS_CATALOG . DIR_PUBLISHED_THEME_PATH);
// Setup optional parameter aliases.
$styleName = $_GET['style_name'] ?? StyleEditServiceFactory::service()->getStyleFileName();
$renewCache = $_GET['renew_cache'] ?? StyleEditServiceFactory::service()->forceCssCacheRenewal();
// Fetch theme name from theme configuration file.
$themeConfigurationFilePath = DIR_FS_PUBLISHED_THEME_PATH . '/theme.json';
$themeConfiguration = json_decode(file_get_contents($themeConfigurationFilePath), true);
$themeId = $themeConfiguration['id'];
$suffix = file_exists(DIR_FS_CATALOG . '.dev-environment') ? '' : '.min';
$additionalCssFiles = [];
$additionalScssFiles = [];
$additionalScssPaths = [];
appendExistingFile($additionalCssFiles, DIR_FS_PUBLISHED_THEME_PATH . '/styles/system/stylesheet.css');
appendExistingFile($additionalCssFiles, DIR_FS_PUBLISHED_THEME_PATH . '/styles/system/vendor' . $suffix . '.css');
appendExistingFile($additionalCssFiles, DIR_FS_CATALOG . 'JSEngine/build/vendor' . $suffix . '.css');
appendExistingFile($additionalCssFiles, DIR_FS_PUBLISHED_THEME_PATH . '/styles/system/vendor_fixes.css');
$themeFiles = GXModulesCache::getInstalledThemeFiles();
$gxModulesFiles = GXModulesCache::getInstalledModuleFiles();
$themes = array_reverse(StaticGXCoreLoader::getThemeControl()->getCurrentThemeHierarchy());
$themes[] = 'all';
foreach ($themes as $currentTheme) {
$lowerCaseCurrentTheme = strtolower(trim($currentTheme));
if(isset($themeFiles[$lowerCaseCurrentTheme]))
{
foreach ($themeFiles[$lowerCaseCurrentTheme] as $gxGroup) {
foreach ($gxGroup['css'] as $file) {
if (substr($file, -4) === '.css') {
$additionalCssFiles[] = $file;
} elseif (substr($file, -9) === 'main.scss') {
$additionalScssFiles[] = $file;
$additionalScssPaths[] = substr(substr($file, 0, strrpos($file, '/')), strlen(DIR_FS_CATALOG));
}
}
}
}
}
$locker = CssRoutineLocker::create( DIR_FS_CATALOG);
$additionalScssFiles = array_unique($additionalScssFiles);
$additionalScssPaths = array_unique($additionalScssPaths);
$cacheFilePath = StyleEditServiceFactory::service()->getCacheFilePath() ??
DIR_FS_CATALOG . 'cache/' . CACHE_FILENAME;
$createCache = false;
if ($renewCache !== null || !file_exists($cacheFilePath) || filesize($cacheFilePath) < 10) {
$createCache = true;
}
if ($createCache === false) {
echo file_get_contents($cacheFilePath) . PHP_EOL . getAdditionalCss($additionalCssFiles, $suffix);
} else {
try {
// during the use of StyleEdit locking has to be disabled to always generate the latest css
if (strpos(DIR_FS_PUBLISHED_THEME_PATH, '/public/tmp/') === false) {
$locker->acquireLock();
}
$css = '';
$fileToServe = 'main.scss';
$basePath = DIR_PUBLISHED_THEME_PATH . '/styles/system/'; // Default theme directory.
$pathPattern = DIR_FS_CATALOG . 'cache/*.css*';
$cachePaths = glob($pathPattern);
if (is_array($cachePaths)) {
foreach ($cachePaths as $result) {
if (strpos($result, '__dynamic') === false) {
unlink($result);
}
}
}
if (file_exists($cacheFilePath)) {
@unlink($cacheFilePath);
}
$errorOccurred = false;
$errorMessage = '';
$styleEditErrorMessage = '';
if (StyleEditServiceFactory::service()->styleEditStylesExists()) {
try {
$_REQUEST['theme'] = 'true'; // Toggle theme mode for StyleEdit.
$styleConfigReader = StyleEditServiceFactory::service()->getStyleEditReader($themeId);
$variableAliases = getFileContent(DIR_FS_PUBLISHED_THEME_PATH. '/styles/system/_variable-aliases.scss');
$variableAliases .= "\n";
$bootstrapScss = $styleConfigReader->getScss('bootstrap');
$templateScss = $styleConfigReader->getScss('template') . $variableAliases;
$customStylesScss = $styleConfigReader->getCustomStyles();
// Download google fonts and use the local fonts
$fontVariableName = StyleEditServiceFactory::service()->getMasterFontVariableName();
$fontUrl = $styleConfigReader->findSettingValueByName($fontVariableName);
if (strpos($fontUrl, '"') === 0 || strpos($fontUrl, '\'') === 0) {
$fontUrl = substr($fontUrl, 1, strlen($fontUrl) - 2);
}
$fontDownloader = new GoogleFontDownloader;
$fontManager = new GoogleFontManager($fontDownloader, $fontUrl !== '' ? $fontUrl : null);
$localFontContent = $fontManager->getFontCss();
if (strlen($localFontContent) !== 0) {
$templateScss .= "\n\n" . '$gx-font-import-url: "";';
$templateScss .= "\n" . $localFontContent;
}
if ($styleConfigReader->getErrorMessage() !== '') {
$styleEditErrorMessage = 'body:before {
content: "' . str_replace('"', '\"', $styleConfigReader->getErrorMessage()) . '";
position: absolute;
background: white;
top: 0;
left: 0;
z-index: 100000;
}';
}
$customDirectoryPath = DIR_FS_PUBLISHED_THEME_PATH . '/styles/system/custom/';
if (file_exists($customDirectoryPath . '_usermod.scss')) {
$customStylesScss .= "\n\n@import \"custom/usermod\";";
}
if (@file_put_contents($customDirectoryPath . '_bootstrap_variables.scss', $bootstrapScss) === false) {
$errorOccurred = true;
}
if (@file_put_contents($customDirectoryPath . '_template_variables.scss', $templateScss) === false) {
$errorOccurred = true;
}
if (@file_put_contents($customDirectoryPath . '_custom_styles.scss', $customStylesScss) === false) {
$errorOccurred = true;
}
if ($errorOccurred) {
$errorMessage = 'body:before {
content: "The directory ' . $customDirectoryPath . ' and/or containing files are not writable. CSS cache file cannot be created causing slow page speed.";
position: absolute;
background: white;
top: 0;
left: 0;
z-index: 100000;
}';
$css .= $errorMessage;
}
} catch (Exception $e) {
$errorOccurred = true;
$errorMessage = '
body:before {
content: "' . str_replace('"', '\"', $e->getMessage()) . '";
position: absolute;
background: white;
top: 0;
left: 0;
z-index: 100000;
}
';
$css .= $errorMessage;
}
} else {
$customDirectoryPath = DIR_FS_PUBLISHED_THEME_PATH . '/styles/custom/';
if (!file_exists($customDirectoryPath . '_bootstrap_variables.scss')) {
@file_put_contents($customDirectoryPath . '_bootstrap_variables.scss', '');
}
if (!file_exists($customDirectoryPath . '_template_variables.scss')) {
@file_put_contents($customDirectoryPath . '_template_variables.scss', '');
}
$customStylesScss = getFileContent($customDirectoryPath . '_custom_styles.scss');
if (file_exists($customDirectoryPath . '_usermod.scss')) {
if (strpos($customStylesScss, '@import "custom/usermod";') === false) {
$customStylesScss .= "\n\n@import \"custom/usermod\";";
@file_put_contents($customDirectoryPath . '_custom_styles.scss', $customStylesScss);
}
} elseif (strpos($customStylesScss, '@import "custom/usermod";') !== false) {
$customStylesScss = str_replace('@import "custom/usermod";', '', $customStylesScss);
@file_put_contents($customDirectoryPath . '_custom_styles.scss', $customStylesScss);
}
}
$compiler = ScssCompilerFactory::create()->createCompiler();
// Serve CSS
$compiler->setVariables([
'theme-base-path' => '"' . DIR_WS_CATALOG . DIR_PUBLISHED_THEME_PATH . '/"'
]);
$compiler->addImportPath($basePath);
$compiler->setBasePath(DIR_FS_CATALOG . $basePath);
if (count($additionalScssPaths) > 0) {
foreach ($additionalScssPaths as $additionalScssPath) {
$compiler->addImportPath($additionalScssPath);
}
}
if ($suffix === '.min') {
$compiler->setFormatter(ScssCompilerInterface::STYLE_COMPRESSED);
} else {
$compiler->setFormatter(ScssCompilerInterface::STYLE_NESTED);
}
$compiler->setAdditionalScssFiles($additionalScssFiles);
ob_start();
try {
$compiler->serve($fileToServe);
} catch (Exception $exception) {
$errorMessage = '
body:before {
content: "' . str_replace('"', '\"', $exception->getMessage()) . '";
position: absolute;
background: white;
top: 0;
left: 0;
z-index: 100000;
}
';
echo $errorMessage . $styleEditErrorMessage;
echo getFileContent(DIR_FS_CATALOG . 'cache/' . CACHE_FILENAME);
$errorOccurred = true;
}
$scss = ob_get_clean();
if (strpos($scss, 'Parse error') === 0) {
$errorMessage = 'body:before {
content: "' . str_replace('"', '\"', str_replace("\n", ' ', str_replace("\r", '', $scss))) . '";
position: absolute;
background: white;
top: 0;
left: 0;
z-index: 100000;
}';
$scss = $errorMessage . $styleEditErrorMessage;
$scss .= getFileContent(DIR_FS_CATALOG . 'cache/' . CACHE_FILENAME);
$errorOccurred = true;
}
// Compile default css in error case.
if ($errorOccurred) {
ob_start();
try {
$compiler = ScssCompilerFactory::create()->createCompiler();
$compiler->setVariables([
'theme-base-path' => '"' . DIR_WS_CATALOG . DIR_PUBLISHED_THEME_PATH . '/"'
]);
$compiler->addImportPath($basePath);
$compiler->setBasePath(DIR_FS_CATALOG . $basePath);
if (count($additionalScssPaths) > 0) {
foreach ($additionalScssPaths as $additionalScssPath) {
$compiler->addImportPath($additionalScssPath);
}
}
if ($suffix === '.min') {
$compiler->setFormatter(ScssCompilerInterface::STYLE_COMPRESSED);
} else {
$compiler->setFormatter(ScssCompilerInterface::STYLE_EXPANDED);
}
$compiler->setAdditionalScssFiles($additionalScssFiles);
// delete custom scss forcing to compile default css to ensure a working frontend
@file_put_contents($customDirectoryPath . '_bootstrap_variables.scss', '');
@file_put_contents($customDirectoryPath . '_template_variables.scss', '');
@file_put_contents($customDirectoryPath . '_custom_styles.scss', '');
$compiler->serve($fileToServe);
$scss = ob_get_clean();
$scss = $errorMessage . "\n" . $styleEditErrorMessage . "\n" . $scss;
} catch (Exception $e) {
ob_clean();
}
}
$scss = str_replace('\"', '"', $scss);
$css .= $scss;
if (!$errorOccurred && !$application->errorOccurred()) {
if ($suffix === '.min') {
$css = preg_replace('!/\*.*?\*/!s', '', $css);
}
file_put_contents($cacheFilePath, $css);
}
header('HTTP/1.1 200 OK');
header('Last-Modified: ' . gmdate('r'), true);
header('ETag: ', true);
header('Cache-Control: no-cache, must-revalidate', true);
$additionalCss = getAdditionalCss($additionalCssFiles, $suffix);
$destinationDirectoryPath = DIR_FS_PUBLISHED_THEME_PATH . '/styles/system';
if ($styleName === null && is_writable($destinationDirectoryPath)) {
$mainCssFilePath = $destinationDirectoryPath . '/main' . $suffix . '.css';
if (file_exists($mainCssFilePath)) {
unlink($mainCssFilePath);
}
file_put_contents($mainCssFilePath, $css . PHP_EOL . $additionalCss);
$fileFlag = DIR_FS_CATALOG . 'cache/update_shop_offline_page_css.flag';
if (!file_exists($fileFlag)) {
touch($fileFlag);
}
}
} catch (RoutineLockedByAnotherInstanceException $e) {
//wait at most 20 seconds here to give a change for the other process to finish
$locker->waitUntilLockIsReleasedOrTimeout(20);
$destinationDirectoryPath = DIR_FS_PUBLISHED_THEME_PATH . '/styles/system';
$mainCssFilePath = $destinationDirectoryPath . '/main' . $suffix . '.css';
$css = file_get_contents($mainCssFilePath);
} catch (RoutineLockerException $e) {
throw $e;
}
finally {
$locker->releaseLock();
}
echo $css . PHP_EOL . ($additionalCss ?? '');
}
/**
* @param $array
* @param $filePath
*/
function appendExistingFile(&$array, $filePath)
{
if (file_exists($filePath)) {
$array[] = $filePath;
}
}
function getFileContent($filename)
{
if (file_exists($filename)) {
return file_get_contents($filename);
}
return '';
}
function minifyCss($css, array $filters, array $plugins)
{
$cssMinifier = new CssMinifier($css, $filters, $plugins);
return $cssMinifier->getMinified();
}
function getAdditionalCss(array $additionalCssFiles, string $suffix) {
ob_start();
foreach ($additionalCssFiles as $additionalCssFile) {
include $additionalCssFile;
// Add comment to close unclosed comment in included file.
echo "\n/**/\n";
}
$additionalCss = ob_get_clean();
if ($suffix === '.min') {
$filters = [
'ImportImports' => false,
'RemoveComments' => true,
'RemoveEmptyRulesets' => true,
'RemoveEmptyAtBlocks' => true,
'ConvertLevel3AtKeyframes' => false,
'ConvertLevel3Properties' => false,
'Variables' => true,
'RemoveLastDelarationSemiColon' => true
];
$plugins = [
'Variables' => true,
'ConvertFontWeight' => true,
'ConvertHslColors' => true,
'ConvertRgbColors' => true,
'ConvertNamedColors' => true,
'CompressColorValues' => true,
'CompressUnitValues' => true,
'CompressExpressionValues' => true
];
$additionalCss = minifyCss($additionalCss, $filters, $plugins);
}
return $additionalCss ?: '';
}
Unexpected error occurred...
Class "main_ORIGIN" not found