PHP XML实体未使用simplexml_load_string和SimpleXMLElement addChild / addAttribute定义解析问题

时间:2015-03-04 19:41:02

标签: php xml parsing

使用PHP 5.3.13

解析xml时,

simplexml_load_string 会抛出实体'除以'未定义错误。

此问题的大多数解决方案都集中在如何处理 SimpleXMLElement 及其 addChild addAttribue 方法。这些方法将一些特殊字符转换为实体。然后解决方案似乎要处理 simplexml_load_string 不理解的几个特殊字符。

问题是列表非常大,如果你在$ string上使用 htmlentities($ string,ENT_QUOTES,'UTF-8',true),你将要插入XML addChild 然后它会添加正常但 simplexml_load_string 会在尝试从 SimpleXMLElement 生成的 as_xml 解析生成的XML时崩溃。

另一个问题是生成的实体列表可能很长,但用户可以轻松输入以下& pizza;它会打破解析器。由于我需要处理所有用户输入,我想出了以下内容,但想知道你是否看到它会失败。

想知道以下解决方案是否有效: 替换&带有& amp;的字符串中的任何地方。 我一直无法找到一个案例,因为我的解决方案已经解决,但因为它很简单,我还没有把它看作列出的解决方案

  1. Rationale behind SimpleXMLElement's handling of text values in addChild and addAttribute - On this issue but does not solve the general issue
  2. XML parser error: entity not defined - Addressing just a few special characters
  3. 以下是我可能的解决方案的示例代码:

    $content_amp_safe = str_replace('&','&',$content);
    

    以下是错误消息:

      

    警告:simplexml_load_string():实体:第11行:解析器错误:内部错误        实体“鸿沟”未定义

    以下是导致问题解决前的代码:

    <?php
    // insert that causes the issue with the windows encoded dash, triple dot, and right quote as an example
    // also issue if user enters &pizza; in the text as it is an unknown entity
    $content = "I love &pizza; in the … morning's  – night as well";
    $content_unsafe = htmlentities($content, ENT_QUOTES, 'UTF-8', true);
    //fix is to use $content_amp_safe string instead
    $content_amp_safe = str_replace('&','&amp;',$content_unsafe);
    $xml = new SimpleXMLElement("<?xml version='1.0' encoding='utf-8'?><Entries />");
    $entry = $xml->addChild('Entry');
    $entry->addChild('Content', $content);
    $xml_string = $xml->asXML();
    libxml_use_internal_errors(true);
    $xml = simplexml_load_string($xml_string);
    if ($xml === false) {
        $error_string = "Failed loading XML\n";
        foreach ( libxml_get_errors() as $error ) {
                $error_string .= "\t" . $error->message;
        }
        echo $error_string;
        ));
    }
    libxml_use_internal_errors(false);
    
    ?>
    

    使用 htmlentities 对用户输入导致问题的某些字符的简短版本。

    <?php 
     $table = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES, 'cp1252');
     var_dump($table);
    ?>
    

    示例字符:

    €,ƒ“...†‡‡<Œ''”“• - 〜™š>œŸ¢¢¥|§«ª«¬®¯°±³³μμ··· »¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ&安培;“'&LT;&GT;

    示例编码:

    €,ƒ“...†‡‰Š<Œ ''‘’•--~™S>œŸ¡¢£¤¥|§¨©ª«¬®¯°±²³'μ¶·¸¹º »¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ&安培;“'&LT;&GT;

    示例新编码:

    &安培;欧元;&安培; sbquo;&安培; fnof;&安培; bdquo;&安培; hellip;&安培;匕首;&安培;匕首;&安培; CIRC;&安培; permil;&安培; Scaron;&安培; lsaquo;上&安培; OElig ;&安培; lsquo的;&安培; rsquo的;&安培; ldquo;&安培; rdquo;的&安培;公牛;&安培; ndash的;&安培; MDASH;&安培;波浪;&安培;贸易;&安培; scaron;&安培; rsaquo;&安培; oelig;&放; Yuml;&安培; NBSP;&安培; iexcl;&安培;百分之;&安培;磅;&安培; CURREN;&安培;日元;&安培; brvbar;&安培;节;&安培; UML;&安培;复印;&安培; ordf;&安培; LAQUO ;&安培;不;&安培;害羞;&安培; REG;&安培; MACR;&安培;度;&安培; plusmn;&安培; SUP2;&安培; SUP3;&安培;急性;&安培;微;&安培;对;&安培; middot;&安培; cedil;&安培; SUP1;&安培; ORDM;&安培; RAQUO;&安培; frac14;&安培; frac12;&安培; frac34;&安培; iquest;&安培; Agrave;&安培; Aacute;&安培; ACIRC;&安培; Atilde;&安培; AUML ;&安培; Aring;&安培; AElig;&安培; Ccedil;&安培; Egrave;&安培; Eacute;&安培; Ecirc;&安培; Euml;&安培; Igrave;&安培; Iacute;&安培; Icirc;&安培; IUML;&安培; ETH;&安培; Ntilde;&安培; Ograve;&安培; Oacute;&安培; Ocirc;&安培; Otilde;&安培; Ouml;&安培;倍;&安培; Oslash;&安培; Ugrave;&安培; Uacute;&安培; Ucirc;&安培; Uuml;&安培; Yacute ;&安培; THORN;&安培;大街;&安培; agrave;&安培; aacu TE;&安培; ACIRC;&安培; atilde;&安培; AUML;&安培; aring;&安培; aelig;&安培; ccedil;&安培; egrave;&安培; eacute;&安培; ecirc;&安培; euml;&安培; igrave;&安培; iacute; &安培; icirc;&安培; IUML;&安培; ETH;&安培; ntilde;&安培; ograve;&安培; oacute;&安培; ocirc;&安培; otilde;&安培; ouml;&安培;除法;&安培; oslash;&安培; ugrave;&安培; uacute;&安培; ucirc;&安培; uuml;&安培; yacute;&安培;刺;&安培; yuml;&放大器;放大器;&安培; QUOT;&安培;#039;&安培; LT;&安培; GT;

