Skip to content

Commit 8dffbf2

Browse files
author
Rob Richards
committed
- Synch with head
1 parent 6ce1f43 commit 8dffbf2

5 files changed

Lines changed: 318 additions & 38 deletions

File tree

ext/simplexml/simplexml.c

Lines changed: 214 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,14 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
632632
xmlAttrPtr attr = NULL;
633633
int exists = 0;
634634
int test = 0;
635+
zval tmp_zv;
636+
637+
if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
638+
tmp_zv = *member;
639+
zval_copy_ctor(&tmp_zv);
640+
member = &tmp_zv;
641+
convert_to_string(member);
642+
}
635643

636644
sxe = php_sxe_fetch_object(object TSRMLS_CC);
637645

@@ -661,13 +669,28 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
661669

662670
if (node) {
663671
if (attribs) {
664-
while (attr) {
665-
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
666-
exists = 1;
667-
break;
672+
if (Z_TYPE_P(member) == IS_LONG) {
673+
int nodendx = 0;
674+
675+
while (attr && nodendx <= Z_LVAL_P(member)) {
676+
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
677+
if (nodendx == Z_LVAL_P(member)) {
678+
exists = 1;
679+
break;
680+
}
681+
nodendx++;
682+
}
683+
attr = attr->next;
668684
}
685+
} else {
686+
while (attr) {
687+
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
688+
exists = 1;
689+
break;
690+
}
669691

670-
attr = attr->next;
692+
attr = attr->next;
693+
}
671694
}
672695
}
673696

@@ -679,14 +702,6 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
679702
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
680703
}
681704
else {
682-
zval tmp_zv;
683-
684-
if (Z_TYPE_P(member) != IS_STRING) {
685-
tmp_zv = *member;
686-
zval_copy_ctor(&tmp_zv);
687-
member = &tmp_zv;
688-
convert_to_string(member);
689-
}
690705
node = node->children;
691706
while (node) {
692707
xmlNodePtr nnext;
@@ -696,16 +711,17 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
696711
}
697712
node = nnext;
698713
}
699-
if (member == &tmp_zv) {
700-
zval_dtor(&tmp_zv);
701-
}
702714
}
703715
if (node) {
704716
exists = 1;
705717
}
706718
}
707719
}
708720

721+
if (member == &tmp_zv) {
722+
zval_dtor(&tmp_zv);
723+
}
724+
709725
return exists;
710726
}
711727
/* }}} */
@@ -733,12 +749,12 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
733749
php_sxe_object *sxe;
734750
xmlNodePtr node;
735751
xmlNodePtr nnext;
736-
xmlAttrPtr attr;
752+
xmlAttrPtr attr = NULL;
737753
xmlAttrPtr anext;
738754
zval tmp_zv;
739-
int test;
755+
int test = 0;
740756

741-
if (Z_TYPE_P(member) != IS_STRING) {
757+
if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
742758
tmp_zv = *member;
743759
zval_copy_ctor(&tmp_zv);
744760
member = &tmp_zv;
@@ -748,45 +764,83 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
748764
sxe = php_sxe_fetch_object(object TSRMLS_CC);
749765

750766
GET_NODE(sxe, node);
767+
768+
if (Z_TYPE_P(member) == IS_LONG) {
769+
if (sxe->iter.type != SXE_ITER_ATTRLIST) {
770+
attribs = 0;
771+
elements = 1;
772+
if (sxe->iter.type == SXE_ITER_CHILD) {
773+
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
774+
}
775+
}
776+
}
777+
751778
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
752779
attribs = 1;
753780
elements = 0;
754781
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
755782
attr = (xmlAttrPtr)node;
756783
test = sxe->iter.name != NULL;
757-
} else {
784+
} else if (sxe->iter.type != SXE_ITER_CHILD) {
758785
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
759786
attr = node ? node->properties : NULL;
760787
test = 0;
761788
}
762789

