xref: /PHP-7.3/ext/soap/php_xml.c (revision 3c939e3f)
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@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 #if LIBXML_VERSION >= 20703
103 		ctxt->options |= XML_PARSE_HUGE;
104 #endif
105 		old = php_libxml_disable_entity_loader(1);
106 		xmlParseDocument(ctxt);
107 		php_libxml_disable_entity_loader(old);
108 		if (ctxt->wellFormed) {
109 			ret = ctxt->myDoc;
110 			if (ret->URL == NULL && ctxt->directory != NULL) {
111 				ret->URL = xmlCharStrdup(ctxt->directory);
112 			}
113 		} else {
114 			ret = NULL;
115 			xmlFreeDoc(ctxt->myDoc);
116 			ctxt->myDoc = NULL;
117 		}
118 		xmlFreeParserCtxt(ctxt);
119 	} else {
120 		ret = NULL;
121 	}
122 
123 /*
124 	xmlCleanupParser();
125 */
126 
127 	if (ret) {
128 		cleanup_xml_node((xmlNodePtr)ret);
129 	}
130 	return ret;
131 }
132 
soap_xmlParseMemory(const void * buf,size_t buf_size)133 xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
134 {
135 	xmlParserCtxtPtr ctxt = NULL;
136 	xmlDocPtr ret;
137 
138 
139 /*
140 	xmlInitParser();
141 */
142 	ctxt = xmlCreateMemoryParserCtxt(buf, buf_size);
143 	if (ctxt) {
144 		zend_bool old;
145 
146 		ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
147 		ctxt->sax->comment = soap_Comment;
148 		ctxt->sax->warning = NULL;
149 		ctxt->sax->error = NULL;
150 		/*ctxt->sax->fatalError = NULL;*/
151 #if LIBXML_VERSION >= 20703
152 		ctxt->options |= XML_PARSE_HUGE;
153 #endif
154 		old = php_libxml_disable_entity_loader(1);
155 		xmlParseDocument(ctxt);
156 		php_libxml_disable_entity_loader(old);
157 		if (ctxt->wellFormed) {
158 			ret = ctxt->myDoc;
159 			if (ret->URL == NULL && ctxt->directory != NULL) {
160 				ret->URL = xmlCharStrdup(ctxt->directory);
161 			}
162 		} else {
163 			ret = NULL;
164 			xmlFreeDoc(ctxt->myDoc);
165 			ctxt->myDoc = NULL;
166 		}
167 		xmlFreeParserCtxt(ctxt);
168 	} else {
169 		ret = NULL;
170 	}
171 
172 /*
173 	xmlCleanupParser();
174 */
175 
176 /*
177 	if (ret) {
178 		cleanup_xml_node((xmlNodePtr)ret);
179 	}
180 */
181 	return ret;
182 }
183 
attr_find_ns(xmlAttrPtr node)184 xmlNsPtr attr_find_ns(xmlAttrPtr node)
185 {
186 	if (node->ns) {
187 		return node->ns;
188 	} else if (node->parent->ns) {
189 		return node->parent->ns;
190 	} else {
191 		return xmlSearchNs(node->doc, node->parent, NULL);
192 	}
193 }
194 
node_find_ns(xmlNodePtr node)195 xmlNsPtr node_find_ns(xmlNodePtr node)
196 {
197 	if (node->ns) {
198 		return node->ns;
199 	} else {
200 		return xmlSearchNs(node->doc, node, NULL);
201 	}
202 }
203 
attr_is_equal_ex(xmlAttrPtr node,char * name,char * ns)204 int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns)
205 {
206 	if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
207 		if (ns) {
208 			xmlNsPtr nsPtr = attr_find_ns(node);
209 			if (nsPtr) {
210 				return (strcmp((char*)nsPtr->href, ns) == 0);
211 			} else {
212 				return FALSE;
213 			}
214 		}
215 		return TRUE;
216 	}
217 	return FALSE;
218 }
219 
node_is_equal_ex(xmlNodePtr node,char * name,char * ns)220 int node_is_equal_ex(xmlNodePtr node, char *name, char *ns)
221 {
222 	if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
223 		if (ns) {
224 			xmlNsPtr nsPtr = node_find_ns(node);
225 			if (nsPtr) {
226 				return (strcmp((char*)nsPtr->href, ns) == 0);
227 			} else {
228 				return FALSE;
229 			}
230 		}
231 		return TRUE;
232 	}
233 	return FALSE;
234 }
235 
236 
get_attribute_ex(xmlAttrPtr node,char * name,char * ns)237 xmlAttrPtr get_attribute_ex(xmlAttrPtr node, char *name, char *ns)
238 {
239 	while (node!=NULL) {
240 		if (attr_is_equal_ex(node, name, ns)) {
241 			return node;
242 		}
243 		node = node->next;
244 	}
245 	return NULL;
246 }
247 
get_node_ex(xmlNodePtr node,char * name,char * ns)248 xmlNodePtr get_node_ex(xmlNodePtr node, char *name, char *ns)
249 {
250 	while (node!=NULL) {
251 		if (node_is_equal_ex(node, name, ns)) {
252 			return node;
253 		}
254 		node = node->next;
255 	}
256 	return NULL;
257 }
258 
get_node_recurisve_ex(xmlNodePtr node,char * name,char * ns)259 xmlNodePtr get_node_recurisve_ex(xmlNodePtr node, char *name, char *ns)
260 {
261 	while (node != NULL) {
262 		if (node_is_equal_ex(node, name, ns)) {
263 			return node;
264 		} else if (node->children != NULL) {
265 			xmlNodePtr tmp = get_node_recurisve_ex(node->children, name, ns);
266 			if (tmp) {
267 				return tmp;
268 			}
269 		}
270 		node = node->next;
271 	}
272 	return NULL;
273 }
274 
get_node_with_attribute_ex(xmlNodePtr node,char * name,char * name_ns,char * attribute,char * value,char * attr_ns)275 xmlNodePtr get_node_with_attribute_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns)
276 {
277 	xmlAttrPtr attr;
278 
279 	while (node != NULL) {
280 		if (name != NULL) {
281 			node = get_node_ex(node, name, name_ns);
282 			if (node==NULL) {
283 				return NULL;
284 			}
285 		}
286 
287 		attr = get_attribute_ex(node->properties, attribute, attr_ns);
288 		if (attr != NULL && strcmp((char*)attr->children->content, value) == 0) {
289 			return node;
290 		}
291 		node = node->next;
292 	}
293 	return NULL;
294 }
295 
get_node_with_attribute_recursive_ex(xmlNodePtr node,char * name,char * name_ns,char * attribute,char * value,char * attr_ns)296 xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns)
297 {
298 	while (node != NULL) {
299 		if (node_is_equal_ex(node, name, name_ns)) {
300 			xmlAttrPtr attr = get_attribute_ex(node->properties, attribute, attr_ns);
301 			if (attr != NULL && strcmp((char*)attr->children->content, value) == 0) {
302 				return node;
303 			}
304 		}
305 		if (node->children != NULL) {
306 			xmlNodePtr tmp = get_node_with_attribute_recursive_ex(node->children, name, name_ns, attribute, value, attr_ns);
307 			if (tmp) {
308 				return tmp;
309 			}
310 		}
311 		node = node->next;
312 	}
313 	return NULL;
314 }
315 
parse_namespace(const xmlChar * inval,char ** value,char ** namespace)316 int parse_namespace(const xmlChar *inval, char **value, char **namespace)
317 {
318 	char *found = strrchr((char*)inval, ':');
319 
320 	if (found != NULL && found != (char*)inval) {
321 		(*namespace) = estrndup((char*)inval, found - (char*)inval);
322 		(*value) = estrdup(++found);
323 	} else {
324 		(*value) = estrdup((char*)inval);
325 		(*namespace) = NULL;
326 	}
327 
328 	return FALSE;
329 }
330