Особенности работы с HTML в PHP 8.4
В версиях PHP до 8.4 для очистки выборочной очистки HTML использовался класс DOMDocument, который изначально был предназначен для работы с XML. Однако в версии 8.4 его использование приводит к тому, что возвращается пустая строка. Стал искать решение, и выяснилось, что с этой версии именно для HTML появился новый класс: Dom\HTMLDocument, а для выборки с помощью XPath вместе с ним теперь следует использовать Dom\XPath.
В итоге код для обработки HTML приобретает примерно такой вид:
<?php
function process_html($html) {
if (version_compare(PHP_VERSION,'8.4','>=')) { // для PHP 8.4 и выше
$dom = Dom\HTMLDocument::createFromString($html,LIBXML_HTML_NOIMPLIED);
$xpath = new Dom\XPath($dom);
}
else { // для более старых версий PHP
$html = mb_encode_numericentity($html, [0x80, 0x10FFFF, 0, ~0], $charset);
$dom = new \DOMDocument('1.0',$charset);
$dom->formatOutput = false;
$dom->loadHTML($html, LIBXML_NONET|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD); // LIBXML_NONET — for protection against XXE, LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD — to don't add DOCTYPE and html/body tags
$xpath = new DOMXPath($dom);
}
// TODO: код обработки
$result=$dom->saveHTML(); // возвращаем результат
if (version_compare(PHP_VERSION,'8.4','<')) $result = \mb_decode_numericentity($result,[0x80, 0x10FFFF, 0, ~0], $charset);
return $result;
}
Ещё одно существенное отличие: Dom\XPath возвращает имена тегов в заглавном регистре, тогда как DOMXPath — в том регистре, в котором теги написаны в HTML-коде, что также может влиять на обработку.
Ещё одна особенность выявилась: для Dom\XPath не работает поиск по имени тега, если импорт документа делать без опции Dom\HTML_NO_DEFAULT_NS.
Т.е. нужно примерно так:
<?php
$dom = Dom\HTMLDocument::createFromString($html,Dom\HTML_NO_DEFAULT_NS);
$xpath = new Dom\XPath($dom);
$og_title = $xpath->query('//meta[@property="og:title"]');