Вебсервер обслуживает ответы с помощью кодировки utf-8, все файлы сохраняются с помощью кодировки utf-8, и все, что мне известно об установке, было установлено на кодировку utf-8.
Вот быстрая программа, чтобы проверить, работает ли выход:
<?php $html = <<<HTML <!doctype html> <html> <head> <meta charset="utf-8"> <title>Test!</title> </head> <body> <h1>☆ Hello ☆ World ☆</h1> </body> </html> HTML; $dom = new DomDocument("1.0", "utf-8"); $dom->loadHTML($html); header("Content-Type: text/html; charset=utf-8"); echo($dom->saveHTML());
Выходной сигнал программы:
<!DOCTYPE html> <html><head><meta charset="utf-8"><title>Test!</title></head><body> <h1>â Hello â World â</h1> </body></html>
Который отображает как:
Что я могу делать неправильно? Насколько более конкретным я должен сказать, чтобы DomDocument правильно обрабатывал utf-8?
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
с кодировкой, с loadHTML
может работать 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">
который представляет собой Content-Type, определяющий кодировку. Это также лучшая практика для строк 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>
У вас есть более быстрое исправление, после загрузки вашего html-документа в DOMDocument вы просто устанавливаете (или лучше упомянутый сброс) исходную кодировку. Вот пример кода:
$dom = new DOMDocument(); $dom->loadHTML('<?xml encoding="UTF-8">' . $html); foreach ($dom->childNodes as $item) if ($item->nodeType == XML_PI_NODE) $dom->removeChild($item); $dom->encoding = 'UTF-8'; // reset original encoding
<?php header("Content-type: text/html; charset=utf-8"); $html = <<<HTML <!doctype html> <html> <head> <meta charset="utf-8"> <title>Test!</title> </head> <body> <h1>☆ Hello ☆ World ☆</h1> </body> </html> HTML; $html = mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8"); $dom = new DomDocument("1.0", "utf-8"); $dom->loadHTML($html); header("Content-Type: text/html; charset=utf-8"); echo($dom->saveHTML());
Вывод:
<!DOCTYPE html> <html><head><meta charset="utf-8"><title>Test!</title></head><body> <h1>☆ Hello ☆ World ☆</h1> </body></html>