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é?
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).
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');
Notez que ce qui précède ne convertira que:
&
à &
<
à <
>
à >
Si vous souhaitez échapper du texte à utiliser dans un attribut placé entre guillemets:
htmlspecialchars($string, ENT_XML1 | ENT_COMPAT, 'UTF-8');
convertira "
en "
en plus de &
, <
et >
.
Et si vos attributs sont entre guillemets simples:
htmlspecialchars($string, ENT_XML1 | ENT_QUOTES, 'UTF-8');
convertira '
en '
en plus des &
, <
, >
et "
.
(Bien sûr, vous pouvez l'utiliser même en dehors d'attributs).
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<6 and 6>5
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>
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.
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.
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 = '"';
break;
case "'":
$esc = ''';
break;
case '&':
$esc = '&';
break;
case '<':
$esc = '<';
break;
case '>':
$esc = '>';
break;
case "\t":
$esc = '	';
break;
case "\n":
if (!$escapeNewline) {
continue 2;
}
$esc = '
';
break;
case "\r":
$esc = '
';
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