【问题标题】:Is htmlentities() sufficient for creating xml-safe values?htmlentities() 是否足以创建 xml 安全值?
【发布时间】:2011-02-18 20:22:35
【问题描述】:

我正在从头开始构建一个 XML 文件,并且需要知道 htmlentities() 是否转换了每个可能破坏 XML 文件(可能还有 UTF-8 数据)的字符?

这些值将来自 twitter/flickr 提要,所以我需要确定-

【问题讨论】:

标签: php xml xml-serialization


【解决方案1】:

htmlentities() 不是构建合法 XML 的保证方式。

如果您只担心这些,请使用htmlspecialchars() 而不是htmlentities()。如果您的数据表示和 XML 文档的编码之间存在编码不匹配,htmlentities() 可能会解决/掩盖它们(这样做会使您的 XML 大小膨胀)。我相信最好让你的编码保持一致,只使用htmlspecialchars()

另外,请注意,如果您将 htmlspecialchars() 的返回值插入以单引号分隔的 XML 属性,您还需要传递 ENT_QUOTES 标志,以便源字符串中的任何单引号都被正确编码以及。我建议无论如何都这样做,因为它可以让您的代码免受将来有人对 XML 属性使用单引号引起的错误。

编辑:澄清:

htmlentities() 会将许多非 ANSI 字符(我假设这就是您所说的 UTF-8 数据的意思)转换为实体(仅用 ANSI 字符表示)。但是,它不能对没有对应实体的任何字符执行此操作,因此不能保证其返回值仅由 ANSI 字符组成。这就是为什么我建议不要使用它。

如果可能存在编码问题,请明确处理(例如使用iconv())。

编辑 2:考虑到 Josh Davis 的以下评论,改进了答案。

【讨论】:

  • 不要将htmlentities 用于XML;它适用于 HTML 而不是 XML。 XML 只知道 ampltgtaposquot这五个实体>。但是htmlentities 会使用更多(那些为 HTML 注册的)。
  • 感谢您对使用 ENC_QUOTES 的详尽解释和注意事项!
  • “这将使您的 XML 保证合法”的声明再错误不过了。如上所述,htmlentities() 使用 XML 中未定义的实体。此外,它不会清理不应出现在 XML 文档中的字节,例如 NUL 字节。它也不会清理无效的 UTF-8,因此在某些情况下,XML 解析器可能无法解析生成的文档。
  • htmlspecialchars($string, ENT_XML1)怎么样
  • @Meglio 自 PHP 7.3.5 起,使用 ENT_QUOTES | ENT_XML1 与仅使用 ENT_QUOTES 相同,仅 ENT_NOQUOTES 与仅使用 ENT_XML1 相同。
【解决方案2】:

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() 中设置第二个参数$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>

【讨论】:

    【解决方案3】:

    戈登的回答很好并解释了 XML 编码问题,但没有显示简单的功能(或黑盒的作用)。 Jon 的回答从 'htmlspecialchars' 功能推荐开始,但他和其他人犯了一些错误,那么我会强调。

    优秀的程序员必须控制是否在您的字符串和 XML 数据中使用 UTF-8:UTF-8(或其他非 ASCII 编码)在一致的算法中是安全的。

    安全的 UTF-8 XML 不需要完整的实体编码。不分青红皂白的编码产生“第二类,非人类可读,编码/解码需求,XML”。并且安全的 ASCII XML,也不需要实体编码,当你所有的内容都是 ASCII 时。

    在 XML 内容的字符串中只需要转义 3 或 4 个字符:&gt;&lt;&amp; 和可选的"。 请阅读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。

    【讨论】:

    • 谢谢!!我尝试了很多 tidy、htmlentities、htmlspecialchars 的组合,但你的 xmlsafe 是最好的; (但在我推荐使用 html_entity_decode() 之前)
    • 关于我的xmlsafe(),正如我所说,是“为了说明”,但谢谢! :-) 关于html_entity_decode() 与 XML 的使用,请参阅stackoverflow.com/q/18039765/287948 上的更多问题和解决方案
    • 真的很感谢这个答案只是为了示例函数。我认为 Jons 的回答是最好的,但这只是因为在我的特殊情况下,它对我的​​帮助更大,所以我想对此投赞成票。谢谢。 (我可以投票两个答案吗?)
    • 你可以做得更好:更正我的代码或我的英语,现在文本作为 Wiki 打开。
    • 请帮助维护维基百科中的CDATA Criticism section
    【解决方案4】:

    所以您的问题是“htmlentities() 的结果是否保证符合 XML 和 UTF-8?”答案是否定的,不是。

    htmlspecialchars() 应该 足以转义 XML 的特殊字符,但无论哪种方式,您都必须清理 UTF-8 字符串。即使您使用 SimpleXML 构建 XML,您也必须清理字符串。 XMLWriter 或者 DOM 等其他库我不知道,我认为是一样的。

    【讨论】:

      【解决方案5】:

      我想我会为那些需要清理和不丢失 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>
      

      【讨论】:

        猜你喜欢
        • 2021-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-21
        • 1970-01-01
        • 1970-01-01
        • 2013-09-20
        相关资源
        最近更新 更多