Intereting Posts
документ openoffice (odt) для PDF с линией commad на Linux? Получить следующую / предыдущую ISO-неделю и год в PHP Параметр обратного вызова Luracast Restler для междоменного AJAX Laravel 4 кроме фильтра в конструкторе контроллера Запустить php-скрипт как процесс демона Получите URL-адрес реферера – посетители, прибывающие из Paypal (HTTPS) Знак PHP – Plus с запросом GET Компонент автономной формы Symfony2 – настройка формы Проверьте, существует ли таблица базы данных с использованием PHP / PDO Запросить определенное значение с помощью сводной таблицы mySQL Сервер Apache 2 на ubuntu не может разобрать php-код внутри html-файла Файл-получить-содержимое не удалось открыть поток Неавторизованный Мне нужно некоторое руководство по платежным шлюзам Могу ли я использовать промежуточное программное обеспечение Laravel 5, чтобы позволить пакетам перекрывать маршруты приложений? Pagination продолжает показывать ту же часть данных SQL

Проблема с PHP DOM UTF-8

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

Проблема в том, что я использую PHP DOM для анализа HTML-кода, хранящегося в базе данных (HTML – это выход из редактора WYSIWYG и недействителен, он не имеет html, head, body tags и т. Д.).

HTML может выглядеть примерно так, например:

<p>Hello</p> 

