web-dev-qa-db-fra.com

Comment faites-vous des chaînes "XML safe"?

Je réponds à un appel AJAX en lui envoyant un document XML via PHP echos. Afin de former ce document XML, je parcoure les enregistrements d'une base de données. Le problème est que la base de données comprend des enregistrements comportant des symboles "<". Alors, naturellement, le navigateur génère une erreur à cet endroit. Comment cela peut-il être corrigé?

55
JayD3e

Vous pouvez soit échapper ces caractères avec htmlspecialchars , soit utiliser une bibliothèque pour construire des documents XML, tels que DOMDocument ou XMLWriter .

Une autre solution consisterait à utiliser les sections CDATA, mais vous devrez alors rechercher les occurrences de ]]>.

Prenez également en compte le fait que vous devez respecter le codage que vous définissez pour le document XML (par défaut, UTF-8).

61
Artefacto

Depuis PHP 5.4, vous pouvez utiliser:

htmlspecialchars($string, ENT_XML1);

Vous devez spécifier le codage, tel que:

htmlspecialchars($string, ENT_XML1, 'UTF-8');

Mettre à jour

Notez que ce qui précède ne convertira que:

  • & à &amp;
  • < à &lt;
  • > à &gt;

Si vous souhaitez échapper du texte à utiliser dans un attribut placé entre guillemets:

htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8');

convertira " en &quot; en plus de &, < et >.


Et si vos attributs sont entre guillemets simples:

htmlspecialchars($string, ENT_XML1 | ENT_QUOTES, 'UTF-8');

convertira ' en &apos; en plus des &, <, > et ".

(Bien sûr, vous pouvez l'utiliser même en dehors d'attributs).


Voir l’entrée manuelle pour htmlspecialchars .

57
user3409662

1) Vous pouvez envelopper votre texte en tant que CDATA comme ceci:

<mytag>
    <![CDATA[Your text goes here. Btw: 5<6 and 6>5]]>
</mytag>

voir http://www.w3schools.com/xml/xml_cdata.asp

2) Comme déjà dit quelqu'un: échapper ces caractères. Par exemple. ainsi: 

5&lt;6 and 6&gt;5
9
Elvith

Essaye ça:

$str = htmlentities($str,ENT_QUOTES,'UTF-8');

Ainsi, après avoir filtré vos données à l'aide de la fonction htmlentities(), vous pouvez utiliser les données dans une balise XML comme: 

<mytag>$str</mytag>
5
Mosiur

Dans la mesure du possible, il est toujours judicieux de créer votre code XML à l'aide des classes XML plutôt que de la manipulation de chaîne. L'un des avantages est que les classes échapperont automatiquement les caractères au besoin.

5
Ed Schembor

Ajouter ceci au cas où cela aiderait quelqu'un.

Comme je travaille avec des caractères japonais, le codage a également été défini correctement. Cependant, de temps en temps, je trouve que htmlentities et htmlspecialchars ne sont pas suffisants.

Certaines entrées utilisateur contiennent des caractères spéciaux qui ne sont pas supprimés par les fonctions ci-dessus. Dans ces cas, je dois faire ceci:

preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string))

Cela supprimera également certains caractères de contrôle xml-unsafe tels que Null character ou EOT. Vous pouvez utiliser cette table pour déterminer les caractères que vous souhaitez omettre.

4
Reuben L.

Je préfère la façon dont Golang cite l'échappement pour XML (et quelques extras comme l'échappement de nouvelle ligne et certains caractères), j'ai donc porté sa fonction d'échappement XML sur PHP ci-dessous.

function isInCharacterRange(int $r): bool {
    return $r == 0x09 ||
            $r == 0x0A ||
            $r == 0x0D ||
            $r >= 0x20 && $r <= 0xDF77 ||
            $r >= 0xE000 && $r <= 0xFFFD ||
            $r >= 0x10000 && $r <= 0x10FFFF;
}

function xml(string $s, bool $escapeNewline = true): string {
    $w = '';

    $Last = 0;
    $l = strlen($s);
    $i = 0;

    while ($i < $l) {
        $r = mb_substr(substr($s, $i), 0, 1);
        $Width = strlen($r);
        $i += $Width;
        switch ($r) {
            case '"':
                $esc = '&#34;';
                break;
            case "'":
                $esc = '&#39;';
                break;
            case '&':
                $esc = '&amp;';
                break;
            case '<':
                $esc = '&lt;';
                break;
            case '>':
                $esc = '&gt;';
                break;
            case "\t":
                $esc = '&#x9;';
                break;
            case "\n":
                if (!$escapeNewline) {
                    continue 2;
                }
                $esc = '&#xA;';
                break;
            case "\r":
                $esc = '&#xD;';
                break;
            default:
                if (!isInCharacterRange(mb_ord($r)) || (mb_ord($r) === 0xFFFD && $Width === 1)) {
                    $esc = "\u{FFFD}";
                    break;
                }

                continue 2;
        }
        $w .= substr($s, $Last, $i - $Last - $Width) . $esc;
        $Last = $i;
    }
    $w .= substr($s, $Last);
    return $w;
}

Notez que vous aurez besoin d'au moins PHP 7.2 à cause de l'utilisation de mb_ord, ou vous devrez l'échanger pour un autre polyfill, mais ces fonctions fonctionnent très bien pour nous!

Pour les curieux, voici le code source pertinent https://golang.org/src/encoding/xml/xml.go?s=44219:44263#L1887

0
Brian Leishman