Files
ltsecurityinc/app/code/Plumrocket/GlobalPrivacyControl/Block/ComponentInit.php
T

164 lines
5.1 KiB
PHP

<?php
/**
* @package Plumrocket_GlobalPrivacyControl
* @copyright Copyright (c) 2025 Plumrocket Inc.
* @license https://plumrocket.com/license End-user License Agreement
*/
declare(strict_types=1);
namespace Plumrocket\GlobalPrivacyControl\Block;
use Magento\Framework\Code\Minifier\Adapter\Js\JShrink;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Magento\Framework\View\Helper\SecureHtmlRenderer;
use Plumrocket\GlobalPrivacyControl\Helper\Config;
use Plumrocket\GlobalPrivacyControl\ViewModel\Geotargeting as GeotargetingViewModel;
class ComponentInit extends Template
{
public const SCRIPT_TAG_REPLACEMENT = 'pr-global-privacy-control-head-script';
/**
* @var \Magento\Framework\Code\Minifier\Adapter\Js\JShrink
*/
private $jsMinifier;
/**
* @var \Magento\Framework\Serialize\SerializerInterface
*/
private $serializer;
/**
* @var \Plumrocket\GlobalPrivacyControl\Helper\Config
*/
private $config;
/**
* @var \Plumrocket\GlobalPrivacyControl\ViewModel\Geotargeting
*/
private $geotargetingViewModel;
/**
* @var \Magento\Framework\View\Helper\SecureHtmlRenderer|mixed|null
*/
private $secureHtmlRenderer;
/**
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Framework\Code\Minifier\Adapter\Js\JShrink $jsMinifier
* @param \Magento\Framework\Serialize\SerializerInterface $serializer
* @param \Magento\Framework\ObjectManagerInterface $objectManager
* @param \Plumrocket\GlobalPrivacyControl\Helper\Config $config
* @param \Plumrocket\GlobalPrivacyControl\ViewModel\Geotargeting $geotargetingViewModel
* @param array $data
*/
public function __construct(
Context $context,
JShrink $jsMinifier,
SerializerInterface $serializer,
ObjectManagerInterface $objectManager,
Config $config,
GeotargetingViewModel $geotargetingViewModel,
array $data = []
) {
parent::__construct($context, $data);
$this->jsMinifier = $jsMinifier;
$this->serializer = $serializer;
$this->config = $config;
$this->geotargetingViewModel = $geotargetingViewModel;
/**
* @TODO Refactor when leave support of Magento 2.3.7 and less
*/
$this->secureHtmlRenderer = class_exists(SecureHtmlRenderer::class)
? $objectManager->get(SecureHtmlRenderer::class)
: null;
}
/**
* @return array
*/
public function getConfig(): array
{
return [
'canProcessSignal' => $this->config->isModuleEnabled(),
'isGeotargetingEnabled' => $this->geotargetingViewModel->isEnabled(),
'geotargetingApiEndpoint' => $this->geotargetingViewModel->getApplicabilityUrl()
];
}
/**
* @return string
*/
public function getSerializedConfig(): string
{
return $this->serializer->serialize($this->getConfig());
}
/**
* @return array|string|string[]
*/
protected function _toHtml()
{
$html = parent::_toHtml();
preg_match_all('/<script[\s\S]*?\/script>/', $html, $scriptTags);
$scriptTags = array_shift($scriptTags);
foreach ($scriptTags as $scriptTag) {
try {
$modifiedScriptTag = $this->modifyScriptTag($scriptTag);
} catch (\Exception $e) {
continue;
}
$html = str_replace($scriptTag, $modifiedScriptTag, $html);
}
return $html;
}
/**
* Modify script tag to prevent from being moved to footer
*
* @param string $scriptTag
* @return string
* @throws \Exception
*/
private function modifyScriptTag(string $scriptTag): string
{
/**
* @TODO Refactor when leave support of Magento 2.3.7 and less
*/
if (! $this->secureHtmlRenderer) {
preg_match('#<script[\s\S]*?>([^`]*?)<\/script>#', $scriptTag, $matches);
if(isset($matches[1])) {
$originalTagContent = $matches[1];
$minifiedContent = $this->jsMinifier->minify($originalTagContent);
$scriptTag = str_replace($originalTagContent, $minifiedContent, $scriptTag);
}
return str_replace(
['<script', '/script>'],
['<' . self::SCRIPT_TAG_REPLACEMENT, '/'.self::SCRIPT_TAG_REPLACEMENT.'>'],
$scriptTag
);
}
$doc = new \DOMDocument();
$doc->loadHTML($scriptTag);
$scriptNode = $doc->getElementsByTagName('script')->item(0);
$tagAttributes = array_column(iterator_to_array($scriptNode->attributes), 'nodeValue', 'name');
$tagContent = $this->jsMinifier->minify($scriptNode->textContent);
return $this->secureHtmlRenderer->renderTag(self::SCRIPT_TAG_REPLACEMENT, $tagAttributes, $tagContent, false);
}
}