web-dev-qa-db-fra.com

PHP - htmlentities () est-il suffisant pour créer des valeurs xml-safe?

Je crée un fichier XML à partir de zéro et j'ai besoin de savoir si htmlentities () convertit chaque caractère qui pourrait potentiellement casser un fichier XML (et éventuellement des données UTF-8)? Les valeurs proviendront d'un flux Twitter/flickr, donc je dois être sûr!

34
John Himmelman

htmlentities() n'est pas un moyen garanti de construire du XML légal.

Utilisez htmlspecialchars() au lieu de htmlentities() si c'est tout ce qui vous inquiète. Si vous avez des incompatibilités de codage entre la représentation de vos données et le codage de votre document XML, htmlentities() peut servir à les contourner/à les couvrir (cela gonflera votre taille XML en le faisant). Je pense qu'il vaut mieux que vos encodages soient cohérents et utilisez simplement htmlspecialchars().

Sachez également que si vous pompez la valeur de retour de htmlspecialchars() à l'intérieur d'attributs XML délimités par des guillemets simples, vous devrez également passer l'indicateur ENT_QUOTES Pour que les guillemets simples dans votre source les chaînes sont également correctement encodées. Je suggère de le faire de toute façon, car cela rend votre code à l'abri des bogues résultant de l'utilisation de guillemets simples pour les attributs XML à l'avenir.

Modifier: Pour clarifier:

