xref: /PHP-7.4/ext/dom/domimplementation.c (revision f15f8fc5)
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: Christian Stocker <chregu@php.net>                          |
16    |          Rob Richards <rrichards@php.net>                            |
17    +----------------------------------------------------------------------+
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "php.h"
25 #if HAVE_LIBXML && HAVE_DOM
26 #include "php_dom.h"
27 
28 /* {{{ arginfo */
29 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_implementation_get_feature, 0, 0, 2)
30 	ZEND_ARG_INFO(0, feature)
31 	ZEND_ARG_INFO(0, version)
32 ZEND_END_ARG_INFO();
33 
34 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_implementation_has_feature, 0, 0, 0)
35 ZEND_END_ARG_INFO();
36 
37 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_implementation_create_documenttype, 0, 0, 3)
38 	ZEND_ARG_INFO(0, qualifiedName)
39 	ZEND_ARG_INFO(0, publicId)
40 	ZEND_ARG_INFO(0, systemId)
41 ZEND_END_ARG_INFO();
42 
43 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_implementation_create_document, 0, 0, 2)
44 	ZEND_ARG_INFO(0, namespaceURI)
45 	ZEND_ARG_INFO(0, qualifiedName)
46 	ZEND_ARG_OBJ_INFO(0, docType, DOMDocumentType, 0)
47 ZEND_END_ARG_INFO();
48 /* }}} */
49 
50 /*
51 * class DOMImplementation
52 *
53 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-102161490
54 * Since:
55 */
56 
57 const zend_function_entry php_dom_domimplementation_class_functions[] = {
58 	PHP_ME(domimplementation, getFeature, arginfo_dom_implementation_get_feature, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
59 	PHP_ME(domimplementation, hasFeature, arginfo_dom_implementation_has_feature, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
60 	PHP_ME(domimplementation, createDocumentType, arginfo_dom_implementation_create_documenttype, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
61 	PHP_ME(domimplementation, createDocument, arginfo_dom_implementation_create_document, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
62 	PHP_FE_END
63 };
64 
65 /* {{{ proto bool dom_domimplementation_has_feature(string feature, string version);
66 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-5CED94D7
67 Since:
68 */
PHP_METHOD(domimplementation,hasFeature)69 PHP_METHOD(domimplementation, hasFeature)
70 {
71 	size_t feature_len, version_len;
72 	char *feature, *version;
73 
74 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &feature, &feature_len, &version, &version_len) == FAILURE) {
75 		return;
76 	}
77 
78 	if (dom_has_feature(feature, version)) {
79 		RETURN_TRUE;
80 	} else {
81 		RETURN_FALSE;
82 	}
83 }
84 /* }}} end dom_domimplementation_has_feature */
85 
86 /* {{{ proto DOMDocumentType dom_domimplementation_create_document_type(string qualifiedName, string publicId, string systemId);
87 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocType
88 Since: DOM Level 2
89 */
PHP_METHOD(domimplementation,createDocumentType)90 PHP_METHOD(domimplementation, createDocumentType)
91 {
92 	xmlDtd *doctype;
93 	int ret;
94 	size_t name_len = 0, publicid_len = 0, systemid_len = 0;
95 	char *name = NULL, *publicid = NULL, *systemid = NULL;
96 	xmlChar *pch1 = NULL, *pch2 = NULL, *localname = NULL;
97 	xmlURIPtr uri;
98 
99 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &name, &name_len, &publicid, &publicid_len, &systemid, &systemid_len) == FAILURE) {
100 		return;
101 	}
102 
103 	if (name_len == 0) {
104 		php_error_docref(NULL, E_WARNING, "qualifiedName is required");
105 		RETURN_FALSE;
106 	}
107 
108 	if (publicid_len > 0) {
109 		pch1 = (xmlChar *) publicid;
110 	}
111 	if (systemid_len > 0) {
112 		pch2 = (xmlChar *) systemid;
113 	}
114 
115 	if (strstr(name, "%00")) {
116 		php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
117 		RETURN_FALSE;
118 	}
119 
120 	uri = xmlParseURI(name);
121 	if (uri != NULL && uri->opaque != NULL) {
122 		localname = xmlStrdup((xmlChar *) uri->opaque);
123 		if (xmlStrchr(localname, (xmlChar) ':') != NULL) {
124 			php_dom_throw_error(NAMESPACE_ERR, 1);
125 			xmlFreeURI(uri);
126 			xmlFree(localname);
127 			RETURN_FALSE;
128 		}
129 	} else {
130 		localname = xmlStrdup((xmlChar *) name);
131 	}
132 
133 	/* TODO: Test that localname has no invalid chars
134 	php_dom_throw_error(INVALID_CHARACTER_ERR,);
135 	*/
136 
137 	if (uri) {
138 		xmlFreeURI(uri);
139 	}
140 
141 	doctype = xmlCreateIntSubset(NULL, localname, pch1, pch2);
142 	xmlFree(localname);
143 
144 	if (doctype == NULL) {
145 		php_error_docref(NULL, E_WARNING, "Unable to create DocumentType");
146 		RETURN_FALSE;
147 	}
148 
149 	DOM_RET_OBJ((xmlNodePtr) doctype, &ret, NULL);
150 }
151 /* }}} end dom_domimplementation_create_document_type */
152 
153 /* {{{ proto DOMDocument dom_domimplementation_create_document(string namespaceURI, string qualifiedName, DOMDocumentType doctype);
154 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocument
155 Since: DOM Level 2
156 */
PHP_METHOD(domimplementation,createDocument)157 PHP_METHOD(domimplementation, createDocument)
158 {
159 	zval *node = NULL;
160 	xmlDoc *docp;
161 	xmlNode *nodep;
162 	xmlDtdPtr doctype = NULL;
163 	xmlNsPtr nsptr = NULL;
164 	int ret, errorcode = 0;
165 	size_t uri_len = 0, name_len = 0;
166 	char *uri = NULL, *name = NULL;
167 	char *prefix = NULL, *localname = NULL;
168 	dom_object *doctobj;
169 
170 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssO", &uri, &uri_len, &name, &name_len, &node, dom_documenttype_class_entry) == FAILURE) {
171 		return;
172 	}
173 
174 	if (node != NULL) {
175 		DOM_GET_OBJ(doctype, node, xmlDtdPtr, doctobj);
176 		if (doctype->type == XML_DOCUMENT_TYPE_NODE) {
177 			php_error_docref(NULL, E_WARNING, "Invalid DocumentType object");
178 			RETURN_FALSE;
179 		}
180 		if (doctype->doc != NULL) {
181 			php_dom_throw_error(WRONG_DOCUMENT_ERR, 1);
182 			RETURN_FALSE;
183 		}
184 	} else {
185 		doctobj = NULL;
186 	}
187 
188 	if (name_len > 0) {
189 		errorcode = dom_check_qname(name, &localname, &prefix, 1, name_len);
190 		if (errorcode == 0 && uri_len > 0
191 			&& ((nsptr = xmlNewNs(NULL, (xmlChar *) uri, (xmlChar *) prefix)) == NULL)
192 		) {
193 			errorcode = NAMESPACE_ERR;
194 		}
195 	}
196 
197 	if (prefix != NULL) {
198 		xmlFree(prefix);
199 	}
200 
201 	if (errorcode != 0) {
202 		if (localname != NULL) {
203 			xmlFree(localname);
204 		}
205 		php_dom_throw_error(errorcode, 1);
206 		RETURN_FALSE;
207 	}
208 
209 	/* currently letting libxml2 set the version string */
210 	docp = xmlNewDoc(NULL);
211 	if (!docp) {
212 		if (localname != NULL) {
213 			xmlFree(localname);
214 		}
215 		RETURN_FALSE;
216 	}
217 
218 	if (doctype != NULL) {
219 		docp->intSubset = doctype;
220 		doctype->parent = docp;
221 		doctype->doc = docp;
222 		docp->children = (xmlNodePtr) doctype;
223 		docp->last = (xmlNodePtr) doctype;
224 	}
225 
226 	if (localname != NULL) {
227 		nodep = xmlNewDocNode(docp, nsptr, (xmlChar *) localname, NULL);
228 		if (!nodep) {
229 			if (doctype != NULL) {
230 				docp->intSubset = NULL;
231 				doctype->parent = NULL;
232 				doctype->doc = NULL;
233 				docp->children = NULL;
234 				docp->last = NULL;
235 			}
236 			xmlFreeDoc(docp);
237 			xmlFree(localname);
238 			/* Need some type of error here */
239 			php_error_docref(NULL, E_WARNING, "Unexpected Error");
240 			RETURN_FALSE;
241 		}
242 
243 		nodep->nsDef = nsptr;
244 
245 		xmlDocSetRootElement(docp, nodep);
246 		xmlFree(localname);
247 	}
248 
249 	DOM_RET_OBJ((xmlNodePtr) docp, &ret, NULL);
250 
251 	if (doctobj != NULL) {
252 		doctobj->document = ((dom_object *)((php_libxml_node_ptr *)docp->_private)->_private)->document;
253 		php_libxml_increment_doc_ref((php_libxml_node_object *)doctobj, docp);
254 	}
255 }
256 /* }}} end dom_domimplementation_create_document */
257 
258 /* {{{ proto DOMNode dom_domimplementation_get_feature(string feature, string version);
259 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#DOMImplementation3-getFeature
260 Since: DOM Level 3
261 */
PHP_METHOD(domimplementation,getFeature)262 PHP_METHOD(domimplementation, getFeature)
263 {
264  DOM_NOT_IMPLEMENTED();
265 }
266 /* }}} end dom_domimplementation_get_feature */
267 
268 #endif
269