标头发送时SimpleXML addChild问题

时间:2014-01-27 11:32:02

标签: php simplexml

我有这段代码:

$xml = new SimpleXMLElement('<myxml></myxml>');
$xml->addChild('testNode attr="test Attribute"');
$node = $xml->addChild('erroNode attr="My Child node causes error -> expect >"');
//$node->addChild('nodeChild attr="node Child"');
header('Content-type: text/xml');
echo $xml->asXML();
exit();

我可以通过$xml创建一个包含属性的子节点,但不能创建$node(孩子的孩子),为什么?我收到错误error on line 2 at column 66: expected '>' 从文档中可以看出addChild函数返回子进程的SimpleXmlElement。 通过取消注释评论行$node->addChild('nodeChild attr="node Child"');进行检查 它也只发生在标题发送时,如果我评论标题并且如下所示我可以在页面源中看到正确的xml:

 $xml = new SimpleXMLElement('<myxml></myxml>');
    $xml->addChild('testNode attr="test Attribute"');
    $node = $xml->addChild('erroNode attr="My Child node causes error -> expect >"');
    $node->addChild('nodeChild attr="node Child"');
    //header('Content-type: text/xml');
    echo $xml->asXML();
    exit();

我的PHP版本是5.4.9

1 个答案:

答案 0 :(得分:0)

您看到的错误不是来自SimpleXML,而是来自您的浏览器 - 这就是更改HTTP标头的原因。使用此行,浏览器知道页面是XML,并检查它是否有效;没有它,它假定它是HTML,并且更宽松:

header('Content-type: text/xml');

如果您在浏览器中使用“查看源代码”,您会发现PHP的实际输出在两种情况下都是相同的。另一个不错的测试是将内容类型设置为text/plain,这意味着浏览器根本不会解释输出,只是按原样显示。

因此,由于某种原因,SimpleXML生成无效的XML。这是因为the ->addChild() method将第一个参数作为要添加的元素的名称,在您的情况下'erroNode';您传入的无效名称也包含属性,稍后应使用->addAttribute()添加。


如果我们进一步简化示例,并查看生成的XML,我们可以看到正在发生的事情(这里是an online demo):

// Make browser show plain output
header('Content-type: text/plain');

// Working example
$xml = new SimpleXMLElement('<myxml></myxml>');
$xml->addChild('testNode attr="test Attribute"');
echo $xml->asXML();

echo "\n";

// Broken example
$xml = new SimpleXMLElement('<myxml></myxml>');
$node = $xml->addChild('testNode attr="test Attribute"');
$node->addChild('test');
echo $xml->asXML();Child('testNode attr="test Attribute"');
$node->addChild('test');
echo $xml->asXML();

这输出如下:

<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"/></myxml>

<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"><test/></testNode attr="test Attribute"></myxml>

XML 的第一个版本正在做正确的事情,因为它创建了一个“自闭标签”。但是,在第二个中,您可以看到SimpleXML认为标记名称为'testNode attr="test Attribute"',而不仅仅是'testNode',因为这就是我们所说的。

结果是它尝试使用该“name”放置一个结束标记,最后是</testNode attr="test Attribute">,这是无效的XML。

可以说,SimpleXML可以保护您免受此类攻击,但现在您知道,您可以轻松修复代码(demo):

// Make browser show plain output
header('Content-type: text/plain');

// Fixed example
$xml = new SimpleXMLElement('<myxml></myxml>');
$node = $xml->addChild('testNode');
$node->addAttribute('attr', 'test Attribute');
$node->addChild('test');
echo $xml->asXML();

现在,SimpleXML知道标签只是被称为'testNode',因此可以在需要时创建正确的结束标记:

<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"><test/></testNode></myxml>