2010-08-19 27 views
6

Estoy usando DOMDocument para manipular/modificar HTML antes de que salga a la página. Esto es solo un fragmento html, no una página completa. Mi problema inicial fue que todo el personaje francés se echó a perder, lo que pude corregir después de un poco de prueba y error. Ahora, parece que solo queda un problema: '¿el personaje se transforma en? .Problemas/caracteres de codificación DOMDocument transformados

El código:

<?php 
    $dom = new DOMDocument('1.0','utf-8'); 
     $dom->loadHTML(utf8_decode($row->text)); 

     //Some pretty basic modification here, not even related to text 

     //reinsert HTML, and make sure to remove DOCTYPE, html and body that get added auto. 
     $row->text = utf8_encode(preg_replace('/^<!DOCTYPE.+?>/', '', str_replace(array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $dom->saveHTML()))); 
?> 

Sé que ensuciarse con el UTF-8 decodificar/codificar, pero esta es la única manera de hacer que funcione hasta el momento. Aquí es una cadena de ejemplo:

de entrada: Sans doute parce qu'il vient d'une atteindre fecha determinante dans son spectaculaire cheminement

Salida:?? Sans doute parce qu il vient d fecha atteindre une d & eacute ; terminante dans son spectaculaire cheminement

Si encuentro más detalles, los agregaré. ¡Gracias por tu tiempo y apoyo!

+1

¿Qué conjunto de caracteres es '$ row-> text'?Si se trata de UTF-8 directamente (suponiendo que provenga de MySQL, necesitarás configurar el juego de caracteres de conexión en UTF8), entonces no necesitas las funciones 'utf8_ (en | de) code'. Fuerce el juego de caracteres a UTF8 y todos sus problemas * deben * desaparecer (suponiendo que de ahí viene '$ row') ... – ircmaxell

+0

La entrada proviene de un CMS, todo configurado en utf8 (cadena, base de datos, etc.) Pero parece que mi problema no es lo que creo que era. Descubrí que la cadena que venía de mí está bien, y también la de mis compañeros de trabajo. El problema solo ocurre cuando la PC de mi cliente ingresa la cadena. Apuesto a que está pegando el texto de la palabra o lo que sea, y algunas cosas raras están sucediendo entonces. Tendré que excavar en esto. – Kyrotomia

+1

Ahhh ... Entonces quizás verifique si hay caracteres UCS-2LE (UTF-16LE) (dado que es el valor predeterminado para Word IIRC) ... – ircmaxell

Respuesta

16

No utilice utf8_decode. Si su texto está en UTF-8, páselo como tal.

Desafortunadamente, DOMDocument usa por defecto LATIN1 en caso de HTML. Al parecer, el comportamiento es esta

  • Si ir a buscar un documento remoto, se debe deducir la codificación de las cabeceras
  • Si la cabecera no se ha enviado o el archivo es local, buscar la corresponsal de meta-equiv
  • De lo contrario, por defecto a LATIN1.

Ejemplo de ello trabajar:

<?php 
$s = <<<HTML 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
</head> 
<body> 
Sans doute parce qu’il vient d’atteindre une date déterminante 
dans son spectaculaire cheminement 
</body> 
</html> 
HTML; 

libxml_use_internal_errors(true); 
$d = new domdocument; 
$d->loadHTML($s); 

echo $d->textContent; 

Y con XML (por defecto es UTF-8):

<?php 
$s = '<x>Sans doute parce qu’il vient d’atteindre une date déterminante'. 
    'dans son spectaculaire cheminement</x>'; 
libxml_use_internal_errors(true); 
$d = new domdocument; 
$d->loadXML($s); 

echo $d->textContent; 
+5

si mal no recuerdo, creo que solía hacer la siguiente solución pirata para asegurarse de que el html se configuró en utf8, '$ d-> loadHTML (''. $ html);' siendo que siempre parecía recuperarse tan bien al analizar el html no válido de todos modos – goat

+0

@chris Solía ​​hacer eso también, hasta que se rompió recientemente. La respuesta es correcta, la etiqueta es necesaria para que funcione sin problemas; ver también: https://bugs.php.net/bug.php?id=32547 –

+0

¡SÍ, GRACIAS! Esta es la solución: NO convierta su HTML UTF8 original, solo agregue la etiqueta META. PD: y puede ser más simple, probé sin etiqueta raíz HTML, solo etiquetas P y comenzando con este META. –

7

loadHtml() no siempre reconoce la codificación correcta como se especifica en el contenido tipo de metaetiqueta HTTP-EQUIV.

Si los DomDocument('1.0', 'UTF-8') y loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . $html) hacks no funcionan ya que no hicieron por mí (PHP 5.3.13), intente esto:

Añadir otra sección <head> inmediatamente después de la etiqueta de apertura <html> con el Content correcta escriba metaetiqueta HTTP-EQUIV. Luego llame al loadHtml(), luego elimine la etiqueta adicional <head>.

// Ensure entire page is encoded in UTF-8 
$encoding = mb_detect_encoding($body); 
$body = $encoding ? @iconv($encoding, 'UTF-8', $body) : $body; 

// Insert a head and meta tag immediately after the opening <html> to force UTF-8 encoding 
$insertPoint = false; 
if (preg_match("/<html.*?>/is", $body, $matches, PREG_OFFSET_CAPTURE)) { 
    $insertPoint = mb_strlen($matches[0][0]) + $matches[0][1]; 
} 
if ($insertPoint) { 
    $body = mb_substr(
     $body, 
     0, 
     $insertPoint 
    ) . "<head><meta http-equiv='Content-type' content='text/html; charset=UTF-8' /></head>" . mb_substr(
     $body, 
     $insertPoint 
    ); 
} 
$dom = new DOMDocument(); 

// Suppress warnings for loading non-standard html pages 
libxml_use_internal_errors(true); 
$dom->loadHTML($body); 
libxml_use_internal_errors(false); 

// Now remove extra <head> 

Ver este artículo: http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/

4

Esto fue suficiente para mí, las otras respuestas aquí eran una exageración. Dado que tengo un documento HTML con una etiqueta HEAD existente. Las etiquetas HEAD no tienen atributos y no tuve problemas al dejar la etiqueta META adicional en el HTML para mi caso de uso.

$data = str_ireplace('<head>', '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', $data); 
$document = new DOMDocument(); 
$document->loadHTML($data);