1 个答案:

答案 0 :(得分:1)

您的观察是正确的SimpleXMLElement::addChild()(和::addAttribute())将(仅)某些特殊字符转换为实体。

这是逐字输入一些字符(特别是&符号“&”字符)。

但是你不希望在你的情况下这样做。要转换所有特殊字符,您需要通过属性访问设置XML元素的文本值,例如:

$entry->Content = $content;

如您所见,未使用$entry->addChild('Content', $content),而是使用属性访问$entry->Content。只有插入一个Content元素时,该属性访问才有效。如果要向同一父项插入多个,则必须使用所谓的simplexml-self-reference。现在再次演示 addChild()

$entry->addChild('Content')->{0} = $content;

完整示例:

$content = "I love &pizza; in the … morning's  – night as well";

$xml = new SimpleXMLElement("<Entries />");
$entry = $xml->addChild('Entry');
$entry->Content = $content;
$entry->addChild('Content')->{0} = $content;

echo $xml->asXML();

输出(美化):

<?xml version="1.0"?>
<Entries>
  <Entry>
    <Content>I love &amp;pizza; in the … morning's  – night as well</Content>
    <Content>I love &amp;pizza; in the … morning's  – night as well</Content>
  </Entry>
</Entries>

我希望现在不会太混乱。

除了&符号的问题之外,您可能会看到一些字符编码问题。对于那些有一个简单的规则:每当您将字符串传递给 SimpleXMLElement 时,该字符串的编码必须是UTF-8。

因此,如果您从网站上获取HTML表单中的数据,请注意浏览器会将数据UTF-8编码 - 或者 - 将数据重新编码为UTF-8,然后再将其传递给 SimpleXMLElement