Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions ext/simplexml/simplexml.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ static void php_sxe_iterator_move_forward(zend_object_iterator *iter);
static void php_sxe_iterator_rewind(zend_object_iterator *iter);
static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int type);

static zend_always_inline bool php_sxe_is_inclusive_text_node(const xmlNode *node)
{
return node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE;
}

/* {{{ _node_as_zval() */
static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix)
{
Expand Down Expand Up @@ -746,7 +751,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
if (node) {
exists = 1;
if (check_empty == 1 &&
(!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
(!node->children || (php_sxe_is_inclusive_text_node(node->children) && !node->children->next &&
(!node->children->content || !node->children->content[0] || xmlStrEqual(node->children->content, (const xmlChar *) "0")))) ) {
exists = 0;
}
Expand Down Expand Up @@ -928,7 +933,7 @@ static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval
php_sxe_object *subnode;
xmlChar *contents;

if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
if (node->children && php_sxe_is_inclusive_text_node(node->children) && !xmlIsBlankNode(node->children)) {
contents = xmlNodeListGetString(node->doc, node->children, 1);
if (contents) {
ZVAL_STRING(value, (char *)contents);
Expand Down Expand Up @@ -1026,7 +1031,7 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
if (node->children != NULL || node->prev != NULL || node->next != NULL) {
SKIP_TEXT(node);
} else {
if (node->type == XML_TEXT_NODE) {
if (php_sxe_is_inclusive_text_node(node)) {
const xmlChar *cur = node->content;
if (*cur != 0) {
is_empty = 0;
Expand Down Expand Up @@ -1147,7 +1152,7 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
if (node->children != NULL || node->prev != NULL || node->next != NULL || xmlIsBlankNode(node)) {
SKIP_TEXT(node);
} else {
if (node->type == XML_TEXT_NODE) {
if (php_sxe_is_inclusive_text_node(node)) {
const xmlChar *cur = node->content;

if (*cur != 0) {
Expand Down Expand Up @@ -1313,13 +1318,13 @@ PHP_METHOD(SimpleXMLElement, xpath)

for (i = 0; i < result->nodeNr; ++i) {
nodeptr = result->nodeTab[i];
if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
if (php_sxe_is_inclusive_text_node(nodeptr) || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
/**
* Detect the case where the last selector is text(), simplexml
* always accesses the text() child by default, therefore we assign
* to the parent node.
*/
if (nodeptr->type == XML_TEXT_NODE) {
if (php_sxe_is_inclusive_text_node(nodeptr)) {
_node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_NONE, NULL, NULL, 0);
} else if (nodeptr->type == XML_ATTRIBUTE_NODE) {
_node_as_zval(sxe, nodeptr->parent, &value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0);
Expand Down
94 changes: 94 additions & 0 deletions ext/simplexml/tests/bug70570.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
--TEST--
Bug #70570 (json_encode and var_dump ignore simplexml cdata)
--EXTENSIONS--
simplexml
--FILE--
<?php

$input = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<container>
<A><![CDATA[0]]></A>
<B><![CDATA[hello world]]></B>
<C><![CDATA[hello]]><foo/><![CDATA[world]]></C>
<D><foo/><![CDATA[hello]]><bar/></D>
</container>
XML;

$xml = simplexml_load_string($input);

var_dump($xml);

foreach (["A", "B"] as $item) {
echo "--- Testing $item ---\n";
var_dump($xml->xpath("//$item/text()"));
var_dump($xml->$item);
var_dump(isset($xml->$item));
var_dump(empty($xml->$item));
var_dump((bool) ($xml->$item));
}

echo "--- Testing C ---\n";

var_dump($xml->C); // Equivalent to how (normal) text nodes behave
var_dump((string) $xml->C);
var_dump($xml->C->foo);

?>
--EXPECT--
object(SimpleXMLElement)#1 (4) {
["A"]=>
string(1) "0"
["B"]=>
string(11) "hello world"
["C"]=>
string(10) "helloworld"
["D"]=>
object(SimpleXMLElement)#2 (2) {
["foo"]=>
object(SimpleXMLElement)#3 (0) {
}
["bar"]=>
object(SimpleXMLElement)#4 (0) {
}
}
}
--- Testing A ---
array(1) {
[0]=>
object(SimpleXMLElement)#2 (1) {
[0]=>
string(1) "0"
}
}
object(SimpleXMLElement)#2 (1) {
[0]=>
string(1) "0"
}
bool(true)
bool(true)
bool(true)
--- Testing B ---
array(1) {
[0]=>
object(SimpleXMLElement)#2 (1) {
[0]=>
string(11) "hello world"
}
}
object(SimpleXMLElement)#2 (1) {
[0]=>
string(11) "hello world"
}
bool(true)
bool(false)
bool(true)
--- Testing C ---
object(SimpleXMLElement)#2 (1) {
["foo"]=>
object(SimpleXMLElement)#3 (0) {
}
}
string(10) "helloworld"
object(SimpleXMLElement)#3 (0) {
}