763790
if (node) {
764791
if (attribs) {
765-
while (attr) {
766-
anext = attr->next;
767-
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
768-
xmlUnlinkNode((xmlNodePtr) attr);
769-
php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
770-
break;
792+
if (Z_TYPE_P(member) == IS_LONG) {
793+
int nodendx = 0;
794+
795+
while (attr && nodendx <= Z_LVAL_P(member)) {
796+
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
797+
if (nodendx == Z_LVAL_P(member)) {
798+
xmlUnlinkNode((xmlNodePtr) attr);
799+
php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
800+
break;
801+
}
802+
nodendx++;
803+
}
804+
attr = attr->next;
805+
}
806+
} else {
807+
while (attr) {
808+
anext = attr->next;
809+
if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
810+
xmlUnlinkNode((xmlNodePtr) attr);
811+
php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
812+
break;
813+
}
814+
attr = anext;
771815
}
772-
attr = anext;
773816
}
774817
}
775818

776819
if (elements) {
777-
node = node->children;
778-
while (node) {
779-
nnext = node->next;
780-
781-
SKIP_TEXT(node);
782-
783-
if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
820+
if (Z_TYPE_P(member) == IS_LONG) {
821+
if (sxe->iter.type == SXE_ITER_CHILD) {
822+
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
823+
}
824+
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
825+
if (node) {
784826
xmlUnlinkNode(node);
785827
php_libxml_node_free_resource(node TSRMLS_CC);
786828
}
829+
} else {
830+
node = node->children;
831+
while (node) {
832+
nnext = node->next;
833+
834+
SKIP_TEXT(node);
835+
836+
if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
837+
xmlUnlinkNode(node);
838+
php_libxml_node_free_resource(node TSRMLS_CC);
839+
}
787840

788841
next_iter:
789-
node = nnext;
842+
node = nnext;
843+
}
790844
}
791845
}
792846
}
@@ -1356,6 +1410,129 @@ SXE_METHOD(attributes)
13561410
}
13571411
/* }}} */
13581412

1413+
/* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [,string ns]])
1414+
Add Element with optional namespace information */
1415+
SXE_METHOD(addChild)
1416+
{
1417+
php_sxe_object *sxe;
1418+
char *qname, *value = NULL, *nsuri = NULL;
1419+
int qname_len, value_len = 0, nsuri_len = 0;
1420+
xmlNodePtr node, newnode;
1421+
xmlNsPtr nsptr = NULL;
1422+
xmlChar *localname, *prefix = NULL;
1423+
1424+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
1425+
&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1426+
return;
1427+
}
1428+
1429+
if (qname_len == 0) {
1430+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
1431+
return;
1432+
}
1433+
1434+
sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1435+
GET_NODE(sxe, node);
1436+
1437+
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
1438+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
1439+
return;
1440+
}
1441+
1442+
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1443+
1444+
localname = xmlSplitQName2(qname, &prefix);
1445+
if (localname == NULL) {
1446+
localname = xmlStrdup(qname);
1447+
}
1448+
1449+
1450+
newnode = xmlNewChild(node, NULL, localname, value);
1451+
1452+
if (nsuri != NULL) {
1453+
nsptr = xmlSearchNsByHref(node->doc, node, nsuri);
1454+
if (nsptr == NULL) {
1455+
nsptr = xmlNewNs(newnode, nsuri, prefix);
1456+
}
1457+
newnode->ns = nsptr;
1458+
}
1459+
1460+
_node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, localname, prefix TSRMLS_CC);
1461+
1462+
xmlFree(localname);
1463+
if (prefix != NULL) {
1464+
xmlFree(prefix);
1465+
}
1466+
}
1467+
/* }}} */
1468+
1469+
/* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1470+
Add Attribute with optional namespace information */
1471+
SXE_METHOD(addAttribute)
1472+
{
1473+
php_sxe_object *sxe;
1474+
char *qname, *value = NULL, *nsuri = NULL;
1475+
int qname_len, value_len = 0, nsuri_len = 0;
1476+
xmlNodePtr node;
1477+
xmlAttrPtr attrp = NULL;
1478+
xmlNsPtr nsptr = NULL;
1479+
xmlChar *localname, *prefix = NULL;
1480+
1481+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
1482+
&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
1483+
return;
1484+
}
1485+
1486+
if (qname_len == 0 || value_len == 0) {
1487+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name and value are required");
1488+
return;
1489+
}
1490+
1491+
sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
1492+
GET_NODE(sxe, node);
1493+
1494+
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
1495+
1496+
if (node->type != XML_ELEMENT_NODE) {
1497+
node = node->parent;
1498+
}
1499+
1500+
if (node == NULL) {
1501+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
1502+
return;
1503+
}
1504+
1505+
localname = xmlSplitQName2(qname, &prefix);
1506+
if (localname == NULL) {
1507+
localname = xmlStrdup(qname);
1508+
}
1509+
1510+
attrp = xmlHasNsProp(node, localname, nsuri);
1511+
if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
1512+
xmlFree(localname);
1513+
if (prefix != NULL) {
1514+
xmlFree(prefix);
1515+
}
1516+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
1517+
return;
1518+
}
1519+
1520+
if (nsuri != NULL) {
1521+
nsptr = xmlSearchNsByHref(node->doc, node, nsuri);
1522+
if (nsptr == NULL) {
1523+
nsptr = xmlNewNs(node, nsuri, prefix);
1524+
}
1525+
}
1526+
1527+
attrp = xmlNewNsProp(node, nsptr, localname, value);
1528+
1529+
xmlFree(localname);
1530+
if (prefix != NULL) {
1531+
xmlFree(prefix);
1532+
}
1533+
}
1534+
/* }}} */
1535+
13591536
/* {{{ cast_object()
13601537
*/
13611538
static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
@@ -2059,6 +2236,8 @@ static zend_function_entry sxe_functions[] = {
20592236
SXE_ME(getNamespaces, NULL, ZEND_ACC_PUBLIC)
20602237
SXE_ME(getDocNamespaces, NULL, ZEND_ACC_PUBLIC)
20612238
SXE_ME(getName, NULL, ZEND_ACC_PUBLIC)
2239+
SXE_ME(addChild, NULL, ZEND_ACC_PUBLIC)
2240+
SXE_ME(addAttribute, NULL, ZEND_ACC_PUBLIC)
20622241
{NULL, NULL, NULL}
20632242
};
20642243