Вот метод, который я использую для анализа определенного HTML из базы данных:

  private function ParseSlideContent($slideContent) { var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters $doc = new DOMDocument('1.0', 'UTF-8'); // hack to preserve UTF-8 characters $html = iconv('Windows-1250', 'UTF-8', $slideContent); $doc->loadHTML('<?xml encoding="UTF-8">' . $html); $doc->preserveWhiteSpace = false; foreach($doc->getElementsByTagName('img') as $t) { $path = trim($t->getAttribute('src')); $t->setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path)); } foreach ($doc->getElementsByTagName('object') as $o) { foreach ($o->getElementsByTagName('param') as $p) { $path = trim($p->getAttribute('value')); $p->setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path)); } } foreach ($doc->getElementsByTagName('embed') as $e) { if (true === $e->hasAttribute('pluginspage')) { $path = trim($e->getAttribute('src')); $e->setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path)); } else { $path = end(explode('data/media/video/', trim($e->getAttribute('src')))); $path = 'data/media/video/' . $path; $path = '/clientarea/utils/locate-video?path=' . urlencode($path); $width = $e->getAttribute('width') . 'px'; $height = $e->getAttribute('height') . 'px'; $a = $doc->createElement('a', ''); $a->setAttribute('href', $path); $a->setAttribute('style', "display:block;width:$width;height:$height;"); $a->setAttribute('class', 'player'); $e->parentNode->replaceChild($a, $e); $this->slideContainsVideo = true; } } $html = trim($doc->saveHTML()); $html = explode('<body>', $html); $html = explode('</body>', $html[1]); return $html[0]; } 

Результат вышеописанного метода – это мусор со всеми специальными символами, замененными такими странными вещами, как ÃšÄ .

Еще кое-что. Он работает на моем сервере разработки.

Однако он не работает на производственном сервере.

Какие-либо предложения?

PHP-версия производственного сервера: PHP-версия 5.2.0RC4-dev

PHP-версия сервера разработки: PHP Version 5.2.13


ОБНОВИТЬ:

Я сам работаю над решением. У меня есть вдохновение из этого отчета об ошибке PHP (на самом деле это не ошибка): http://bugs.php.net/bug.php?id=32547

Это мое предложенное решение. Я попробую завтра и сообщит, если это сработает:

  private function ParseSlideContent($slideContent) { var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters $doc = new DOMDocument('1.0', 'UTF-8'); // hack to preserve UTF-8 characters $html = iconv('Windows-1250', 'UTF-8', $slideContent); $doc->loadHTML('<?xml encoding="UTF-8">' . $html); $doc->preserveWhiteSpace = false; // this might work // it basically just adds head and meta tags to the document $html = $doc->getElementsByTagName('html')->item(0); $head = $doc->createElement('head', ''); $meta = $doc->createElement('meta', ''); $meta->setAttribute('http-equiv', 'Content-Type'); $meta->setAttribute('content', 'text/html; charset=utf-8'); $head->appendChild($meta); $body = $doc->getElementsByTagName('body')->item(0); $html->removeChild($body); $html->appendChild($head); $html->appendChild($body); foreach($doc->getElementsByTagName('img') as $t) { $path = trim($t->getAttribute('src')); $t->setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path)); } foreach ($doc->getElementsByTagName('object') as $o) { foreach ($o->getElementsByTagName('param') as $p) { $path = trim($p->getAttribute('value')); $p->setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path)); } } foreach ($doc->getElementsByTagName('embed') as $e) { if (true === $e->hasAttribute('pluginspage')) { $path = trim($e->getAttribute('src')); $e->setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path)); } else { $path = end(explode('data/media/video/', trim($e->getAttribute('src')))); $path = 'data/media/video/' . $path; $path = '/clientarea/utils/locate-video?path=' . urlencode($path); $width = $e->getAttribute('width') . 'px'; $height = $e->getAttribute('height') . 'px'; $a = $doc->createElement('a', ''); $a->setAttribute('href', $path); $a->setAttribute('style', "display:block;width:$width;height:$height;"); $a->setAttribute('class', 'player'); $e->parentNode->replaceChild($a, $e); $this->slideContainsVideo = true; } } $html = trim($doc->saveHTML()); $html = explode('<body>', $html); $html = explode('</body>', $html[1]); return $html[0]; } 

Ваш «взлом» не имеет смысла.

Вы конвертируете HTML-файл Windows-1250 в UTF-8, а затем добавляете <?xml encoding="UTF-8"> . Это не сработает. Расширение DOM для файлов HTML:

  • Принимает кодировку, указанную в мета-http-equiv для «content-type».
  • В противном случае предполагается, что ISO-8859-1

Я предлагаю вам вместо этого конвертировать из Windows-1250 в ISO-8859-1 и ничего не добавлять.

EDIT . Предложение не очень хорошо, потому что Windows-1250 имеет символы, не входящие в ISO-8859-1. Поскольку вы имеете дело с фрагментами без meta элементов для типа контента, вы можете добавить свои собственные для интерпретации как UTF-8:

 <?php //script and output are in UTF-8 /* Simulate HTML fragment in Windows-1250 */ $html = <<<XML <p>ĄĽź ‰ ‡ … á (some exist on win-1250, but not LATIN1 or even win-1252)</p> XML; $htmlInterm = iconv("UTF-8", "Windows-1250", $html); //convert /* Append meta header to force UTF-8 interpretation and convert into UTF-8 */ $htmlInterm = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" . iconv("Windows-1250", "UTF-8", $htmlInterm); /* Omit libxml warnings */ libxml_use_internal_errors(true); /* Build DOM */ $d = new domdocument; $d->loadHTML($htmlInterm); var_dump($d->getElementsByTagName("body")->item(0)->textContent); //correct UTF-8 

дает:

 string (79) "ĄĽź ‰ ‡ ... á (некоторые существуют на win-1250, но не LATIN1 или даже win-1252)"

Два решения.

Вы можете установить кодировку как заголовок:

 <?php header("Content-Type", "text/html; charset=utf-8"); ?> 

Или вы можете установить его как тег META:

 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> 

EDIT: в случае, если оба из них установлены правильно, выполните следующие действия:

  • Создайте небольшую страницу с символом UTF-8.
  • Напишите страницу тем же способом, который у вас уже есть.
  • Используйте Fiddler или Wireshark для проверки необработанных байтов, передаваемых в ваших DEV и PROD-средах. Вы также можете дважды проверить заголовки с помощью Fiddler / Wireshark.

Если вы уверены, что отправлен правильный заголовок, то ваш лучший шанс найти ошибку – начать поиск необработанных байтов. Идентичные байты, отправленные в идентичный браузер, дадут тот же результат, поэтому вам нужно начать искать, почему они не идентичны. Fiddler / Wireshark поможет в этом.

У меня такая же проблема. Мое исправление использовало notepad ++ и установило кодировку документа php на «UTF-8 без спецификации». Надеюсь, это поможет любому другому.