Sto costruendo un file XML da zero e ho bisogno di sapere se htmlentities() converte ogni carattere che potrebbe potenzialmente rompere un file XML (e possibilmente dati UTF-8)? I valori saranno da un feed twitter/flickr, quindi ho bisogno di essere sicuro!PHP - È sufficiente htmlentities() per creare valori xml-safe?
risposta
htmlentities()
non è un modo garantito per creare XML legale.
Utilizzare htmlspecialchars()
anziché htmlentities()
se questo è tutto ciò di cui si è preoccupati. Se si hanno discrepanze di codifica tra la rappresentazione dei propri dati e la codifica del proprio documento XML, lo htmlentities()
può servire a risolverli/coprirli (aumenterà la dimensione XML nel farlo). Credo che sia meglio ottenere le codifiche coerenti e utilizzare solo htmlspecialchars()
.
Inoltre, tenere presente che se si pompa il valore di ritorno di htmlspecialchars()
all'interno di attributi XML delimitati da virgolette singole, sarà necessario passare anche il flag ENT_QUOTES
in modo che anche le singole virgolette nella stringa di origine siano correttamente codificate. Suggerisco comunque di farlo, poiché rende il tuo codice immune ai bug risultanti da qualcuno che utilizza le virgolette singole per gli attributi XML in futuro.
Edit: per chiarire:
htmlentities()
sarà convertire un numero di caratteri non ANSI (presumo questo è ciò che si intende per dati UTF-8) a soggetti (che sono rappresentati con solo caratteri ANSI) . Tuttavia, non può farlo per i caratteri che non hanno un'entità corrispondente, e quindi non può garantire che il suo valore di ritorno sia costituito solo da caratteri ANSI. Ecco perché sto suggerendo di non usarlo.
Se la codifica è un problema possibile, gestirlo in modo esplicito (ad esempio con iconv()
).
Modifica 2: risposta migliore tenendo conto del commento di Josh Davis di seguito.
Non utilizzare 'htmlentities' per XML; è inteso per HTML e non XML. XML conosce solo le cinque entità * amp *, * lt *, * gt *, * apos * e * quot *. Ma 'htmlentities' userà molto di più (quelli che sono registrati per HTML). – Gumbo
Grazie per la spiegazione completa e la nota sull'uso di ENC_QUOTES! –
L'affermazione "renderà il tuo XML garantito legale" ** non potrebbe essere più sbagliato ** però. Come menzionato sopra, htmlentities() utilizza entità che non sono definite in XML. Inoltre, non disinfetta i byte che non dovrebbero apparire in un documento XML, come il byte NUL. Non disinfetta neanche UTF-8, quindi in alcuni casi potrebbe diventare impossibile per i parser XML sul documento risultante. –
Dom::createTextNode()
uscirà automaticamente dal contenuto.
Esempio:
$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();
uscita:
<?xml version="1.0"?>
<Element>I am text with Ünicödé & HTML €ntities ©</Element>
Quando si imposta la codifica interna utf-8, ad esempio
$dom->encoding = 'utf-8';
ci si può comunque
<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé & HTML €ntities ©</Element>
Si noti che quanto sopra non è lo stesso che l'impostazione del secondo argomento $value
in Dom::createElement()
. Il metodo si accerterà solo che i nomi degli elementi siano validi. Vedere le note nella pagina del manuale, ad es.
$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();
si tradurrà in un avvertimento
Warning: DOMDocument::createElement(): unterminated entity reference HTML €ntities ©
e il seguente output:
<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé </Element>
Quindi la tua domanda è "è htmlentities() 's risultato garantito per essere compatibile con XML e UTF-8-compatibile?" La risposta è no, non lo è.
htmlspecialchars() dovrebbe essere sufficiente per sfuggire ai caratteri speciali di XML, ma sarà necessario disinfettare le stringhe UTF-8 in entrambi i casi. Anche se costruisci il tuo XML con, ad esempio, SimpleXML, dovrai disinfettare le stringhe. Non so altre librairie come XMLWriter o DOM, penso che sia lo stesso.
La risposta di Gordon è buona e spiega i problemi di codifica XML, ma non mostra una funzione semplice (o ciò che fa la scatola nera). La risposta di Jon inizia bene con la raccomandazione della funzione 'htmlspecialchars', ma lui e altri fanno qualche errore, quindi sarò enfatico.
Un buon programmatore deve avere il controllo circa l'uso o meno di UTF-8 nelle stringhe e dati XML: UTF-8 (o un'altra codifica non ASCII) è sicuro in un algoritmo coerente.
XML UTILE SICURO NON HA BISOGNO DI CODICE ENTITÀ COMPLETA. La codifica indiscriminata produce "seconda classe, non leggibile da parte dell'utente, codifica/decodifica-richiesta, XML". E sicuro ASCII XML, inoltre non è necessario codificare l'entità, quando tutti i tuoi contenuti sono ASCII.
Solo 3 o 4 caratteri devono essere sfuggito in una serie di contenuti XML: >
, <
, &
, e facoltativo "
. Leggere http://www.w3.org/TR/REC-xml/ "2.4 Dati carattere e marcatura" e "4.6 Entità predefinite". Quindi è possibile utilizzare 'htmlentities'
Per l'illustrazione, la seguente funzione PHP farà un XML completamente sicuro:
// it is a didactic illustration, USE htmlentities($S,flag)
function xmlsafe($s,$intoQuotes=0) {
if ($intoQuotes)
return str_replace(array('&','>','<','"'), array('&','>','<','"'), $s);
// SAME AS htmlspecialchars($s)
else
return str_replace(array('&','>','<'), array('&','>','<'), $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;
}
In un blocco CDATA non è necessario utilizzare questa funzione ... Ma, per favore, evitare l'uso indiscriminato di CDATA.
Grazie !! Ho provato molte combinazioni di tidy, htmlentities, htmlspecialchars ma il tuo xmlsafe è il migliore; (ma prima consiglio di usare html_entity_decode()) –
Informazioni su my 'xmlsafe()', come dico, è "per illustrazione", ma grazie! :-) A proposito dell'uso di 'html_entity_decode()' con XML, vedere altri problemi e soluzioni su http://stackoverflow.com/q/18039765/287948 –
Questa risposta è stata apprezzata semplicemente per la funzione di esempio. Penso che Jons abbia risposto è stato il migliore, ma questo, solo perché nella mia situazione particolare, mi ha aiutato di più, e così ho voluto votare questo. Grazie. (posso votare due risposte?) – gregthegeek
Ho pensato di aggiungere questo per coloro che hanno bisogno di disinfettare lo & senza perdere gli attributi 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);
}
}
utilizzo:
$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);
Returns:
<?xml version='1.0' encoding='UTF-8'?>
<searchResult count="1">
<item>
<title>2016 & Au Rendez-Vous Des Enfoir&</title>
</item>
</searchResult>
vedere un altro problemi e soluzioni UTF8 XML di sicurezza presso http://stackoverflow.com/q/18039765/ 287948 –