xref: /PHP-7.4/ext/soap/php_xml.c (revision 3c939e3f)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) The PHP Group                                          |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
16   |          Shane Caraveo <shane@caraveo.com>                           |
17   |          Dmitry Stogov <dmitry@php.net>                              |
18   +----------------------------------------------------------------------+
19 */
20 
21 #include "php_soap.h"
22 #include "ext/libxml/php_libxml.h"
23 #include "libxml/parser.h"
24 #include "libxml/parserInternals.h"
25 
26 /* Channel libxml file io layer through the PHP streams subsystem.
27  * This allows use of ftps:// and https:// urls */
28 
is_blank(const xmlChar * str)29 static int is_blank(const xmlChar* str)
30 {
31 	while (*str != '\0') {
32 		if (*str != ' '  && *str != 0x9 && *str != 0xa && *str != 0xd) {
33 			return 0;
34 		}
35 		str++;
36 	}
37 	return 1;
38 }
39 
40 /* removes all empty text, comments and other insignoficant nodes */
cleanup_xml_node(xmlNodePtr node)41 static void cleanup_xml_node(xmlNodePtr node)
42 {
43 	xmlNodePtr trav;
44 	xmlNodePtr del = NULL;
45 
46 	trav = node->children;
47 	while (trav != NULL) {
48 		if (del != NULL) {
49 			xmlUnlinkNode(del);
50 			xmlFreeNode(del);
51 			del = NULL;
52 		}
53 		if (trav->type == XML_TEXT_NODE) {
54 			if (is_blank(trav->content)) {
55 				del = trav;
56 			}
57 		} else if ((trav->type != XML_ELEMENT_NODE) &&
58 		           (trav->type != XML_CDATA_SECTION_NODE)) {
59 			del = trav;
60 		} else if (trav->children != NULL) {
61 			cleanup_xml_node(trav);
62 		}
63 		trav = trav->next;
64 	}
65 	if (del != NULL) {
66 		xmlUnlinkNode(del);
67 		xmlFreeNode(del);
68 	}
69 }
70 
soap_ignorableWhitespace(void * ctx,const xmlChar * ch,int len)71 static void soap_ignorableWhitespace(void *ctx, const xmlChar *ch, int len)
72 {
73 }
74 
soap_Comment(void * ctx,const xmlChar * value)75 static void soap_Comment(void *ctx, const xmlChar *value)
76 {
77 }
78 
soap_xmlParseFile(const char * filename)79 xmlDocPtr soap_xmlParseFile(const char *filename)
80 {
81 	xmlParserCtxtPtr ctxt = NULL;
82 	xmlDocPtr ret;
83 	zend_bool old_allow_url_fopen;
84 
85 /*
86 	xmlInitParser();
87 */
88 
89 	old_allow_url_fopen = PG(allow_url_fopen);
90 	PG(allow_url_fopen) = 1;
91 	ctxt = xmlCreateFileParserCtxt(filename);
92 	PG(allow_url_fopen) = old_allow_url_fopen;
93 	if (ctxt) {
94 		zend_bool old;
95 
96 		ctxt->keepBlanks = 0;
97 		ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
98 		ctxt->sax->comment = soap_Comment;
99 		ctxt->sax->warning = NULL;
100 		ctxt->sax->error = NULL;
101 		/*ctxt->sax->fatalError = NULL;*/
102 		ctxt->options |= XML_PARSE_HUGE;
103 		old = php_libxml_disable_entity_loader(1);
104 		xmlParseDocument(ctxt);
105 		php_libxml_disable_entity_loader(old);
106 		if (ctxt->wellFormed) {
107 			ret = ctxt->myDoc;
108 			if (ret->URL == NULL && ctxt->directory != NULL) {
109 				ret->URL = xmlCharStrdup(ctxt->directory);
110 			}
111 		} else {
112 			ret = NULL;
113 			xmlFreeDoc(ctxt->myDoc);
114 			ctxt->myDoc = NULL;
115 		}
116 		xmlFreeParserCtxt(ctxt);
117 	} else {
118 		ret = NULL;
119 	}
120 
121 /*
122 	xmlCleanupParser();
123 */
124 
125 	if (ret) {
126 		cleanup_xml_node((xmlNodePtr)ret);
127 	}
128 	return ret;
129 }
130 
soap_xmlParseMemory(const void * buf,size_t buf_size)131 xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
132 {
133 	xmlParserCtxtPtr ctxt = NULL;
134 	xmlDocPtr ret;
135 
136 
137 /*
138 	xmlInitParser();
139 */
140 	ctxt = xmlCreateMemoryParserCtxt(buf, buf_size);
141 	if (ctxt) {
142 		zend_bool old;
143 
144 		ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
145 		ctxt->sax->comment = soap_Comment;
146 		ctxt->sax->warning = NULL;
147 		ctxt->sax->error = NULL;
148 		/*ctxt->sax->fatalError = NULL;*/
149 		ctxt->options |= XML_PARSE_HUGE;
150 		old = php_libxml_disable_entity_loader(1);
151 		xmlParseDocument(ctxt);
152 		php_libxml_disable_entity_loader(old);
153 		if (ctxt->wellFormed) {
154 			ret = ctxt->myDoc;
155 			if (ret->URL == NULL && ctxt->directory != NULL) {
156 				ret->URL = xmlCharStrdup(ctxt->directory);
157 			}
158 		} else {
159 			ret = NULL;
160 			xmlFreeDoc(ctxt->myDoc);
161 			ctxt->myDoc = NULL;
162 		}
163 		xmlFreeParserCtxt(ctxt);
164 	} else {
165 		ret = NULL;
166 	}
167 
168 /*
169 	xmlCleanupParser();
170 */
171 
172 /*
173 	if (ret) {
174 		cleanup_xml_node((xmlNodePtr)ret);
175 	}
176 */
177 	return ret;
178 }
179 
attr_find_ns(xmlAttrPtr node)180 xmlNsPtr attr_find_ns(xmlAttrPtr node)
181 {
182 	if (node->ns) {
183 		return node->ns;
184 	} else if (node->parent->ns) {
185 		return node->parent->ns;
186 	} else {
187 		return xmlSearchNs(node->doc, node->parent, NULL);
188 	}
189 }
190 
node_find_ns(xmlNodePtr node)191 xmlNsPtr node_find_ns(xmlNodePtr node)
192 {
193 	if (node->ns) {
194 		return node->ns;
195 	} else {
196 		return xmlSearchNs(node->doc, node, NULL);
197 	}
198 }
199 
attr_is_equal_ex(xmlAttrPtr node,char * name,char * ns)200 int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns)
201 {
202 	if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
203 		if (ns) {
204 			xmlNsPtr nsPtr = attr_find_ns(node);
205 			if (nsPtr) {
206 				return (strcmp((char*)nsPtr->href, ns) == 0);
207 			} else {
208 				return FALSE;
209 			}
210 		}
211 		return TRUE;
212 	}
213 	return FALSE;
214 }
215 
node_is_equal_ex(xmlNodePtr node,char * name,char * ns)216 int node_is_equal_ex(xmlNodePtr node, char *name, char *ns)
217 {
218 	if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
219 		if (ns) {
220 			xmlNsPtr nsPtr = node_find_ns(node);
221 			if (nsPtr) {
222 				return (strcmp((char*)nsPtr->href, ns) == 0);
223 			} else {
224 				return FALSE;
225 			}
226 		}
227 		return TRUE;
228 	}
229 	return FALSE;
230 }
231 
232 
get_attribute_ex(xmlAttrPtr node,char * name,char * ns)233 xmlAttrPtr get_attribute_ex(xmlAttrPtr node, char *name, char *ns)
234 {
235 	while (node!=NULL) {
236 		if (attr_is_equal_ex(node, name, ns)) {
237 			return node;
238 		}
239 		node = node->next;
240 	}
241 	return NULL;
242 }
243 
get_node_ex(xmlNodePtr node,char * name,char * ns)244 xmlNodePtr get_node_ex(xmlNodePtr node, char *name, char *ns)
245 {
246 	while (node!=NULL) {
247 		if (node_is_equal_ex(node, name, ns)) {
248 			return node;
249 		}
250 		node = node->next;
251 	}
252 	return NULL;
253 }
254 
get_node_recurisve_ex(xmlNodePtr node,char * name,char * ns)255 xmlNodePtr get_node_recurisve_ex(xmlNodePtr node, char *name, char *ns)
256 {
257 	while (node != NULL) {
258 		if (node_is_equal_ex(node, name, ns)) {
259 			return node;
260 		} else if (node->children != NULL) {
261 			xmlNodePtr tmp = get_node_recurisve_ex(node->children, name, ns);
262 			if (tmp) {
263 				return tmp;
264 			}
265 		}
266 		node = node->next;
267 	}
268 	return NULL;
269 }
270 
get_node_with_attribute_ex(xmlNodePtr node,char * name,char * name_ns,char * attribute,char * value,char * attr_ns)271 xmlNodePtr get_node_with_attribute_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns)
272 {
273 	xmlAttrPtr attr;
274 
275 	while (node != NULL) {
276 		if (name != NULL) {
277 			node = get_node_ex(node, name, name_ns);
278 			if (node==NULL) {
279 				return NULL;
280 			}
281 		}
282 
283 		attr = get_attribute_ex(node->properties, attribute, attr_ns);
284 		if (attr != NULL && strcmp((char*)attr->children->content, value) == 0) {
285 			return node;
286 		}
287 		node = node->next;
288 	}
289 	return NULL;
290 }
291 
get_node_with_attribute_recursive_ex(xmlNodePtr node,char * name,char * name_ns,char * attribute,char * value,char * attr_ns)292 xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns)
293 {
294 	while (node != NULL) {
295 		if (node_is_equal_ex(node, name, name_ns)) {
296 			xmlAttrPtr attr = get_attribute_ex(node->properties, attribute, attr_ns);
297 			if (attr != NULL && strcmp((char*)attr->children->content, value) == 0) {
298 				return node;
299 			}
300 		}
301 		if (node->children != NULL) {
302 			xmlNodePtr tmp = get_node_with_attribute_recursive_ex(node->children, name, name_ns, attribute, value, attr_ns);
303 			if (tmp) {
304 				return tmp;
305 			}
306 		}
307 		node = node->next;
308 	}
309 	return NULL;
310 }
311 
parse_namespace(const xmlChar * inval,char ** value,char ** namespace)312 int parse_namespace(const xmlChar *inval, char **value, char **namespace)
313 {
314 	char *found = strrchr((char*)inval, ':');
315 
316 	if (found != NULL && found != (char*)inval) {
317 		(*namespace) = estrndup((char*)inval, found - (char*)inval);
318 		(*value) = estrdup(++found);
319 	} else {
320 		(*value) = estrdup((char*)inval);
321 		(*namespace) = NULL;
322 	}
323 
324 	return FALSE;
325 }
326