* @copyright Copyright (c) 2022 Samuel Marshall / JCH Optimize * @license GNU/GPLv3, or later. See LICENSE file * * If LICENSE file missing, see . */ namespace JchOptimize\Core; // No direct access use _JchOptimizeVendor\V91\Joomla\DI\ContainerAwareInterface; use _JchOptimizeVendor\V91\Joomla\DI\ContainerAwareTrait; use _JchOptimizeVendor\V91\Psr\Log\LoggerAwareInterface; use _JchOptimizeVendor\V91\Psr\Log\LoggerAwareTrait; use CodeAlfa\Minify\Html; use JchOptimize\Core\Debug\JchProfiler; use JchOptimize\Core\Debug\JchProfilerInterface; use JchOptimize\Core\Exception\ExceptionInterface; use JchOptimize\Core\Html\CacheManager; use JchOptimize\Core\Html\HtmlManager; use JchOptimize\Core\Html\HtmlProcessor; use JchOptimize\Core\Platform\ProfilerInterface; use JchOptimize\Core\Platform\UtilityInterface; use JchOptimize\Core\Preloads\Http2Preload; use function defined; use function ini_get; use function ini_set; use function json_encode; use function version_compare; use const JSON_PRETTY_PRINT; use const JSON_UNESCAPED_SLASHES; defined('_JCH_EXEC') or die('Restricted access'); /** * Main plugin file * */ class Optimize implements LoggerAwareInterface, ContainerAwareInterface { use LoggerAwareTrait; use ContainerAwareTrait; private string $jit; /** * @throws Exception\RuntimeException */ public function __construct( private Registry $params, private HtmlProcessor $htmlProcessor, private CacheManager $cacheManager, private HtmlManager $htmlManager, private Http2Preload $http2Preload, private ProfilerInterface $jProfiler, private UtilityInterface $utility ) { $this->jit = ini_get('pcre.jit'); self::setPcreLimits(); if (version_compare(PHP_VERSION, '8.0', '<')) { throw new Exception\RuntimeException('PHP Version less than 8.0, Exiting plugin...'); } } public static function setPcreLimits(): void { ini_set('pcre.backtrack_limit', '1000000'); ini_set('pcre.recursion_limit', '1000000'); ini_set('pcre.jit', '0'); } public function process(string $html): string { !JCH_DEBUG ?: $this->jProfiler->start('Process', true); try { $this->htmlProcessor->setHtml($html); $this->htmlManager->preProcessHtml(); $this->htmlProcessor->processCombineJsCss(); $this->htmlProcessor->processImageAttributes(); $this->cacheManager->handleCombineJsCss(); $this->cacheManager->handleImgAttributes(); $this->htmlProcessor->processCdn(); $this->htmlProcessor->processLazyLoad(); $this->htmlManager->postProcessHtml(); $optimizedHtml = $this->minifyHtml($this->htmlProcessor->getHtml()); !JCH_DEBUG ?: $this->jProfiler->stop('Process', true); !JCH_DEBUG ?: $this->jProfiler->attachProfiler($optimizedHtml, $this->htmlProcessor->isAmpPage); } catch (ExceptionInterface $e) { $this->logger->error((string)$e); $optimizedHtml = $html; } $profiler = $this->getContainer()->get(JchProfilerInterface::class); if ($profiler instanceof JchProfiler) { $stats = $profiler->snapshot(); if ($stats) { $this->logger?->debug( json_encode($stats, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) ); } } ini_set('pcre.jit', (string)$this->jit); return $optimizedHtml; } /** * If parameter is set will minify HTML before sending to browser; * Inline CSS and JS will also be minified if respective parameters are set * * @param string $html * * @return string Optimized HTML */ public function minifyHtml(string $html): string { !JCH_DEBUG ?: $this->jProfiler->start('MinifyHtml'); if ( $this->params->get('combine_files_enable', '1') && $this->params->get('html_minify', 0) ) { $options = []; if ($this->params->get('css_minify', 0)) { $options['cssMinifier'] = array('CodeAlfa\Minify\Css', 'optimize'); } if ($this->params->get('js_minify', 0)) { $options['jsMinifier'] = array('CodeAlfa\Minify\Js', 'optimize'); } $options['jsonMinifier'] = array('CodeAlfa\Minify\Json', 'optimize'); $options['minifyLevel'] = $this->params->get('html_minify_level', 0); $options['isXhtml'] = Helper::isXhtml($html); $options['isHtml5'] = Helper::isHtml5($html); $htmlMin = Html::optimize($html, $options); if ($htmlMin == '') { $this->logger->error('Error while minifying HTML'); $htmlMin = $html; } $html = $htmlMin; } !JCH_DEBUG ?: $this->jProfiler->stop('MinifyHtml', true); return $html; } }