xref: /PHP-8.0/ext/soap/php_xml.c (revision c283c3ab)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.php.net/license/3_01.txt                                  |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
14   |          Shane Caraveo <shane@caraveo.com>                           |
15   |          Dmitry Stogov <dmitry@php.net>                              |
16   +----------------------------------------------------------------------+
17 */
18 
19 #include "php_soap.h"
20 #include "ext/libxml/php_libxml.h"
21 #include "libxml/parser.h"
22 #include "libxml/parserInternals.h"
23 
24 /* Channel libxml file io layer through the PHP streams subsystem.
25  * This allows use of ftps:// and https:// urls */
26 
is_blank(const xmlChar * str)27 static int is_blank(const xmlChar* str)
28 {
29 	while (*str != '\0') {
30 		if (*str != ' '  && *str != 0x9 && *str != 0xa && *str != 0xd) {
31 			return 0;
32 		}
33 		str++;
34 	}
35 	return 1;
36 }
37 
38 /* removes all empty text, comments and other insignoficant nodes */
cleanup_xml_node(xmlNodePtr node)39 static void cleanup_xml_node(xmlNodePtr node)
40 {
41 	xmlNodePtr trav;
42 	xmlNodePtr del = NULL;
43 
44 	trav = node->children;
45 	while (trav != NULL) {
46 		if (del != NULL) {
47 			xmlUnlinkNode(del);
48 			xmlFreeNode(del);
49 			del = NULL;
50 		}
51 		if (trav->type == XML_TEXT_NODE) {
52 			if (is_blank(trav->content)) {
53 				del = trav;
54 			}
55 		} else if ((trav->type != XML_ELEMENT_NODE) &&
56 		           (trav->type != XML_CDATA_SECTION_NODE)) {
57 			del = trav;
58 		} else if (trav->children != NULL) {
59 			cleanup_xml_node(trav);
60 		}
61 		trav = trav->next;
62 	}
63 	if (del != NULL) {
64 		xmlUnlinkNode(del);
65 		xmlFreeNode(del);
66 	}
67 }
68 
soap_ignorableWhitespace(void * ctx,const xmlChar * ch,int len)69 static void soap_ignorableWhitespace(void *ctx, const xmlChar *ch, int len)
70 {
71 }
72 
soap_Comment(void * ctx,const xmlChar * value)73 static void soap_Comment(void *ctx, const xmlChar *value)
74 {
75 }
76 
soap_xmlParseFile(const char * filename)77 xmlDocPtr soap_xmlParseFile(const char *filename)
78 {
79 	xmlParserCtxtPtr ctxt = NULL;
80 	xmlDocPtr ret;
81 	zend_bool old_allow_url_fopen;
82 
83 /*
84 	xmlInitParser();
85 */
86 
87 	old_allow_url_fopen = PG(allow_url_fopen);
88 	PG(allow_url_fopen) = 1;
89 	ctxt = xmlCreateFileParserCtxt(filename);
90 	PG(allow_url_fopen) = old_allow_url_fopen;
91 	if (ctxt) {
92 		zend_bool old;
93 
94 		php_libxml_sanitize_parse_ctxt_options(ctxt);
95 		ctxt->keepBlanks = 0;
96 		ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
97 		ctxt->sax->comment = soap_Comment;
98 		ctxt->sax->warning = NULL;
99 		ctxt->sax->error = NULL;
100 		/*ctxt->sax->fatalError = NULL;*/
101 		ctxt->options |= XML_PARSE_HUGE;
102 		old = php_libxml_disable_entity_loader(1);
103 		xmlParseDocument(ctxt);
104 		php_libxml_disable_entity_loader(old);
105 		if (ctxt->wellFormed) {
106 			ret = ctxt->myDoc;
107 			if (ret->URL == NULL && ctxt->directory != NULL) {
108 				ret->URL = xmlCharStrdup(ctxt->directory);
109 			}
110 		} else {
111 			ret = NULL;
112 			xmlFreeDoc(ctxt->myDoc);
113 			ctxt->myDoc = NULL;
114 		}
115 		xmlFreeParserCtxt(ctxt);
116 	} else {
117 		ret = NULL;
118 	}
119 
120 /*
121 	xmlCleanupParser();
122 */
123 
124 	if (ret) {
125 		cleanup_xml_node((xmlNodePtr)ret);
126 	}
127 	return ret;
128 }
129 
soap_xmlParseMemory(const void * buf,size_t buf_size)130 xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
131 {
132 	xmlParserCtxtPtr ctxt = NULL;
133 	xmlDocPtr ret;
134 
135 
136 /*
137 	xmlInitParser();
138 */
139 	ctxt = xmlCreateMemoryParserCtxt(buf, buf_size);
140 	if (ctxt) {
141 		zend_bool old;
142 
143 		php_libxml_sanitize_parse_ctxt_options(ctxt);
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