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