htmlentities() convertira un certain nombre de caractères non ANSI (je suppose que c'est ce que vous entendez par données UTF-8) en entités (qui sont représentées avec uniquement des caractères ANSI). Cependant, il ne peut pas le faire pour les caractères qui n'ont pas d'entité correspondante et ne peut donc pas garantir que sa valeur de retour consiste uniquement en caractères ANSI. C'est pourquoi je suggère de ne pas l'utiliser.

Si l'encodage est un problème possible, gérez-le explicitement (par exemple avec iconv() ).

Edit 2 : Amélioration de la réponse en tenant compte du commentaire de Josh Davis ci-dessous.

51
Jon

Dom::createTextNode() échappera automatiquement à votre contenu.

Exemple:

$dom = new DOMDocument;
$element = $dom->createElement('Element');
$element->appendChild(
    $dom->createTextNode('I am text with Ünicödé & HTML €ntities ©'));

$dom->appendChild($element);
echo $dom->saveXml();

Production:

<?xml version="1.0"?>
<Element>I am text with &#xDC;nic&#xF6;d&#xE9; &amp; HTML &#x20AC;ntities &#xA9;</Element>

Lorsque vous définissez l'encodage interne sur utf-8, par exemple.

$dom->encoding = 'utf-8';

vous aurez toujours

<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé &amp; HTML €ntities ©</Element>

Notez que ce qui précède ne revient pas à définir le deuxième argument $value Dans Dom::createElement() . La méthode s'assurera seulement que vos noms d'élément sont valides. Voir les notes sur la page de manuel, par ex.

$dom = new DOMDocument;
$element = $dom->createElement('Element', 'I am text with Ünicödé & HTML €ntities ©');
$dom->appendChild($element);
$dom->encoding = 'utf-8';
echo $dom->saveXml();

entraînera un avertissement

Warning: DOMDocument::createElement(): unterminated entity reference  HTML €ntities ©

et la sortie suivante:

<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé </Element>
20
Gordon

La réponse de Gordon est bonne et explique les problèmes de codage XML, mais ne montre pas une fonction simple (ou ce que fait la boîte noire). La réponse de Jon commence bien par la recommandation de la fonction 'htmlspecialchars', mais lui et d'autres font une erreur, alors je serai catégorique.

Un bon programmeur DOIT avoir un contrôle sur l'utilisation ou non de l'UTF-8 dans vos chaînes et données XML: UTF-8 (ou un autre encodage non ASCII) IS SAFE dans un algorithme cohérent.

SÉCURISÉ UTF-8 XML PAS BESOIN D'ENCODE DE PLEINE ENTITÉ . Le codage aveugle produit "XML de seconde classe, non lisible par l'homme, demande de codage/décodage". Et sûr ASCII XML, pas besoin non plus de codage d'entité, lorsque tout votre contenu est ASCII.

Seuls 3 ou 4 caractères doivent être échappés dans une chaîne de contenu XML: >, <, & et facultatif ". Veuillez lire http://www.w3.org/TR/REC-xml/ "2.4 Données de caractères et balisage" et "4.6 Entités prédéfinies". ALORS VOUS pouvez utiliser ' htmlentities '

Par exemple, la fonction PHP de PHP rendra le XML complètement sûr:

// it is a didactic illustration, USE htmlentities($S,flag)
function xmlsafe($s,$intoQuotes=0) {
if ($intoQuotes)
    return str_replace(array('&','>','<','"'), array('&amp;','&gt;','&lt;','&quot;'), $s);
    // SAME AS htmlspecialchars($s)
else
    return str_replace(array('&','>','<'), array('&amp;','&gt;','&lt;'), $s);
    // SAME AS htmlspecialchars($s,ENT_NOQUOTES)
}

// example of SAFE XML CONSTRUCTION
function xmlTag( $element, $attribs, $contents = NULL) {
$out = '<' . $element;
foreach( $attribs as $name => $val )
   $out .= ' '.$name.'="'. xmlsafe( $val,1 ) .'"';
if ( $contents==='' || is_null($contents) )
    $out .= '/>';
else
    $out .= '>'.xmlsafe( $contents )."</$element>";
return $out;
}

Dans un bloc CDATA, vous n'avez pas besoin d'utiliser cette fonction ... Mais évitez l'utilisation aveugle de CDATA.

14
Peter Krauss

Votre question est donc "le résultat de htmlentities () est-il garanti conforme à XML et conforme à UTF-8?" La réponse est non, ce n'est pas le cas.

htmlspecialchars () devrait être suffisant pour échapper aux caractères spéciaux de XML mais vous devrez aseptiser vos chaînes UTF-8 de toute façon. Même si vous construisez votre XML avec, disons, SimpleXML, vous devrez aseptiser les chaînes. Je ne connais pas d'autres librairies comme XMLWriter ou DOM, je pense que c'est la même chose.

5
Josh Davis

Je pensais que j'ajouterais cela pour ceux qui ont besoin de nettoyer et de ne pas perdre les attributs XML.

// Returns SimpleXML Safe XML keeping the elements attributes as well
function sanitizeXML($xml_content, $xml_followdepth=true){

    if (preg_match_all('%<((\w+)\s?.*?)>(.+?)</\2>%si', $xml_content, $xmlElements, PREG_SET_ORDER)) {

        $xmlSafeContent = '';

        foreach($xmlElements as $xmlElem){
            $xmlSafeContent .= '<'.$xmlElem['1'].'>';
            if (preg_match('%<((\w+)\s?.*?)>(.+?)</\2>%si', $xmlElem['3'])) {
                $xmlSafeContent .= sanitizeXML($xmlElem['3'], false);
            }else{
                $xmlSafeContent .= htmlspecialchars($xmlElem['3'],ENT_NOQUOTES);
            }
            $xmlSafeContent .= '</'.$xmlElem['2'].'>';
        }

        if(!$xml_followdepth)
            return $xmlSafeContent;
        else
            return "<?xml version='1.0' encoding='UTF-8'?>".$xmlSafeContent;

    } else {
        return htmlspecialchars($xml_content,ENT_NOQUOTES);
    }

}

tilisation:

$body = <<<EG
<?xml version='1.0' encoding='UTF-8'?>
<searchResult count="1">
   <item>
      <title>2016 & Au Rendez-Vous Des Enfoir&</title>
   </item>
</searchResult>
EG;
$newXml = sanitizeXML($body);
var_dump($newXml);

Renvoie:

<?xml version='1.0' encoding='UTF-8'?>
<searchResult count="1">
    <item>
        <title>2016 &amp; Au Rendez-Vous Des Enfoir&amp;</title>
    </item>
</searchResult>
0
Cylosh