Skip to content

Instantly share code, notes, and snippets.

@Ibochkarev
Last active July 13, 2026 11:39
Show Gist options
  • Select an option

  • Save Ibochkarev/d21bb00d57df7b241afad899486f2909 to your computer and use it in GitHub Desktop.

Select an option

Save Ibochkarev/d21bb00d57df7b241afad899486f2909 to your computer and use it in GitHub Desktop.
<?php
defined('MODX_CORE_PATH') || exit;
/**
* Pull script/style/noscript/textarea out before DOMDocument so markup inside
* JS/CSS strings is not rewritten (can inject literal </script> and break pages).
*
* @return array{0: string, 1: array<string, string>}
*/
function imageoptimizer_extract_raw_blocks(string $html): array
{
$blocks = [];
$replaced = preg_replace_callback(
'#<(script|style|noscript|textarea)\b[^>]*>.*?</\1>#is',
static function (array $match) use (&$blocks): string {
$token = '<!--IMAGEOPTIMIZER_RAW_' . count($blocks) . '-->';
$blocks[$token] = $match[0];
return $token;
},
$html
);
return [$replaced ?? $html, $blocks];
}
/**
* @param array<string, string> $blocks
*/
function imageoptimizer_restore_raw_blocks(string $html, array $blocks): string
{
if ($blocks === []) {
return $html;
}
return str_replace(array_keys($blocks), array_values($blocks), $html);
}
/**
* Full page document (has doctype or html root) vs HTML fragment.
*/
function imageoptimizer_is_full_html_document(string $html): bool
{
$sample = ltrim(substr($html, 0, 2048));
if ($sample === '') {
return false;
}
return (bool) preg_match('/^(?:<!DOCTYPE\b|<html\b)/i', $sample);
}
function imageoptimizer_load_html_document(string $html): ?DOMDocument
{
$doc = new DOMDocument();
$flags = LIBXML_NOERROR | LIBXML_NOWARNING;
if (defined('LIBXML_HTML_NODEFDTD')) {
$flags |= LIBXML_HTML_NODEFDTD;
}
if (imageoptimizer_is_full_html_document($html)) {
// Keep <html>/<head>/<body>; do not wrap in #imageoptimizer-root.
$payload = '<?xml encoding="UTF-8">' . $html;
if (!$doc->loadHTML($payload, $flags)) {
return null;
}
return $doc;
}
if (defined('LIBXML_HTML_NOIMPLIED')) {
$flags |= LIBXML_HTML_NOIMPLIED;
}
$wrapped = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><div id="imageoptimizer-root">'
. $html . '</div></body></html>';
if (!$doc->loadHTML($wrapped, $flags)) {
return null;
}
return $doc;
}
/**
* @return DOMElement[]
*/
function imageoptimizer_extract_img_nodes(DOMDocument $doc): array
{
$images = [];
$nodes = $doc->getElementsByTagName('img');
foreach ($nodes as $node) {
if ($node instanceof DOMElement) {
$images[] = $node;
}
}
return $images;
}
function imageoptimizer_serialize_document(DOMDocument $doc): string
{
$root = $doc->getElementById('imageoptimizer-root');
if ($root) {
$html = '';
foreach ($root->childNodes as $child) {
$html .= $doc->saveHTML($child);
}
return imageoptimizer_normalize_html_output($html);
}
$html = (string) $doc->saveHTML();
// loadHTML UTF-8 hint may serialize as PI or as HTML comment after doctype.
$html = preg_replace('/<\?xml[^?]*\?>\s*/i', '', $html) ?? $html;
$html = preg_replace('/<!--\?xml[^>]*-->\s*/i', '', $html) ?? $html;
return imageoptimizer_normalize_html_output($html);
}
function imageoptimizer_normalize_html_output(string $html): string
{
$voidTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
foreach ($voidTags as $tag) {
$html = preg_replace('#(<' . $tag . '\b[^>]*>)\s*</' . $tag . '>#i', '$1', $html) ?? $html;
}
$html = preg_replace('#</source>\s*</picture>#i', '</picture>', $html) ?? $html;
return $html;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment