php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
namespace_compat.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: Niels Dossche <nielsdos@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "php.h"
22#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
23#include "php_dom.h"
24#include "namespace_compat.h"
25#include "private_data.h"
26#include "internal_helpers.h"
27
28/* The actual value of these doesn't matter as long as they serve as a unique ID.
29 * They need to be pointers because the `_private` field is a pointer, however we can choose the contents ourselves.
30 * We need keep these at least 4-byte aligned because the pointer may be tagged (although for now 2 byte alignment works too).
31 * We use a trick: we declare a struct with a double member to force the alignment. */
32#define DECLARE_NS_TOKEN(name, uri) \
33 static const struct { \
34 char val[sizeof(uri)]; \
35 double align; \
36 } decl_##name = { uri, 0.0 }; \
37 PHP_DOM_EXPORT const php_dom_ns_magic_token *(name) = (const php_dom_ns_magic_token *) &decl_##name;
44
45static void php_dom_libxml_ns_mapper_prefix_map_element_dtor(zval *zv)
46{
47 if (DOM_Z_IS_OWNED(zv)) {
49 }
50}
51
52static HashTable *php_dom_libxml_ns_mapper_ensure_prefix_map(php_dom_libxml_ns_mapper *mapper, zend_string **uri)
53{
54 zval *zv = zend_hash_find(&mapper->uri_to_prefix_map, *uri);
55 HashTable *prefix_map;
56 if (zv == NULL) {
57 prefix_map = emalloc(sizeof(HashTable));
58 zend_hash_init(prefix_map, 0, NULL, php_dom_libxml_ns_mapper_prefix_map_element_dtor, false);
59 zval zv_prefix_map;
60 ZVAL_ARR(&zv_prefix_map, prefix_map);
61 zend_hash_add_new(&mapper->uri_to_prefix_map, *uri, &zv_prefix_map);
62 } else {
63 /* cast to Bucket* only works if this holds, I would prefer a static assert but we're stuck at C99. */
66 Bucket *bucket = (Bucket *) zv;
67 /* Make sure we take the value from the key string that lives long enough. */
68 *uri = bucket->key;
69 prefix_map = Z_ARRVAL_P(zv);
70 }
71 return prefix_map;
72}
73
74static xmlNsPtr php_dom_libxml_ns_mapper_ensure_cached_ns(php_dom_libxml_ns_mapper *mapper, xmlNsPtr *ptr, const char *uri, size_t length, const php_dom_ns_magic_token *token)
75{
76 if (EXPECTED(*ptr != NULL)) {
77 return *ptr;
78 }
79
80 zend_string *uri_str = zend_string_init(uri, length, false);
81 *ptr = php_dom_libxml_ns_mapper_get_ns(mapper, NULL, uri_str);
82 (*ptr)->_private = (void *) token;
83 zend_string_release_ex(uri_str, false);
84 return *ptr;
85}
86
88{
89 return php_dom_libxml_ns_mapper_ensure_cached_ns(mapper, &mapper->html_ns, DOM_XHTML_NS_URI, sizeof(DOM_XHTML_NS_URI) - 1, php_dom_ns_is_html_magic_token);
90}
91
93{
94 return php_dom_libxml_ns_mapper_ensure_cached_ns(mapper, &mapper->prefixless_xmlns_ns, DOM_XMLNS_NS_URI, sizeof(DOM_XMLNS_NS_URI) - 1, php_dom_ns_is_xmlns_magic_token);
95}
96
97static xmlNsPtr dom_create_owned_ns(zend_string *prefix, zend_string *uri)
98{
100 ZEND_ASSERT(uri != NULL);
101
102 xmlNsPtr ns = emalloc(sizeof(*ns));
103 memset(ns, 0, sizeof(*ns));
104 ns->type = XML_LOCAL_NAMESPACE;
105 /* These two strings are kept alive because they're the hash table keys that lead to this entry. */
106 ns->prefix = ZSTR_LEN(prefix) == 0 ? NULL : BAD_CAST ZSTR_VAL(prefix);
107 ns->href = BAD_CAST ZSTR_VAL(uri);
108 /* Note ns->context is unused in libxml2 at the moment, and if it were used it would be for
109 * LIBXML_NAMESPACE_DICT which is opt-in anyway. */
110
111 return ns;
112}
113
115{
116 if (uri == NULL) {
117 uri = zend_empty_string;
118 }
119
120 if (prefix == NULL) {
122 }
123
124 if (ZSTR_LEN(prefix) == 0 && ZSTR_LEN(uri) == 0) {
125 return NULL;
126 }
127
128 HashTable *prefix_map = php_dom_libxml_ns_mapper_ensure_prefix_map(mapper, &uri);
129 xmlNsPtr found = zend_hash_find_ptr(prefix_map, prefix);
130 if (found != NULL) {
131 return found;
132 }
133
134 xmlNsPtr ns = dom_create_owned_ns(prefix, uri);
135
136 zval new_zv;
137 DOM_Z_OWNED(&new_zv, ns);
138 zend_hash_add_new(prefix_map, prefix, &new_zv);
139
140 return ns;
141}
142
144{
145 xmlNsPtr ns;
146 if (prefix_len == 0) {
147 /* Fast path */
149 } else {
150 zend_string *prefix_str = zend_string_init((const char *) prefix, prefix_len, false);
151 ns = php_dom_libxml_ns_mapper_get_ns(mapper, prefix_str, uri);
152 zend_string_release_ex(prefix_str, false);
153 }
154 return ns;
155}
156
157static xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_strings_ex(php_dom_libxml_ns_mapper *mapper, const char *prefix, size_t prefix_len, const char *uri, size_t uri_len)
158{
159 zend_string *prefix_str = zend_string_init(prefix, prefix_len, false);
160 zend_string *uri_str = zend_string_init(uri, uri_len, false);
161 xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns(mapper, prefix_str, uri_str);
162 zend_string_release_ex(prefix_str, false);
163 zend_string_release_ex(uri_str, false);
164 return ns;
165}
166
167static zend_always_inline xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_strings(php_dom_libxml_ns_mapper *mapper, const char *prefix, const char *uri)
168{
169 return php_dom_libxml_ns_mapper_get_ns_raw_strings_ex(mapper, prefix, strlen(prefix), uri, strlen(uri));
170}
171
173{
174 if (prefix == NULL) {
175 prefix = "";
176 }
177 if (uri == NULL) {
178 uri = "";
179 }
180 return php_dom_libxml_ns_mapper_get_ns_raw_strings(mapper, prefix, uri);
181}
182
183static xmlNsPtr php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(php_dom_libxml_ns_mapper *mapper, xmlNsPtr ns)
184{
185 ZEND_ASSERT(ns != NULL);
186
187 zend_string *href_str = zend_string_init((const char *) ns->href, xmlStrlen(ns->href), false);
188 zend_string *href_str_orig = href_str;
189 HashTable *prefix_map = php_dom_libxml_ns_mapper_ensure_prefix_map(mapper, &href_str);
190 zend_string_release_ex(href_str_orig, false);
191
192 const char *prefix = (const char *) ns->prefix;
193 size_t prefix_len;
194 if (prefix == NULL) {
195 prefix = "";
196 prefix_len = 0;
197 } else {
198 prefix_len = xmlStrlen(ns->prefix);
199 }
200
201 zval *zv = zend_hash_str_find_ptr(prefix_map, prefix, prefix_len);
202 if (zv != NULL) {
203 return Z_PTR_P(zv);
204 }
205
206 zval new_zv;
207 DOM_Z_UNOWNED(&new_zv, ns);
208 zend_hash_str_add_new(prefix_map, prefix, prefix_len, &new_zv);
209
210 return ns;
211}
212
213typedef struct {
214 /* Fast lookup for created mappings. */
215 HashTable old_ns_to_new_ns_ptr;
216 /* It is common that the last created mapping will be used for a while,
217 * cache it too to bypass the hash table. */
218 xmlNsPtr last_mapped_src, last_mapped_dst;
219 php_dom_libxml_ns_mapper *ns_mapper;
220} dom_libxml_reconcile_ctx;
221
223{
224 return &php_dom_get_private_data(object)->ns_mapper;
225}
226
227PHP_DOM_EXPORT xmlAttrPtr php_dom_ns_compat_mark_attribute(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node, xmlNsPtr ns)
228{
229 xmlNsPtr xmlns_ns;
230 const xmlChar *name;
231 if (ns->prefix != NULL) {
232 xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings(mapper, "xmlns", DOM_XMLNS_NS_URI);
233 name = ns->prefix;
234 } else {
236 name = BAD_CAST "xmlns";
237 }
238
239 ZEND_ASSERT(xmlns_ns != NULL);
240
241 return xmlSetNsProp(node, xmlns_ns, name, ns->href);
242}
243
245{
246 if (node->nsDef == NULL) {
247 return;
248 }
249
250 /* We want to prepend at the front, but in order of the namespace definitions.
251 * So temporarily unlink the existing properties and add them again at the end. */
252 xmlAttrPtr attr = node->properties;
253 node->properties = NULL;
254
255 xmlNsPtr ns = node->nsDef;
256 xmlAttrPtr last_added = NULL;
257 do {
258 last_added = php_dom_ns_compat_mark_attribute(mapper, node, ns);
259 php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(mapper, ns);
260 xmlNsPtr next = ns->next;
261 ns->next = NULL;
262 php_libxml_set_old_ns(node->doc, ns);
263 ns = next;
264 } while (ns != NULL);
265
266 if (last_added != NULL) {
267 /* node->properties now points to the first namespace declaration attribute. */
268 if (attr != NULL) {
269 last_added->next = attr;
270 attr->prev = last_added;
271 }
272 } else {
273 /* Nothing added, so nothing changed. Only really possible on OOM. */
274 node->properties = attr;
275 }
276
277 node->nsDef = NULL;
278}
279
280PHP_DOM_EXPORT bool php_dom_ns_is_fast_ex(xmlNsPtr ns, const php_dom_ns_magic_token *magic_token)
281{
282 ZEND_ASSERT(ns != NULL);
283 /* cached for fast checking */
284 if (ns->_private == magic_token) {
285 return true;
286 } else if (ns->_private != NULL && ((uintptr_t) ns->_private & 1) == 0) {
287 /* Other token stored */
288 return false;
289 }
290 /* Slow path */
291 if (xmlStrEqual(ns->href, BAD_CAST magic_token)) {
292 if (ns->_private == NULL) {
293 /* Only overwrite the private data if there is no other token stored. */
294 ns->_private = (void *) magic_token;
295 }
296 return true;
297 }
298 return false;
299}
300
301PHP_DOM_EXPORT bool php_dom_ns_is_fast(const xmlNode *nodep, const php_dom_ns_magic_token *magic_token)
302{
303 ZEND_ASSERT(nodep != NULL);
304 xmlNsPtr ns = nodep->ns;
305 if (ns != NULL) {
306 return php_dom_ns_is_fast_ex(ns, magic_token);
307 }
308 return false;
309}
310
312{
313 ZEND_ASSERT(nodep != NULL);
314 return nodep->doc && nodep->doc->type == XML_HTML_DOCUMENT_NODE && php_dom_ns_is_fast(nodep, php_dom_ns_is_html_magic_token);
315}
316
317/* will rename prefixes if there is a declaration with the same prefix but different uri. */
319{
320 ZEND_ASSERT(attrp != NULL);
321
322 if (attrp->ns != NULL) {
323 /* Try to link to an existing namespace. If that won't work, reconcile. */
324 xmlNodePtr nodep = attrp->parent;
325 xmlNsPtr matching_ns = xmlSearchNs(nodep->doc, nodep, attrp->ns->prefix);
326 if (matching_ns && xmlStrEqual(matching_ns->href, attrp->ns->href)) {
327 /* Doesn't leak because this doesn't define the declaration. */
328 attrp->ns = matching_ns;
329 } else {
330 if (attrp->ns->prefix != NULL) {
331 /* Note: explicitly use the legacy reconciliation as it mostly (i.e. as good as it gets for legacy DOM)
332 * does the right thing for attributes. */
333 xmlReconciliateNs(nodep->doc, nodep);
334 }
335 }
336 }
337}
338
339static zend_always_inline void php_dom_libxml_reconcile_modern_single_node(dom_libxml_reconcile_ctx *ctx, xmlNodePtr node)
340{
341 ZEND_ASSERT(node->ns != NULL);
342
343 if (node->ns == ctx->last_mapped_src) {
344 node->ns = ctx->last_mapped_dst;
345 return;
346 }
347
348 /* If the namespace is the same as in the map, we're good. */
349 xmlNsPtr new_ns = zend_hash_index_find_ptr(&ctx->old_ns_to_new_ns_ptr, dom_mangle_pointer_for_key(node->ns));
350 if (new_ns == NULL) {
351 /* We have to create an alternative declaration, and we'll add it to the map. */
352 const char *prefix = (const char *) node->ns->prefix;
353 const char *href = (const char *) node->ns->href;
354 new_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ctx->ns_mapper, prefix, href);
355 zend_hash_index_add_new_ptr(&ctx->old_ns_to_new_ns_ptr, dom_mangle_pointer_for_key(node->ns), new_ns);
356 ctx->last_mapped_src = node->ns;
357 ctx->last_mapped_dst = new_ns;
358 node->ns = new_ns;
359 } else if (node->ns != new_ns) {
360 /* The namespace is different, so we have to replace it. */
361 node->ns = new_ns;
362 }
363}
364
365static zend_always_inline bool dom_libxml_reconcile_fast_element_skip(xmlNodePtr node)
366{
367 /* Fast path: this is a lone element and the namespace is defined by the node (or the namespace is NULL). */
368 ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
369 return node->children == NULL && node->properties == NULL && node->ns == node->nsDef;
370}
371
372static zend_always_inline void php_dom_libxml_reconcile_modern_single_element_node(dom_libxml_reconcile_ctx *ctx, xmlNodePtr node)
373{
374 ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
375
376 /* Since this is modern DOM, the declarations are not on the node and thus there's nothing to add from nsDef. */
377 ZEND_ASSERT(node->nsDef == NULL);
378
379 if (node->ns != NULL) {
380 php_dom_libxml_reconcile_modern_single_node(ctx, node);
381 }
382
383 for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
384 if (attr->ns != NULL) {
385 php_dom_libxml_reconcile_modern_single_node(ctx, (xmlNodePtr) attr);
386 }
387 }
388}
389
391{
392 if (node->type == XML_ATTRIBUTE_NODE) {
393 if (node->ns != NULL) {
394 node->ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, (const char *) node->ns->prefix, (const char *) node->ns->href);
395 }
396 return;
397 }
398
399 if (node->type != XML_ELEMENT_NODE || dom_libxml_reconcile_fast_element_skip(node)) {
400 return;
401 }
402
403 dom_libxml_reconcile_ctx ctx;
404 zend_hash_init(&ctx.old_ns_to_new_ns_ptr, 0, NULL, NULL, 0);
405 ctx.last_mapped_src = NULL;
406 ctx.last_mapped_dst = NULL;
407 ctx.ns_mapper = ns_mapper;
408
409 php_dom_libxml_reconcile_modern_single_element_node(&ctx, node);
410
411 xmlNodePtr base = node;
412 node = node->children;
413 while (node != NULL) {
414 ZEND_ASSERT(node != base);
415
416 if (node->type == XML_ELEMENT_NODE) {
417 php_dom_libxml_reconcile_modern_single_element_node(&ctx, node);
418 }
419
420 node = php_dom_next_in_tree_order(node, base);
421 }
422
423 zend_hash_destroy(&ctx.old_ns_to_new_ns_ptr);
424}
425
426PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node, bool ignore_elements)
427{
428 ZEND_ASSERT(node != NULL);
429
430 php_dom_in_scope_ns in_scope_ns;
431 in_scope_ns.origin_is_ns_compat = true;
432
433 /* libxml fetches all nsDef items from bottom to top - left to right, ignoring prefixes already in the list.
434 * We don't have nsDef, but we can use the ns pointer (as that is necessarily in scope),
435 * and check the xmlns attributes. */
436 HashTable tmp_prefix_to_ns_table;
437 zend_hash_init(&tmp_prefix_to_ns_table, 0, NULL, NULL, false);
438 zend_hash_real_init_mixed(&tmp_prefix_to_ns_table);
439
440 for (const xmlNode *cur = node; cur != NULL; cur = cur->parent) {
441 if (cur->type == XML_ELEMENT_NODE) {
442 /* Register namespace of element */
443 if (!ignore_elements && cur->ns != NULL && cur->ns->prefix != NULL) {
444 const char *prefix = (const char *) cur->ns->prefix;
445 zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), cur->ns);
446 }
447
448 /* Register xmlns attributes */
449 for (const xmlAttr *attr = cur->properties; attr != NULL; attr = attr->next) {
450 if (attr->ns != NULL && attr->ns->prefix != NULL && php_dom_ns_is_fast_ex(attr->ns, php_dom_ns_is_xmlns_magic_token)
451 && attr->children != NULL && attr->children->content != NULL) {
452 /* This attribute declares a namespace, get the relevant instance.
453 * The declared namespace is not the same as the namespace of this attribute (which is xmlns). */
454 const char *prefix = (const char *) attr->name;
455 xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_strings(ns_mapper, prefix, (const char *) attr->children->content);
456 zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), ns);
457 }
458 }
459 }
460 }
461
462 in_scope_ns.count = zend_hash_num_elements(&tmp_prefix_to_ns_table);
463 in_scope_ns.list = safe_emalloc(in_scope_ns.count, sizeof(xmlNsPtr), 0);
464
465 size_t index = 0;
466 xmlNsPtr ns;
467 ZEND_HASH_MAP_FOREACH_PTR(&tmp_prefix_to_ns_table, ns) {
468 in_scope_ns.list[index++] = ns;
470
471 zend_hash_destroy(&tmp_prefix_to_ns_table);
472
473 return in_scope_ns;
474}
475
477{
478 ZEND_ASSERT(node != NULL);
479
480 php_dom_in_scope_ns in_scope_ns;
481 in_scope_ns.origin_is_ns_compat = false;
482 in_scope_ns.list = xmlGetNsList(node->doc, node);
483 in_scope_ns.count = 0;
484
485 if (in_scope_ns.list != NULL) {
486 while (in_scope_ns.list[in_scope_ns.count] != NULL) {
487 in_scope_ns.count++;
488 }
489 }
490
491 return in_scope_ns;
492}
493
495{
496 ZEND_ASSERT(in_scope_ns != NULL);
497 if (in_scope_ns->origin_is_ns_compat) {
498 efree(in_scope_ns->list);
499 } else {
500 xmlFree(in_scope_ns->list);
501 }
502}
503
504#endif /* HAVE_LIBXML && HAVE_DOM */
zval * zv
Definition ffi.c:3975
void * ptr
Definition ffi.c:3814
memset(ptr, 0, type->size)
new_type attr
Definition ffi.c:4364
zval * val
Definition ffi.c:4262
#define NULL
Definition gdcache.h:45
#define prefix
#define DOM_Z_IS_OWNED(z)
#define DOM_Z_UNOWNED(z, v)
#define DOM_Z_OWNED(z, v)
#define next(ls)
Definition minilua.c:2661
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns_legacy(const xmlNode *node)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_html_magic_token
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 php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node, bool ignore_elements)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xmlns_magic_token
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_html_ns(php_dom_libxml_ns_mapper *mapper)
#define DOM_XLINK_NS_URI
PHP_DOM_EXPORT bool php_dom_ns_is_fast_ex(xmlNsPtr ns, const php_dom_ns_magic_token *magic_token)
PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xlink_magic_token
#define DOM_XML_NS_URI
struct php_dom_ns_magic_token php_dom_ns_magic_token
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(php_dom_libxml_ns_mapper *mapper)
PHP_DOM_EXPORT bool php_dom_ns_is_fast(const xmlNode *nodep, const php_dom_ns_magic_token *magic_token)
PHP_DOM_EXPORT bool php_dom_ns_is_html_and_document_is_html(const xmlNode *nodep)
PHP_DOM_EXPORT void php_dom_libxml_reconcile_modern(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node)
PHP_DOM_EXPORT void php_dom_reconcile_attribute_namespace_after_insertion(xmlAttrPtr attrp)
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns(php_dom_libxml_ns_mapper *mapper, zend_string *prefix, zend_string *uri)
PHP_DOM_EXPORT void php_dom_ns_compat_mark_attribute_list(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_svg_magic_token
#define DOM_MATHML_NS_URI
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_mathml_magic_token
#define DOM_XHTML_NS_URI
PHP_DOM_EXPORT php_dom_libxml_ns_mapper * php_dom_get_ns_mapper(dom_object *object)
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(php_dom_libxml_ns_mapper *mapper, const char *prefix, const char *uri)
#define DOM_SVG_NS_URI
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xml_magic_token
PHP_DOM_EXPORT xmlAttrPtr php_dom_ns_compat_mark_attribute(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node, xmlNsPtr ns)
#define DOM_XMLNS_NS_URI
const XML_HTML_DOCUMENT_NODE
const XML_ELEMENT_NODE
const XML_ATTRIBUTE_NODE
const XML_LOCAL_NAMESPACE
zend_string * key
Definition zend_types.h:383
#define PHP_DOM_EXPORT
Definition xml_common.h:51
struct _dom_object dom_object
#define efree(ptr)
Definition zend_alloc.h:155
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1007
ZEND_API zval *ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData)
Definition zend_hash.c:1052
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
Definition zend_hash.c:338
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
struct _zend_string zend_string
#define EXPECTED(condition)
#define zend_always_inline
#define XtOffsetOf(s_type, field)
#define ZEND_ASSERT(c)
ZEND_API zend_string * zend_empty_string
Definition zend_string.c:51
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define Z_PTR_P(zval_p)
#define ZVAL_ARR(z, a)
struct _Bucket Bucket
zend_string * name