PHP DOMDocument loadHTML неправильно кодирует UTF-8

Я пытаюсь разобрать HTML-код с использованием DOMDocument, но когда я это делаю, я внезапно теряю свою кодировку (по крайней мере, так мне кажется).

$profile = "<div><p>various japanese characters</p></div>"; $dom = new DOMDocument(); $dom->loadHTML($profile); $divs = $dom->getElementsByTagName('div'); foreach ($divs as $div) { echo $dom->saveHTML($div); } 

Результатом этого кода является то, что я получаю кучу символов, которые не являются японцами. Однако, если я это сделаю:

 echo $profile; 

он отображается правильно. Я попробовал saveHTML и saveXML, и ни один из них не отображается правильно. Я использую PHP 5.3.

Что я вижу:

 ã¤ãªãã¤å·ã·ã«ã´ã«ã¦ãã¢ã¤ã«ã©ã³ãç³»ã®å®¶åºã«ã9人åå¼ã®5çªç®ã¨ãã¦çã¾ãããå½¼ãå«ãã¦4人ã俳åªã«ãªã£ããç¶è¦ªã¯æ¨æã®ã»ã¼ã«ã¹ãã³ã§ãæ¯è¦ªã¯éµä¾¿å±ã®å®¢å®¤ä¿ã ã£ããé«æ ¡æ代ã¯ãã£ãã£ã®ã¢ã«ãã¤ãã«å¤ãã¿ãæè²è³éãåããªããã«ããªãã¯ç³»ã®é«æ ¡ã¸é²å¦ã 

Что следует показать:

 イリノイ州シカゴにて、アイルランド系の家庭に、9人兄弟の5番目として生まれる。彼を含めて4人が俳優になった。父親は木材のセールスマンで、母親は郵便局の客室係だった。高校時代はキャディのアルバイトに勤しみ、教育資金を受けながらカトリック系の高校へ進学 

EDIT: я упростил код до пяти строк, чтобы вы могли проверить его самостоятельно.

 $profile = "<div lang=ja><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div>"; $dom = new DOMDocument(); $dom->loadHTML($profile); echo $dom->saveHTML(); echo $profile; 

Вот html, который возвращается:

 <div lang="ja"><p>イリノイ州シカゴã«ã¦ã€ã‚¢ã‚¤ãƒ«ãƒ©ãƒ³ãƒ‰ç³»ã®å®¶åºã«ã€</p></div> <div lang="ja"><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div> 

DOMDocument::loadHTML будет обрабатывать вашу строку как DOMDocument::loadHTML в ISO-8859-1, если вы не сообщите об этом иначе. Это приводит к тому, что строки UTF-8 интерпретируются неправильно. В SmartDOMDocument есть обходное решение, которое должно помочь вам:

 $profile = '<div><p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p></div>'; $dom = new DOMDocument(); $dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8')); echo $dom->saveHTML($dom->getElementsByTagName('div')->item(0)); 

Альтернативой является добавление HTML с объявлением кодировки XML для обработки строки как UTF-8 при условии, что документ еще не содержит один:

 $dom->loadHTML('<?xml encoding="utf-8" ?>' . $profile); 

Проблема заключается в saveHTML() и saveXML() , оба из них не работают корректно в Unix. Они не сохраняют символы UTF-8 правильно, если они используются в Unix, но они работают в Windows.

Обходной путь очень прост:

Если вы попробуете значение по умолчанию, вы получите сообщение об ошибке

 $str = $dom->saveHTML(); // saves incorrectly 

Все, что вам нужно сделать, это сохранить следующее:

 $str = $dom->saveHTML($dom->documentElement); // saves correctly 

Эта строка кода позволит правильно сохранить ваши символы UTF-8 (используйте тот же обходной путь, если вы используете saveXML() ).


Заметка

  1. Английские символы не вызывают никаких проблем при использовании saveHTML() без параметров (поскольку английские символы сохраняются как одиночные байтовые символы в UTF-8)

  2. Проблема возникает, когда у вас многобайтовые символы (например, китайский, русский, арабский, иврит и т. Д.).

Я рекомендую прочитать эту статью: http://coding.smashingmagazine.com/2012/06/06/all-about-unicode-utf8-character-sets/ . Вы поймете, как работает UTF-8 и почему у вас есть эта проблема. Это займет у вас около 30 минут, но это время хорошо проведено.

Убедитесь, что реальный исходный файл сохранен как UTF-8 (возможно, вы даже захотите попробовать не рекомендованные маркеры спецификации с UTF-8, чтобы убедиться).

Также в случае HTML убедитесь, что вы указали правильную кодировку, используя meta :

 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 

Если это CMS (как вы отметили свой вопрос с помощью Joomla), вам может потребоваться настроить соответствующие настройки для кодирования.

Вы можете префикс строки, обеспечивающей кодировку utf-8 , например:

 @$doc->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $profile); 

И вы можете продолжить с кодом, который у вас уже есть, например:

 $doc->saveXML() 

Вы должны подать DOMDocument версию вашего HTML с заголовком, который имеет смысл. Также как HTML5.

 $profile ='<?xml version="1.0" encoding="'.$_encoding.'"?>'. $html; 

возможно, это хорошая идея, чтобы ваш html был как можно более действенным, так что вы не попадаете в проблемы, когда вы начнете запрос … вокруг 🙂 и избегайте htmlentities !!!! Это необходимый ресурс назад и вперед. держите свой код безумным !!!!

Работы находят для меня:

 $dom = new \DOMDocument; $dom->loadHTML(utf8_decode($html)); ... return utf8_encode( $dom->saveHTML()); 

Мне потребовалось некоторое время, чтобы разобраться, но вот мой ответ.

Перед использованием DomDocument я бы использовал file_get_contents для извлечения URL-адресов, а затем обработал их строковыми функциями. Возможно, это не лучший способ, но быстрый. Убедившись, что Дом был таким же быстрым, я сначала попробовал следующее:

 $dom = new DomDocument('1.0', 'UTF-8'); if ($dom->loadHTMLFile($url) == false) { // read the url // error message } else { // process } 

Это не удавалось эффектно сохранить кодировку UTF-8, несмотря на правильные метатеги, настройки php и все остальные средства, предлагаемые здесь и в других местах. Вот что работает:

 $dom = new DomDocument('1.0', 'UTF-8'); $str = file_get_contents($url); if ($dom->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8')) == false) { } 

и т. д. Теперь все в порядке с миром. Надеюсь это поможет.

Проблема заключается в том, что при добавлении параметра в функцию DOMDocument :: saveHTML () вы теряете кодировку. В некоторых случаях вам нужно избегать использования параметра и использовать функцию старой строки, чтобы найти то, что вы ищете.

Я думаю, что предыдущий ответ работает на вас, но поскольку это обходное решение не сработало для меня, я добавляю этот ответ, чтобы помочь ppl, который может быть в моем случае.

Используйте его для правильного результата

 $dom = new DOMDocument(); $dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $profile); echo $dom->saveHTML(); echo $profile; 

Эта операция

 mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'); 

Это плохо, потому что специальные символы, , & gt; может быть в $ profile, и они не будут конвертировать два раза после mb_convert_encoding. Это отверстие для XSS и неправильный HTML.

Попробуйте использовать utf8_encode