ext/simplexml/tests/027.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ $people->person[3]['gender'] = 'error';
6161
</person>
6262
</people>
6363

64-
Warning: main(): Cannot add element person number 3 when only 2 such elements exist in %sext/simplexml/tests/027.php on line %d
64+
Warning: main(): Cannot add element person number 3 when only 2 such elements exist in %s027.php on line %d
6565
<people>
6666
<person gender="female">Jane
6767
</person>
@@ -71,4 +71,4 @@ Warning: main(): Cannot add element person number 3 when only 2 such elements ex
7171
</person>
7272
</people>
7373

74-
Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %sext/simplexml/tests/027.php on line %d
74+
Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %s027.php on line %d

ext/simplexml/tests/030.phpt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
SimpleXML: isset and unset by offset
3+
--SKIPIF--
4+
<?php if (!extension_loaded("simplexml")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
$xml =<<<EOF
8+
<root s:att1="b" att1="a"
9+
xmlns:s="urn::test" xmlns:t="urn::test-t">
10+
<child1>test</child1>
11+
<child1>test 2</child1>
12+
<s:child3 />
13+
</root>
14+
EOF;
15+
16+
$sxe = simplexml_load_string($xml);
17+
18+
echo $sxe->child1[0]."\n";
19+
echo $sxe->child1[1]."\n\n";
20+
21+
var_dump(isset($sxe->child1[1]));
22+
unset($sxe->child1[1]);
23+
var_dump(isset($sxe->child1[1]));
24+
echo "\n";
25+
26+
$atts = $sxe->attributes("urn::test");
27+
var_dump(isset($atts[0]));
28+
unset($atts[0]);
29+
var_dump(isset($atts[0]));
30+
var_dump(isset($atts[TRUE]));
31+
32+
?>
33+
===DONE===
34+
--EXPECT--
35+
test
36+
test 2
37+
38+
bool(true)
39+
bool(false)
40+
41+
bool(true)
42+
bool(false)
43+
bool(false)
44+
===DONE===

0 commit comments

Comments
 (0)