Ответ 1
DOMDocument::loadHTML()
ожидает строку HTML.
HTML использует кодировку ISO-8859-1
(ISO Latin Alphabet № 1) по умолчанию для нее. Это происходит дольше, см. 6.1. Набор символов HTML-документа. На самом деле это больше поддержка по умолчанию для Windows-1252
в общих веб-браузерах.
Я возвращаюсь так далеко, потому что PHP DOMDocument основан на libxml и приносит HTMLparser, который предназначен для HTML 4.0.
Я бы сказал, что можно с уверенностью предположить, что вы можете загрузить закодированную строку ISO-8859-1
.
Ваша строка UTF-8
закодирована. Поверните все символы выше 127/h7F в HTML-объекты, и все в порядке. Если вы не хотите делать это самостоятельно, это то, что mb_convert_encoding
с целевой кодировкой HTML-ENTITIES
:
- Те символы, у которых есть именованные объекты, получат именованное имя.
€ -> €
- Другие получают свой цифровой (десятичный) объект, например.
☆ -> ☆
Ниже приведен пример кода, который делает прогресс более заметным с помощью функции обратного вызова:
$html = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function($match) {
list($utf8) = $match;
$entity = mb_convert_encoding($utf8, 'HTML-ENTITIES', 'UTF-8');
printf("%s -> %s\n", $utf8, $entity);
return $entity;
}, $html);
Эти примерные выходы для вашей строки:
☆ -> ☆
☆ -> ☆
☆ -> ☆
В любом случае, это просто для того, чтобы глубже заглянуть в вашу строку. Вы хотите, чтобы он конвертировался в кодировку loadHTML
. Это можно сделать, преобразовывая все из US-ASCII
в HTML-объекты:
$us_ascii = mb_convert_encoding($utf_8, 'HTML-ENTITIES', 'UTF-8');
Позаботьтесь, чтобы ваш вход был закодирован в кодировке UTF-8. Если у вас даже смешанные кодировки (что может случиться с некоторыми входами), mb_convert_encoding
может обрабатывать только одну кодировку для каждой строки. Я уже изложил выше, как более конкретно выполнять замену строк с помощью регулярных выражений, поэтому теперь я оставляю более подробную информацию.
Другая альтернатива - это намек на кодировку. Это можно сделать в вашем случае, изменив документ и добавив
<meta http-equiv="content-type" content="text/html; charset=utf-8">
который является типом содержимого, определяющим кодировку. Это также наилучшая практика для строк HTML, которые недоступны через веб-сервер (например, сохранены на диске или внутри строки, как в вашем примере). Обычно веб-сервер устанавливает это как заголовок ответа.
Если вам не нравятся неулокальные предупреждения, вы можете просто добавить их перед строкой:
$dom = new DomDocument();
$dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$html);
В спецификациях HTML 2.0 элементы, которые могут отображаться только в разделе <head>
документа, будут автоматически размещены там. Вот что здесь происходит и здесь. Выход (довольно-печатный):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Test!</title>
</head>
<body>
<h1>☆ Hello ☆ World ☆</h1>
</body>
</html>