2010-08-19 7 views
6

J'utilise DOMDocument pour manipuler/modifier le code HTML avant qu'il ne soit édité sur la page. Ceci est seulement un fragment html, pas une page complète. Mon problème initial était que tout le personnage français était foiré, ce que je pouvais corriger après quelques essais et erreurs. Maintenant, il semble qu'un seul problème demeure: «le personnage se transforme en? .Problèmes d'encodage de DOMDocument/caractères transformés

Le code:

<?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()))); 
?> 

Je sais que ça se salit avec le Décode/encode UTF8, mais c'est la seule façon que je pouvais le faire fonctionner jusqu'à présent. Voici une chaîne exemple:

Entrée: Sans Doute Parcé Qu'il Vient d'Atteindre juin Date Determinante sortie Dans fils du cheminement

:? Sans Doute parce qu il Vient d date de juin de Atteindre d & EACUTE ; terminante dans son spectaculaire cheminement

Si je trouve plus de détails, je les ajouterai. Merci pour votre temps et votre soutien!

+1

Quel jeu de caractères est '$ row-> text'?Si c'est UTF-8 directement (En supposant que cela provienne de MySQL, vous devez définir le jeu de caractères de connexion sur UTF8) alors vous n'avez pas besoin des fonctions 'utf8_ (en | de) code'. Forcer le jeu de caractères à UTF8 et tous vos problèmes * devraient * disparaître (en supposant que c'est de là que '$ row' vient) ... – ircmaxell

+0

L'entrée provient d'un CMS, tous mis à utf8 (chaîne de caractères, base de données, etc.)). Mais il semble que mon problème n'est pas ce que je pense que c'était. J'ai découvert que la chaîne qui vient de moi est tout OK, et le pc de mes collègues aussi. Le problème se produit uniquement lorsque la chaîne est entrée par le PC de mon client. Je parierais qu'elle colle le texte d'un mot ou d'un autre et que quelque chose d'étrange se passe alors. Je vais devoir creuser ça. – Kyrotomia

+1

Ahhh ... Alors peut-être vérifier les caractères UCS-2LE (UTF-16LE) (Depuis c'est le défaut pour Word IIRC) ... – ircmaxell

Répondre

16

N'utilisez pas utf8_decode. Si votre texte est en UTF-8, transmettez-le comme tel.

Malheureusement, DOMDocument est par défaut LATIN1 en cas de code HTML. Il semble que le comportement est ce

  • Si aller chercher un document à distance, il faut en déduire l'encodage des en-têtes
  • Si l'en-tête n'a pas été envoyé ou le fichier est local, recherchez le correspondant méta-equiv
  • Sinon, par défaut à LATIN1.

Exemple de fonctionner:

<?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; 

Et avec XML (par défaut est 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 je me souviens bien, je pense que je faisais le correctif hacky suivant pour s'assurer que le html a été mis à utf8, '$ d-> loadHTML (''. $ html);' étant que cela semblait toujours si bien récupérer lors de l'analyse html invalide de toute façon – goat

+0

@chris J'avais l'habitude de faire ça aussi, jusqu'à ce qu'il se soit cassé récemment. La réponse est correcte, l'étiquette est nécessaire pour que cela fonctionne bien; voir aussi: https://bugs.php.net/bug.php?id=32547 –

+0

OUI, MERCI! C'est la solution: NE PAS convertir votre HTML UTF8 original, seulement ajouter le tag META. PS: et peut être plus simple, j'ai testé sans balise racine HTML, seulement les balises P et en commençant par ce META. –

7

loadHtml() ne reconnaît pas toujours l'encodage correct comme spécifié dans le contenu -type HTTP-EQUIV meta tag.

Si les DomDocument('1.0', 'UTF-8') et loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . $html) hacks ne fonctionnent pas comme ils le faisaient pas pour moi (PHP 5.3.13), essayez ceci:

Ajouter une autre section <head> immédiatement après la balise d'ouverture <html> avec le bon Content- tapez la balise meta HTTP-EQUIV. Ensuite, appelez le loadHtml(), puis supprimez l'étiquette <head> supplémentaire.

// 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> 

Voir cet article: http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/

4

Cela me suffit était pour, les autres réponses ici étaient trop puissantes. Étant donné que j'ai un document HTML avec un tag HEAD existant. Les balises HEAD n'ont pas d'attributs et je n'ai eu aucun problème à laisser la balise META supplémentaire dans le HTML pour mon cas d'utilisation.

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