web-dev-qa-db-ja.com

PHP-htmlentities()はxml-safe値を作成するのに十分ですか?

私はゼロからXMLファイルを構築していますが、htmlentities()がXMLファイル(およびおそらくUTF-8データ)を破壊する可能性のあるすべての文字を変換するかどうかを知る必要がありますか?値はTwitter/flickrフィードから取得されるため、確認する必要があります!

34
John Himmelman

Dom::createTextNode() はコンテンツを自動的にエスケープします。

例:

_$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();
_

出力:

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

内部エンコードをutf-8に設定すると、たとえば.

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

あなたはまだ得るでしょう

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

上記は Dom::createElement() で2番目の引数_$value_を設定することと同じではないことに注意してください。このメソッドは、要素名が有効であることのみを確認します。マニュアルページの注を参照してください。

_$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();
_

警告になります

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

そして、次の出力:

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

Gordonの答えは適切であり、XMLエンコードの問題を説明していますが、単純な機能(またはブラックボックスの機能)は示していません。 Jonの答えは「htmlspecialchars」機能の推奨から始まりますが、彼と他の人は何らかの間違いを犯します。それから私は強調します。

優れたプログラマー文字列とXMLデータでのUTF-8の使用の有無を制御する必要があります:UTF-8(または別の非ASCIIエンコード) IS一貫したアルゴリズムで安全。

安全なUTF-8 XMLは完全なエンティティエンコードを必要としません。無差別エンコードは、「2番目のクラス、非人間可読、エンコード/デコード要求、XML」を生成します。すべてのコンテンツがASCIIの場合、安全なASCII XML、エンティティエンコードも必要ありません。

XMLコンテンツの文字列でエスケープする必要があるのは3文字または4文字のみです:><&、およびオプションの"http://www.w3.org/TR/REC-xml/ 「2.4文字データとマークアップ」および「4.6定義済みエンティティ」をお読みください。次に、「 htmlentities 」を使用できます

例として、次のPHP関数はXMLを完全に安全にします:

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

CDATAブロックでは、この関数を使用する必要はありません...ただし、CDATAを無差別に使用しないでください。

14
Peter Krauss

あなたの質問は、「htmlentities()の結果はXML準拠およびUTF-8準拠であることが保証されていますか?」です。答えはノーです、そうではありません。

htmlspecialchars()shouldはXMLの特殊文字をエスケープするには十分ですが、UTF-8文字列はいずれにしてもサニタイズする必要があります。 SimpleXMLを使用してXMLを構築する場合でも、文字列をサニタイズする必要があります。 XMLWriterやDOMなどの他のライブラリについては知りません。同じだと思います。

5
Josh Davis

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);
    }

}

使用法:

$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);

戻り値:

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