php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
domimplementation.c
Go to the documentation of this file.
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 | https://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: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16*/
17
18#ifdef HAVE_CONFIG_H
19#include <config.h>
20#endif
21
22#include "php.h"
23#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24#include "php_dom.h"
25#include "namespace_compat.h"
26#include "private_data.h"
27
28/*
29* class DOMImplementation
30*
31* URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-102161490
32* Since:
33*/
34
35/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-5CED94D7
36Since:
37*/
39{
40 zend_string *feature, *version;
41
42 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &feature, &version) == FAILURE) {
44 }
45
46 RETURN_BOOL(dom_has_feature(feature, version));
47}
48/* }}} end dom_domimplementation_has_feature */
49
50/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocType
51Modern URL: https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
52Since: DOM Level 2
53*/
54PHP_METHOD(DOMImplementation, createDocumentType)
55{
56 xmlDtd *doctype;
57 size_t name_len = 0, publicid_len = 0, systemid_len = 0;
58 char *name = NULL, *publicid = NULL, *systemid = NULL;
59 xmlChar *pch1 = NULL, *pch2 = NULL, *localname = NULL;
60 xmlURIPtr uri;
61
62 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", &name, &name_len, &publicid, &publicid_len, &systemid, &systemid_len) == FAILURE) {
64 }
65
66 if (name_len == 0) {
69 }
70
71 if (publicid_len > 0) {
72 pch1 = BAD_CAST publicid;
73 }
74 if (systemid_len > 0) {
75 pch2 = BAD_CAST systemid;
76 }
77
78 if (strstr(name, "%00")) {
79 php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes");
81 }
82
83 uri = xmlParseURI(name);
84 if (uri != NULL && uri->opaque != NULL) {
85 localname = xmlStrdup(BAD_CAST uri->opaque);
86 if (xmlStrchr(localname, (xmlChar) ':') != NULL) {
88 xmlFreeURI(uri);
89 xmlFree(localname);
91 }
92 } else {
93 localname = xmlStrdup(BAD_CAST name);
94 }
95
96 if (uri) {
97 xmlFreeURI(uri);
98 }
99
100 doctype = xmlCreateIntSubset(NULL, localname, pch1, pch2);
101 xmlFree(localname);
102
103 if (doctype == NULL) {
104 php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
106 }
107
108 DOM_RET_OBJ((xmlNodePtr) doctype, NULL);
109}
110
111PHP_METHOD(Dom_Implementation, createDocumentType)
112{
113 size_t name_len, publicid_len = 0, systemid_len = 0;
114 const char *name, *publicid = NULL, *systemid = NULL;
115
116 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppp", &name, &name_len, &publicid, &publicid_len, &systemid, &systemid_len) != SUCCESS) {
118 }
119
120 /* 1. Validate qualifiedName. */
121 if (xmlValidateQName(BAD_CAST name, 0) != 0) {
124 }
125
126 /* 2. Return a new doctype, with qualifiedName as its name, publicId as its public ID, and systemId as its system ID ... */
127 xmlDtdPtr doctype = xmlCreateIntSubset(
128 NULL,
129 BAD_CAST name,
130 publicid_len ? BAD_CAST publicid : NULL,
131 systemid_len ? BAD_CAST systemid : NULL
132 );
133 if (UNEXPECTED(doctype == NULL)) {
136 }
137
141 (xmlNodePtr) doctype,
142 NULL
143 );
144}
145/* }}} end dom_domimplementation_create_document_type */
146
147/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocument
148Since: DOM Level 2
149*/
150PHP_METHOD(DOMImplementation, createDocument)
151{
152 zval *node = NULL;
153 xmlDoc *docp;
154 xmlNode *nodep;
155 xmlDtdPtr doctype = NULL;
156 xmlNsPtr nsptr = NULL;
157 int errorcode = 0;
158 size_t uri_len = 0, name_len = 0;
159 char *uri = NULL, *name = NULL;
160 char *prefix = NULL, *localname = NULL;
161 dom_object *doctobj;
162
163 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!sO!", &uri, &uri_len, &name, &name_len, &node, dom_documenttype_class_entry) == FAILURE) {
165 }
166
167 if (node != NULL) {
168 DOM_GET_OBJ(doctype, node, xmlDtdPtr, doctobj);
169 if (doctype->type == XML_DOCUMENT_TYPE_NODE) {
170 zend_argument_value_error(3, "is an invalid DocumentType object");
172 }
173 if (doctype->doc != NULL) {
174 /* As the new document is the context node, and the default for strict error checking
175 * is true, this will always throw. */
178 }
179 } else {
180 doctobj = NULL;
181 }
182
183 if (name_len > 0) {
184 errorcode = dom_check_qname(name, &localname, &prefix, 1, name_len);
185 if (errorcode == 0 && uri_len > 0
186 && ((nsptr = xmlNewNs(NULL, BAD_CAST uri, BAD_CAST prefix)) == NULL)
187 ) {
188 errorcode = NAMESPACE_ERR;
189 }
190 }
191
192 if (prefix != NULL) {
193 xmlFree(prefix);
194 }
195
196 if (errorcode != 0) {
197 if (localname != NULL) {
198 xmlFree(localname);
199 }
200 php_dom_throw_error(errorcode, true);
202 }
203
204 /* currently letting libxml2 set the version string */
205 docp = xmlNewDoc(NULL);
206 if (!docp) {
207 if (localname != NULL) {
208 xmlFree(localname);
209 }
210 /* See above for strict error checking argument. */
211 php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
213 }
214
215 if (doctype != NULL) {
216 docp->intSubset = doctype;
217 doctype->parent = docp;
218 doctype->doc = docp;
219 docp->children = (xmlNodePtr) doctype;
220 docp->last = (xmlNodePtr) doctype;
221 }
222
223 if (localname != NULL) {
224 nodep = xmlNewDocNode(docp, nsptr, BAD_CAST localname, NULL);
225 if (!nodep) {
226 if (doctype != NULL) {
227 docp->intSubset = NULL;
228 doctype->parent = NULL;
229 doctype->doc = NULL;
230 docp->children = NULL;
231 docp->last = NULL;
232 }
233 xmlFreeDoc(docp);
234 xmlFree(localname);
235 php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
237 }
238
239 nodep->nsDef = nsptr;
240
241 xmlDocSetRootElement(docp, nodep);
242 xmlFree(localname);
243 }
244
245 DOM_RET_OBJ((xmlNodePtr) docp, NULL);
246
247 if (doctobj != NULL) {
248 doctobj->document = ((dom_object *)((php_libxml_node_ptr *)docp->_private)->_private)->document;
249 php_libxml_increment_doc_ref((php_libxml_node_object *)doctobj, docp);
250 }
251}
252
253PHP_METHOD(Dom_Implementation, createDocument)
254{
255 zval *dtd = NULL;
256 xmlDtdPtr doctype = NULL;
257 zend_string *uri = NULL, *qualified_name = zend_empty_string;
258 dom_object *doctobj;
259
260 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P!P|O!", &uri, &qualified_name, &dtd, dom_modern_documenttype_class_entry) != SUCCESS) {
262 }
263
264 if (dtd != NULL) {
265 DOM_GET_OBJ(doctype, dtd, xmlDtdPtr, doctobj);
266 }
267
268 xmlDocPtr document = NULL;
269 xmlChar *localname = NULL, *prefix = NULL;
272
273 /* 1. Let document be a new XMLDocument. */
274 document = xmlNewDoc(BAD_CAST "1.0");
275 if (UNEXPECTED(document == NULL)) {
276 goto oom;
277 }
278 document->encoding = xmlStrdup(BAD_CAST "UTF-8");
279
280 /* 2. Let element be null. */
281 xmlNodePtr element = NULL;
282
283 /* 3. If qualifiedName is not the empty string, then set element to the result of running the internal createElementNS steps. */
284 if (ZSTR_LEN(qualified_name) != 0) {
285 int errorcode = dom_validate_and_extract(uri, qualified_name, &localname, &prefix);
286
287 if (EXPECTED(errorcode == 0)) {
288 xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
289 element = xmlNewDocNode(document, ns, localname, NULL);
290 if (UNEXPECTED(element == NULL)) {
291 goto oom;
292 }
293 xmlFree(localname);
294 xmlFree(prefix);
295 localname = NULL;
296 prefix = NULL;
297 } else {
298 php_dom_throw_error(errorcode, /* strict */ true);
299 goto error;
300 }
301 }
302
303 /* 8. Return document.
304 * => This is done here already to gain access to the dom_object */
308 (xmlNodePtr) document,
309 NULL
310 );
312 intern->document->private_data = php_dom_libxml_private_data_header(private_data);
313
314 /* 4. If doctype is non-null, append doctype to document. */
315 if (doctype != NULL) {
316 php_dom_adopt_node((xmlNodePtr) doctype, intern, document);
317 xmlAddChild((xmlNodePtr) document, (xmlNodePtr) doctype);
318 doctype->doc = document;
319 document->intSubset = (xmlDtdPtr) doctype;
320 ZEND_ASSERT(doctype->parent == document);
321 }
322
323 /* 5. If element is non-null, append element to document. */
324 if (element != NULL) {
325 xmlAddChild((xmlNodePtr) document, element);
326 }
327
328 /* 6. document’s origin is this’s associated document’s origin.
329 * => We don't store the origin in ext/dom. */
330
331 /* 7. document’s content type is determined by namespace:
332 * => We don't store the content type in ext/dom. */
333
334 return;
335
336oom:
338error:
339 xmlFree(localname);
340 xmlFree(prefix);
341 xmlFreeDoc(document);
342 php_dom_private_data_destroy(private_data);
344}
345/* }}} end dom_domimplementation_create_document */
346
347/* {{{ URL: https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument */
348PHP_METHOD(Dom_Implementation, createHTMLDocument)
349{
350 const char *title = NULL;
351 size_t title_len = 0;
352
353 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!", &title, &title_len) != SUCCESS) {
355 }
356
357 /* 1. Let doc be a new document that is an HTML document. */
358 xmlDocPtr doc = php_dom_create_html_doc();
359 if (UNEXPECTED(doc == NULL)) {
362 }
363 doc->encoding = xmlStrdup(BAD_CAST "UTF-8");
364
365 /* 2. Set doc’s content type to "text/html".
366 * => We don't store the content type in ext/dom. */
367
368 /* 3. Append a new doctype, with "html" as its name and with its node document set to doc, to doc. */
369 xmlDtdPtr dtd = xmlCreateIntSubset(doc, BAD_CAST "html", NULL, NULL);
370
373 xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper);
374
375 /* 4. Append the result of creating an element given doc, html, and the HTML namespace, to doc. */
376 xmlNodePtr html_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "html", NULL);
377 xmlAddChild((xmlNodePtr) doc, html_element);
378
379 /* 5. Append the result of creating an element given doc, head, and the HTML namespace, to the html element created earlier. */
380 xmlNodePtr head_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "head", NULL);
381 xmlAddChild(html_element, head_element);
382
383 /* 6. If title is given: */
384 xmlNodePtr title_element = NULL;
385 if (title != NULL) {
386 /* 6.1. Append the result of creating an element given doc, title, and the HTML namespace, to the head element created earlier. */
387 /* 6.2. Append the result of creating a text node given doc and title, to the title element created earlier. */
388 title_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "title", BAD_CAST title);
389 xmlAddChild(head_element, title_element);
390 }
391
392 /* 7. Append the result of creating an element given doc, body, and the HTML namespace, to the html element created earlier. */
393 xmlNodePtr body_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "body", NULL);
394 xmlAddChild(html_element, body_element);
395
396 /* 8. doc’s origin is this’s associated document’s origin.
397 * => We don't store the origin in ext/dom. */
398
399 if (UNEXPECTED(dtd == NULL || html_element == NULL || head_element == NULL || (title != NULL && title_element == NULL) || body_element == NULL)) {
401 xmlFreeDoc(doc);
402 php_dom_private_data_destroy(private_data);
404 }
405
406 /* 9. Return doc. */
410 (xmlNodePtr) doc,
411 NULL
412 );
414 intern->document->private_data = php_dom_libxml_private_data_header(private_data);
415}
416/* }}} */
417
418#endif
strstr(string $haystack, string $needle, bool $before_needle=false)
PHP_DOM_EXPORT zend_class_entry * dom_html_document_class_entry
PHP_DOM_EXPORT zend_class_entry * dom_documenttype_class_entry
PHP_DOM_EXPORT zend_class_entry * dom_xml_document_class_entry
PHP_DOM_EXPORT zend_class_entry * dom_modern_documenttype_class_entry
void php_dom_throw_error(dom_exception_code error_code, bool strict_error)
@ INVALID_STATE_ERR
@ NAMESPACE_ERR
@ WRONG_DOCUMENT_ERR
error($message)
Definition ext_skel.php:22
#define NULL
Definition gdcache.h:45
#define prefix
#define SUCCESS
Definition hash_sha3.c:261
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(php_dom_libxml_ns_mapper *mapper, const xmlChar *prefix, size_t prefix_len, zend_string *uri)
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_html_ns(php_dom_libxml_ns_mapper *mapper)
#define PHP_METHOD
Definition php.h:365
dom_object * php_dom_instantiate_object_helper(zval *return_value, zend_class_entry *ce, xmlNodePtr obj, dom_object *parent)
xmlDocPtr php_dom_create_html_doc(void)
bool dom_has_feature(zend_string *feature, zend_string *version)
void dom_set_xml_class(php_libxml_ref_obj *document)
int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len)
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document)
#define DOM_GET_OBJ(__ptr, __id, __prtype, __intern)
Definition php_dom.h:237
int dom_validate_and_extract(const zend_string *namespace, const zend_string *qname, xmlChar **localName, xmlChar **prefix)
const XML_DOCUMENT_TYPE_NODE
void php_dom_private_data_destroy(php_dom_private_data *data)
php_dom_private_data * php_dom_private_data_create(void)
php_dom_libxml_ns_mapper * php_dom_ns_mapper_from_private(php_dom_private_data *private_data)
php_libxml_private_data_header * php_dom_libxml_private_data_header(php_dom_private_data *private_data)
php_libxml_ref_obj * document
Definition xml_common.h:27
struct _dom_object dom_object
#define DOM_RET_OBJ(obj, domobject)
Definition xml_common.h:76
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num)
Definition zend_API.c:443
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_THROWS()
Definition zend_API.h:1060
struct _zval_struct zval
#define E_WARNING
Definition zend_errors.h:24
struct _zend_string zend_string
#define EXPECTED(condition)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
ZEND_API zend_string * zend_empty_string
Definition zend_string.c:51
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
@ FAILURE
Definition zend_types.h:61
zval * return_value
zend_string * name