mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
[RFC] Add a way to opt-in ext/dom spec compliance (#13031)
RFC: https://wiki.php.net/rfc/opt_in_dom_spec_compliance
This commit is contained in:
parent
f438b3bc69
commit
14b6c981c3
255 changed files with 14751 additions and 2642 deletions
1
NEWS
1
NEWS
|
@ -36,6 +36,7 @@ PHP NEWS
|
|||
. Handle OOM more consistently. (nielsdos)
|
||||
. Implemented "Improve callbacks in ext/dom and ext/xsl" RFC. (nielsdos)
|
||||
. Added DOMXPath::quote() static method. (divinity76)
|
||||
. Implemented opt-in ext/dom spec compliance RFC. (nielsdos)
|
||||
|
||||
- Fileinfo:
|
||||
. Update to libmagic 5.45. (nielsdos)
|
||||
|
|
24
UPGRADING
24
UPGRADING
|
@ -186,14 +186,6 @@ PHP 8.4 UPGRADE NOTES
|
|||
. Added constant DOMNode::DOCUMENT_POSITION_CONTAINS.
|
||||
. Added constant DOMNode::DOCUMENT_POSITION_CONTAINED_BY.
|
||||
. Added constant DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC.
|
||||
. Implemented DOM HTML5 parsing and serialization.
|
||||
RFC: https://wiki.php.net/rfc/domdocument_html5_parser.
|
||||
This RFC adds the new DOM namespace along with class and constant aliases.
|
||||
There are two new classes to handle HTML and XML documents:
|
||||
DOM\HTMLDocument and DOM\XMLDocument.
|
||||
These classes provide a cleaner API to handle HTML and XML documents.
|
||||
Furthermore, the DOM\HTMLDocument class implements spec-compliant HTML5
|
||||
parsing and serialization.
|
||||
. It is now possible to pass any callable to registerPhpFunctions().
|
||||
RFC: https://wiki.php.net/rfc/improve_callbacks_dom_and_xsl
|
||||
|
||||
|
@ -453,6 +445,22 @@ PHP 8.4 UPGRADE NOTES
|
|||
7. New Classes and Interfaces
|
||||
========================================
|
||||
|
||||
- DOM:
|
||||
. Implemented DOM HTML5 parsing and serialization.
|
||||
RFC: https://wiki.php.net/rfc/domdocument_html5_parser.
|
||||
This RFC adds the new DOM namespace along with new classes and
|
||||
constant aliases.
|
||||
There are two new classes to handle HTML and XML documents:
|
||||
DOM\HTMLDocument and DOM\XMLDocument.
|
||||
These classes provide a cleaner API to handle HTML and XML documents.
|
||||
Furthermore, the DOM\HTMLDocument class implements spec-compliant HTML5
|
||||
parsing and serialization.
|
||||
. Implemented opt-in ext/dom spec compliance RFC.
|
||||
This adds new classes in the DOM namespace that correspond to modern
|
||||
equivalents to the old DOM classes in the global namespaces.
|
||||
The new classes follow the DOM living spec.
|
||||
RFC: https://wiki.php.net/rfc/opt_in_dom_spec_compliance
|
||||
|
||||
========================================
|
||||
8. Removed Extensions and SAPIs
|
||||
========================================
|
||||
|
|
|
@ -143,6 +143,7 @@ PHP 8.4 INTERNALS UPGRADE NOTES
|
|||
- The macros DOM_NO_ARGS() and DOM_NOT_IMPLEMENTED() have been removed.
|
||||
- New public APIs are available to handle callbacks from XPath, see
|
||||
xpath_callbacks.h.
|
||||
- Added public APIs to manipulate namespace data, see namespace_compat.h.
|
||||
|
||||
b. ext/random
|
||||
- The macro RAND_RANGE_BADSCALING() has been removed. The implementation
|
||||
|
@ -176,6 +177,8 @@ PHP 8.4 INTERNALS UPGRADE NOTES
|
|||
- Added php_libxml_pretend_ctx_error_ex() to emit errors as if they had come
|
||||
from libxml.
|
||||
- Removed the "properties" HashTable field from php_libxml_node_object.
|
||||
- Added a way to attached private data to a php_libxml_ref_obj.
|
||||
- Added a way to fix a class type onto php_libxml_ref_obj.
|
||||
|
||||
e. ext/date
|
||||
- Added the php_format_date_ex() API to format instances of php_date_obj.
|
||||
|
|
|
@ -72,20 +72,24 @@ PHP_METHOD(DOMAttr, __construct)
|
|||
/* {{{ name string
|
||||
readonly=yes
|
||||
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-1112119403
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-attr-name
|
||||
Since:
|
||||
*/
|
||||
zend_result dom_attr_name_read(dom_object *obj, zval *retval)
|
||||
{
|
||||
xmlAttrPtr attrp;
|
||||
|
||||
attrp = (xmlAttrPtr) dom_object_get_node(obj);
|
||||
xmlAttrPtr attrp = (xmlAttrPtr) dom_object_get_node(obj);
|
||||
|
||||
if (attrp == NULL) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, 1);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (php_dom_follow_spec_intern(obj)) {
|
||||
zend_string *str = dom_node_get_node_name_attribute_or_element((xmlNodePtr) attrp, false);
|
||||
ZVAL_NEW_STR(retval, str);
|
||||
} else {
|
||||
ZVAL_STRING(retval, (char *) attrp->name);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -99,7 +103,7 @@ Since:
|
|||
*/
|
||||
zend_result dom_attr_specified_read(dom_object *obj, zval *retval)
|
||||
{
|
||||
/* TODO */
|
||||
/* From spec: "useless; always returns true" */
|
||||
ZVAL_TRUE(retval);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -147,7 +151,13 @@ zend_result dom_attr_value_write(dom_object *obj, zval *newval)
|
|||
zend_string *str = Z_STR_P(newval);
|
||||
|
||||
dom_remove_all_children((xmlNodePtr) attrp);
|
||||
xmlNodeSetContentLen((xmlNodePtr) attrp, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str));
|
||||
|
||||
if (php_dom_follow_spec_intern(obj)) {
|
||||
xmlNodePtr node = xmlNewDocTextLen(attrp->doc, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
|
||||
xmlAddChild((xmlNodePtr) attrp, node);
|
||||
} else {
|
||||
xmlNodeSetContentLen((xmlNodePtr) attrp, BAD_CAST ZSTR_VAL(str), ZSTR_LEN(str));
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,24 @@
|
|||
* Since:
|
||||
*/
|
||||
|
||||
/* For some peculiar reason, many of these methods operate on unsigned numbers.
|
||||
* Unfortunately, "old DOM" doesn't, so we have to conditionally convert...
|
||||
* And the reason we're using "unsigned int" instead of "unsigned zend_long" is because libxml2 internally works with ints. */
|
||||
static bool dom_convert_number_unsigned(dom_object *intern, zend_long input, unsigned int *output)
|
||||
{
|
||||
if (input < 0) {
|
||||
if (php_dom_follow_spec_intern(intern)) {
|
||||
*output = (unsigned int) input;
|
||||
} else {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*output = input;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* {{{ data string
|
||||
readonly=no
|
||||
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-72AB8359
|
||||
|
@ -96,6 +114,7 @@ zend_result dom_characterdata_length_read(dom_object *obj, zval *retval)
|
|||
/* }}} */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6531BCCF
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-substringdata
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOMCharacterData, substringData)
|
||||
|
@ -104,12 +123,13 @@ PHP_METHOD(DOMCharacterData, substringData)
|
|||
xmlChar *cur;
|
||||
xmlChar *substring;
|
||||
xmlNodePtr node;
|
||||
zend_long offset, count;
|
||||
zend_long offset_input, count_input;
|
||||
unsigned int count, offset;
|
||||
int length;
|
||||
dom_object *intern;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset_input, &count_input) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -117,12 +137,21 @@ PHP_METHOD(DOMCharacterData, substringData)
|
|||
|
||||
cur = node->content;
|
||||
if (cur == NULL) {
|
||||
RETURN_FALSE;
|
||||
/* TODO: is this even possible? */
|
||||
cur = BAD_CAST "";
|
||||
}
|
||||
|
||||
length = xmlUTF8Strlen(cur);
|
||||
if (ZEND_LONG_INT_OVFL(offset_input) || ZEND_LONG_INT_OVFL(count_input)) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (offset < 0 || count < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count) || offset > length) {
|
||||
if (!dom_convert_number_unsigned(intern, offset_input, &offset) || !dom_convert_number_unsigned(intern, count_input, &count)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (offset > length) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
@ -143,9 +172,10 @@ PHP_METHOD(DOMCharacterData, substringData)
|
|||
/* }}} end dom_characterdata_substring_data */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-32791A2F
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-appenddata
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOMCharacterData, appendData)
|
||||
static void dom_character_data_append_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *nodep;
|
||||
|
@ -160,26 +190,40 @@ PHP_METHOD(DOMCharacterData, appendData)
|
|||
|
||||
DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
|
||||
xmlTextConcat(nodep, (xmlChar *) arg, arg_len);
|
||||
if (return_true) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMCharacterData, appendData)
|
||||
{
|
||||
dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_CharacterData, appendData)
|
||||
{
|
||||
dom_character_data_append_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
/* }}} end dom_characterdata_append_data */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-3EDB695F
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-insertdata
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOMCharacterData, insertData)
|
||||
static void dom_character_data_insert_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
||||
{
|
||||
zval *id;
|
||||
xmlChar *cur, *first, *second;
|
||||
xmlNodePtr node;
|
||||
char *arg;
|
||||
zend_long offset;
|
||||
zend_long offset_input;
|
||||
unsigned int offset;
|
||||
int length;
|
||||
size_t arg_len;
|
||||
dom_object *intern;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &offset, &arg, &arg_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &offset_input, &arg, &arg_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -187,12 +231,22 @@ PHP_METHOD(DOMCharacterData, insertData)
|
|||
|
||||
cur = node->content;
|
||||
if (cur == NULL) {
|
||||
RETURN_FALSE;
|
||||
/* TODO: is this even possible? */
|
||||
cur = BAD_CAST "";
|
||||
}
|
||||
|
||||
length = xmlUTF8Strlen(cur);
|
||||
|
||||
if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || offset > length) {
|
||||
if (ZEND_LONG_INT_OVFL(offset_input)) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!dom_convert_number_unsigned(intern, offset_input, &offset)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (offset > length) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
@ -207,24 +261,38 @@ PHP_METHOD(DOMCharacterData, insertData)
|
|||
xmlFree(first);
|
||||
xmlFree(second);
|
||||
|
||||
if (return_true) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMCharacterData, insertData)
|
||||
{
|
||||
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_CharacterData, insertData)
|
||||
{
|
||||
dom_character_data_insert_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
/* }}} end dom_characterdata_insert_data */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-7C603781
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-deletedata
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOMCharacterData, deleteData)
|
||||
static void dom_character_data_delete_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
||||
{
|
||||
zval *id;
|
||||
xmlChar *cur, *substring, *second;
|
||||
xmlNodePtr node;
|
||||
zend_long offset, count;
|
||||
zend_long offset, count_input;
|
||||
unsigned int count;
|
||||
int length;
|
||||
dom_object *intern;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &offset, &count_input) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -232,16 +300,21 @@ PHP_METHOD(DOMCharacterData, deleteData)
|
|||
|
||||
cur = node->content;
|
||||
if (cur == NULL) {
|
||||
RETURN_FALSE;
|
||||
/* TODO: is this even possible? */
|
||||
cur = BAD_CAST "";
|
||||
}
|
||||
|
||||
length = xmlUTF8Strlen(cur);
|
||||
|
||||
if (offset < 0 || count < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count) || offset > length) {
|
||||
if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!dom_convert_number_unsigned(intern, count_input, &count)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
substring = xmlUTF8Strsub(cur, 0, (int)offset);
|
||||
} else {
|
||||
|
@ -260,26 +333,40 @@ PHP_METHOD(DOMCharacterData, deleteData)
|
|||
xmlFree(second);
|
||||
xmlFree(substring);
|
||||
|
||||
if (return_true) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMCharacterData, deleteData)
|
||||
{
|
||||
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_CharacterData, deleteData)
|
||||
{
|
||||
dom_character_data_delete_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
/* }}} end dom_characterdata_delete_data */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-E5CBA7FB
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-characterdata-replacedata
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOMCharacterData, replaceData)
|
||||
static void dom_character_data_replace_data(INTERNAL_FUNCTION_PARAMETERS, bool return_true)
|
||||
{
|
||||
zval *id;
|
||||
xmlChar *cur, *substring, *second = NULL;
|
||||
xmlNodePtr node;
|
||||
char *arg;
|
||||
zend_long offset, count;
|
||||
zend_long offset, count_input;
|
||||
unsigned int count;
|
||||
int length;
|
||||
size_t arg_len;
|
||||
dom_object *intern;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lls", &offset, &count, &arg, &arg_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lls", &offset, &count_input, &arg, &arg_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -287,16 +374,21 @@ PHP_METHOD(DOMCharacterData, replaceData)
|
|||
|
||||
cur = node->content;
|
||||
if (cur == NULL) {
|
||||
RETURN_FALSE;
|
||||
/* TODO: is this even possible? */
|
||||
cur = BAD_CAST "";
|
||||
}
|
||||
|
||||
length = xmlUTF8Strlen(cur);
|
||||
|
||||
if (offset < 0 || count < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count) || offset > length) {
|
||||
if (offset < 0 || ZEND_LONG_INT_OVFL(offset) || ZEND_LONG_INT_OVFL(count_input) || offset > length) {
|
||||
php_dom_throw_error(INDEX_SIZE_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!dom_convert_number_unsigned(intern, count_input, &count)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
substring = xmlUTF8Strsub(cur, 0, (int)offset);
|
||||
} else {
|
||||
|
@ -321,8 +413,20 @@ PHP_METHOD(DOMCharacterData, replaceData)
|
|||
}
|
||||
xmlFree(substring);
|
||||
|
||||
if (return_true) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMCharacterData, replaceData)
|
||||
{
|
||||
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_CharacterData, replaceData)
|
||||
{
|
||||
dom_character_data_replace_data(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
/* }}} end dom_characterdata_replace_data */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,7 @@ if test "$PHP_DOM" != "no"; then
|
|||
$LEXBOR_DIR/ns/ns.c \
|
||||
$LEXBOR_DIR/tag/tag.c"
|
||||
PHP_NEW_EXTENSION(dom, [php_dom.c attr.c document.c \
|
||||
xml_document.c html_document.c html5_serializer.c html5_parser.c namespace_compat.c \
|
||||
xml_document.c html_document.c xml_serializer.c html5_serializer.c html5_parser.c namespace_compat.c \
|
||||
domexception.c parentnode.c \
|
||||
processinginstruction.c cdatasection.c \
|
||||
documentfragment.c domimplementation.c \
|
||||
|
@ -49,7 +49,7 @@ if test "$PHP_DOM" != "no"; then
|
|||
PHP_ADD_BUILD_DIR($ext_builddir/$LEXBOR_DIR/ns)
|
||||
PHP_ADD_BUILD_DIR($ext_builddir/$LEXBOR_DIR/tag)
|
||||
PHP_SUBST(DOM_SHARED_LIBADD)
|
||||
PHP_INSTALL_HEADERS([ext/dom], [xml_common.h xpath_callbacks.h])
|
||||
PHP_INSTALL_HEADERS([ext/dom], [xml_common.h xpath_callbacks.h namespace_compat.h])
|
||||
PHP_ADD_EXTENSION_DEP(dom, libxml)
|
||||
])
|
||||
fi
|
||||
|
|
|
@ -8,7 +8,7 @@ if (PHP_DOM == "yes") {
|
|||
CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_DOM", PHP_PHP_BUILD + "\\include\\libxml2")
|
||||
) {
|
||||
EXTENSION("dom", "php_dom.c attr.c document.c \
|
||||
xml_document.c html_document.c html5_serializer.c html5_parser.c namespace_compat.c \
|
||||
xml_document.c html_document.c xml_serializer.c html5_serializer.c html5_parser.c namespace_compat.c \
|
||||
domexception.c parentnode.c processinginstruction.c \
|
||||
cdatasection.c documentfragment.c domimplementation.c element.c \
|
||||
node.c characterdata.c documenttype.c \
|
||||
|
@ -41,7 +41,7 @@ if (PHP_DOM == "yes") {
|
|||
WARNING("dom support can't be enabled, libxml is not found")
|
||||
}
|
||||
}
|
||||
PHP_INSTALL_HEADERS("ext/dom", "xml_common.h xpath_callbacks.h");
|
||||
PHP_INSTALL_HEADERS("ext/dom", "xml_common.h xpath_callbacks.h namespace_compat.h");
|
||||
} else {
|
||||
WARNING("dom support can't be enabled, libxml is not enabled")
|
||||
PHP_DOM = "no"
|
||||
|
|
|
@ -22,19 +22,15 @@
|
|||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "namespace_compat.h"
|
||||
#include "xml_serializer.h"
|
||||
#include "internal_helpers.h"
|
||||
#include <libxml/SAX.h>
|
||||
#include <libxml/xmlsave.h>
|
||||
#ifdef LIBXML_SCHEMAS_ENABLED
|
||||
#include <libxml/relaxng.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#endif
|
||||
|
||||
typedef struct _idsIterator idsIterator;
|
||||
struct _idsIterator {
|
||||
xmlChar *elementId;
|
||||
xmlNode *element;
|
||||
};
|
||||
|
||||
/*
|
||||
* class DOMDocument extends DOMNode
|
||||
*
|
||||
|
@ -76,10 +72,9 @@ Since:
|
|||
*/
|
||||
zend_result dom_document_implementation_read(dom_object *obj, zval *retval)
|
||||
{
|
||||
php_dom_create_implementation(retval);
|
||||
php_dom_create_implementation(retval, false);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ documentElement DOMElement
|
||||
|
@ -253,6 +248,14 @@ zend_result dom_document_version_write(dom_object *obj, zval *newval)
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (php_dom_follow_spec_intern(obj)) {
|
||||
if (!zend_string_equals_literal(str, "1.0") && !zend_string_equals_literal(str, "1.1")) {
|
||||
zend_value_error("Invalid XML version");
|
||||
zend_string_release_ex(str, 0);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (docp->version != NULL) {
|
||||
xmlFree((xmlChar *) docp->version );
|
||||
}
|
||||
|
@ -433,9 +436,13 @@ zend_result dom_document_document_uri_read(dom_object *obj, zval *retval)
|
|||
url = (char *) docp->URL;
|
||||
if (url != NULL) {
|
||||
ZVAL_STRING(retval, url);
|
||||
} else {
|
||||
if (php_dom_follow_spec_intern(obj)) {
|
||||
ZVAL_STRING(retval, "about:blank");
|
||||
} else {
|
||||
ZVAL_NULL(retval);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -481,31 +488,69 @@ zend_result dom_document_config_read(dom_object *obj, zval *retval)
|
|||
/* }}} */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-2141741547
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-createelement
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createElement)
|
||||
PHP_METHOD(DOMDocument, createElement)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
xmlDocPtr docp;
|
||||
dom_object *intern;
|
||||
int ret;
|
||||
size_t name_len, value_len;
|
||||
char *name, *value = NULL;
|
||||
size_t value_len;
|
||||
char *value = NULL;
|
||||
zend_string *name;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
Z_PARAM_STR(name)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STRING(value, value_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
if (xmlValidateName((xmlChar *) name, 0) != 0) {
|
||||
if (xmlValidateName(BAD_CAST ZSTR_VAL(name), 0) != 0) {
|
||||
php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
node = xmlNewDocNode(docp, NULL, (xmlChar *) name, (xmlChar *) value);
|
||||
xmlNodePtr node = xmlNewDocNode(docp, NULL, BAD_CAST ZSTR_VAL(name), BAD_CAST value);
|
||||
|
||||
if (!node) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_RET_OBJ(node, &ret, intern);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, createElement)
|
||||
{
|
||||
xmlNode *node;
|
||||
xmlDocPtr docp;
|
||||
dom_object *intern;
|
||||
int ret;
|
||||
zend_string *name;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(name)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
if (xmlValidateName(BAD_CAST ZSTR_VAL(name), 0) != 0) {
|
||||
php_dom_throw_error(INVALID_CHARACTER_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (docp->type == XML_HTML_DOCUMENT_NODE) {
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
|
||||
char *lower = zend_str_tolower_dup_ex(ZSTR_VAL(name), ZSTR_LEN(name));
|
||||
node = xmlNewDocRawNode(docp, php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper), BAD_CAST (lower ? lower : ZSTR_VAL(name)), NULL);
|
||||
efree(lower);
|
||||
} else {
|
||||
node = xmlNewDocNode(docp, NULL, BAD_CAST ZSTR_VAL(name), NULL);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
|
@ -518,7 +563,7 @@ PHP_METHOD(DOM_Document, createElement)
|
|||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-35CB04B5
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createDocumentFragment)
|
||||
PHP_METHOD(DOMDocument, createDocumentFragment)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
|
@ -546,7 +591,7 @@ PHP_METHOD(DOM_Document, createDocumentFragment)
|
|||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1975348127
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createTextNode)
|
||||
PHP_METHOD(DOMDocument, createTextNode)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
|
@ -576,7 +621,7 @@ PHP_METHOD(DOM_Document, createTextNode)
|
|||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1334481328
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createComment)
|
||||
PHP_METHOD(DOMDocument, createComment)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
|
@ -604,9 +649,10 @@ PHP_METHOD(DOM_Document, createComment)
|
|||
/* }}} end dom_document_create_comment */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D26C0AF8
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-createcdatasection
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createCDATASection)
|
||||
PHP_METHOD(DOMDocument, createCDATASection)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
|
@ -623,6 +669,18 @@ PHP_METHOD(DOM_Document, createCDATASection)
|
|||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
|
||||
if (php_dom_follow_spec_intern(intern)) {
|
||||
if (docp->type == XML_HTML_DOCUMENT_NODE) {
|
||||
php_dom_throw_error_with_message(NOT_SUPPORTED_ERR, "This operation is not supported for HTML documents", /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (zend_memnstr(value, "]]>", strlen("]]>"), value + value_len) != NULL) {
|
||||
php_dom_throw_error_with_message(INVALID_CHARACTER_ERR, "Invalid character sequence \"]]>\" in CDATA section", /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
node = xmlNewCDataBlock(docp, (xmlChar *) value, value_len);
|
||||
if (!node) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
|
@ -634,11 +692,11 @@ PHP_METHOD(DOM_Document, createCDATASection)
|
|||
/* }}} end dom_document_create_cdatasection */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-135944439
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-createprocessinginstruction
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createProcessingInstruction)
|
||||
static void dom_document_create_processing_instruction(INTERNAL_FUNCTION_PARAMETERS, bool modern)
|
||||
{
|
||||
zval *id;
|
||||
xmlNode *node;
|
||||
xmlDocPtr docp;
|
||||
int ret;
|
||||
|
@ -646,56 +704,77 @@ PHP_METHOD(DOM_Document, createProcessingInstruction)
|
|||
dom_object *intern;
|
||||
char *name, *value = NULL;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), modern ? "ss" : "s|s", &name, &name_len, &value, &value_len) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
if (xmlValidateName((xmlChar *) name, 0) != 0) {
|
||||
php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
node = xmlNewPI((xmlChar *) name, (xmlChar *) value);
|
||||
if (modern) {
|
||||
if (value != NULL && zend_memnstr(value, "?>", strlen("?>"), value + value_len) != NULL) {
|
||||
php_dom_throw_error_with_message(INVALID_CHARACTER_ERR, "Invalid character sequence \"?>\" in processing instruction", /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
node = xmlNewDocPI(docp, (xmlChar *) name, (xmlChar *) value);
|
||||
if (!node) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
node->doc = docp;
|
||||
|
||||
DOM_RET_OBJ(node, &ret, intern);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMDocument, createProcessingInstruction)
|
||||
{
|
||||
dom_document_create_processing_instruction(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, createProcessingInstruction)
|
||||
{
|
||||
dom_document_create_processing_instruction(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
/* }}} end dom_document_create_processing_instruction */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1084891198
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-createattribute
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createAttribute)
|
||||
PHP_METHOD(DOMDocument, createAttribute)
|
||||
{
|
||||
zval *id;
|
||||
xmlAttrPtr node;
|
||||
xmlDocPtr docp;
|
||||
int ret;
|
||||
size_t name_len;
|
||||
dom_object *intern;
|
||||
char *name;
|
||||
zend_string *name;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_PATH_STR(name)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
|
||||
if (xmlValidateName((xmlChar *) name, 0) != 0) {
|
||||
if (xmlValidateName(BAD_CAST ZSTR_VAL(name), 0) != 0) {
|
||||
php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
node = xmlNewDocProp(docp, (xmlChar *) name, NULL);
|
||||
if (docp->type == XML_HTML_DOCUMENT_NODE && php_dom_follow_spec_intern(intern)) {
|
||||
char *lower = zend_str_tolower_dup_ex(ZSTR_VAL(name), ZSTR_LEN(name));
|
||||
node = xmlNewDocProp(docp, BAD_CAST (lower ? lower : ZSTR_VAL(name)), NULL);
|
||||
efree(lower);
|
||||
} else {
|
||||
node = xmlNewDocProp(docp, BAD_CAST ZSTR_VAL(name), NULL);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
|
@ -741,31 +820,11 @@ PHP_METHOD(DOMDocument, createEntityReference)
|
|||
}
|
||||
/* }}} end dom_document_create_entity_reference */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C9094
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, getElementsByTagName)
|
||||
{
|
||||
size_t name_len;
|
||||
dom_object *intern, *namednode;
|
||||
char *name;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_THIS_INTERN(intern);
|
||||
|
||||
php_dom_create_iterator(return_value, DOM_NODELIST);
|
||||
namednode = Z_DOMOBJ_P(return_value);
|
||||
dom_namednode_iter(intern, 0, namednode, NULL, name, name_len, NULL, 0);
|
||||
}
|
||||
/* }}} end dom_document_get_elements_by_tag_name */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Core-Document-importNode
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-importnode
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, importNode)
|
||||
PHP_METHOD(DOMDocument, importNode)
|
||||
{
|
||||
zval *node;
|
||||
xmlDocPtr docp;
|
||||
|
@ -782,8 +841,7 @@ PHP_METHOD(DOM_Document, importNode)
|
|||
|
||||
DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
|
||||
|
||||
if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE
|
||||
|| nodep->type == XML_DOCUMENT_TYPE_NODE) {
|
||||
if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE) {
|
||||
php_error_docref(NULL, E_WARNING, "Cannot import: Node Type Not Supported");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
@ -791,12 +849,12 @@ PHP_METHOD(DOM_Document, importNode)
|
|||
if (nodep->doc == docp) {
|
||||
retnodep = nodep;
|
||||
} else {
|
||||
retnodep = dom_clone_node(nodep, docp, intern, recursive);
|
||||
retnodep = dom_clone_node(NULL, nodep, docp, recursive);
|
||||
if (!retnodep) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if ((retnodep->type == XML_ATTRIBUTE_NODE) && (nodep->ns != NULL)) {
|
||||
if (retnodep->type == XML_ATTRIBUTE_NODE && nodep->ns != NULL && retnodep->ns == NULL) {
|
||||
xmlNsPtr nsptr = NULL;
|
||||
xmlNodePtr root = xmlDocGetRootElement(docp);
|
||||
|
||||
|
@ -809,50 +867,93 @@ PHP_METHOD(DOM_Document, importNode)
|
|||
}
|
||||
}
|
||||
|
||||
php_libxml_invalidate_node_list_cache(intern->document);
|
||||
|
||||
DOM_RET_OBJ((xmlNodePtr) retnodep, &ret, intern);
|
||||
DOM_RET_OBJ(retnodep, &ret, intern);
|
||||
}
|
||||
/* }}} end dom_document_import_node */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createElementNS)
|
||||
static void dom_modern_document_import_node(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *node_ce)
|
||||
{
|
||||
zval *id;
|
||||
zval *node;
|
||||
xmlDocPtr docp;
|
||||
xmlNodePtr nodep = NULL;
|
||||
xmlNodePtr nodep, retnodep;
|
||||
dom_object *intern, *nodeobj;
|
||||
int ret;
|
||||
size_t uri_len = 0, name_len = 0, value_len = 0;
|
||||
char *uri, *name, *value = NULL;
|
||||
char *localname = NULL, *prefix = NULL;
|
||||
int errorcode;
|
||||
dom_object *intern;
|
||||
bool recursive = 0;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s|s", &uri, &uri_len, &name, &name_len, &value, &value_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &node, node_ce, &recursive) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
|
||||
DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
|
||||
|
||||
if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE) {
|
||||
php_dom_throw_error(NOT_SUPPORTED_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (nodep->doc == docp) {
|
||||
retnodep = nodep;
|
||||
} else {
|
||||
retnodep = dom_clone_node(php_dom_get_ns_mapper(intern), nodep, docp, recursive);
|
||||
if (!retnodep) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
DOM_RET_OBJ(retnodep, &ret, intern);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, importNode)
|
||||
{
|
||||
dom_modern_document_import_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_node_class_entry);
|
||||
}
|
||||
/* }}} end dom_document_import_node */
|
||||
|
||||
PHP_METHOD(DOM_Document, importLegacyNode)
|
||||
{
|
||||
dom_modern_document_import_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_node_class_entry);
|
||||
}
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#internal-createelementns-steps
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOMDocument, createElementNS)
|
||||
{
|
||||
xmlDocPtr docp;
|
||||
xmlNodePtr nodep = NULL;
|
||||
int ret;
|
||||
size_t value_len = 0;
|
||||
char *value = NULL;
|
||||
int errorcode;
|
||||
dom_object *intern;
|
||||
zend_string *name = NULL, *uri;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!S|s", &uri, &name, &value, &value_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
char *localname = NULL, *prefix = NULL;
|
||||
errorcode = dom_check_qname(ZSTR_VAL(name), &localname, &prefix, uri ? ZSTR_LEN(uri) : 0, ZSTR_LEN(name));
|
||||
|
||||
if (errorcode == 0) {
|
||||
if (xmlValidateName((xmlChar *) localname, 0) == 0) {
|
||||
nodep = xmlNewDocNode(docp, NULL, (xmlChar *) localname, (xmlChar *) value);
|
||||
if (xmlValidateName(BAD_CAST localname, 0) == 0) {
|
||||
nodep = xmlNewDocNode(docp, NULL, BAD_CAST localname, BAD_CAST value);
|
||||
if (UNEXPECTED(nodep == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (uri != NULL) {
|
||||
xmlNsPtr nsptr = xmlSearchNsByHref(nodep->doc, nodep, (xmlChar *) uri);
|
||||
xmlNsPtr nsptr = xmlSearchNsByHref(nodep->doc, nodep, BAD_CAST ZSTR_VAL(uri));
|
||||
if (nsptr == NULL) {
|
||||
nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
|
||||
nsptr = dom_get_ns(nodep, ZSTR_VAL(uri), &errorcode, prefix);
|
||||
}
|
||||
xmlSetNs(nodep, nsptr);
|
||||
nodep->ns = nsptr;
|
||||
}
|
||||
} else {
|
||||
errorcode = INVALID_CHARACTER_ERR;
|
||||
|
@ -860,9 +961,7 @@ PHP_METHOD(DOM_Document, createElementNS)
|
|||
}
|
||||
|
||||
xmlFree(localname);
|
||||
if (prefix != NULL) {
|
||||
xmlFree(prefix);
|
||||
}
|
||||
|
||||
if (errorcode != 0) {
|
||||
xmlFreeNode(nodep);
|
||||
|
@ -872,12 +971,46 @@ PHP_METHOD(DOM_Document, createElementNS)
|
|||
|
||||
DOM_RET_OBJ(nodep, &ret, intern);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, createElementNS)
|
||||
{
|
||||
xmlDocPtr docp;
|
||||
int ret;
|
||||
dom_object *intern;
|
||||
zend_string *name = NULL, *uri;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!S", &uri, &name) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
xmlChar *localname = NULL, *prefix = NULL;
|
||||
int errorcode = dom_validate_and_extract(uri, name, &localname, &prefix);
|
||||
|
||||
if (errorcode == 0) {
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
|
||||
xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
|
||||
xmlNodePtr nodep = xmlNewDocNode(docp, ns, localname, NULL);
|
||||
if (UNEXPECTED(nodep == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
} else {
|
||||
DOM_RET_OBJ(nodep, &ret, intern);
|
||||
}
|
||||
} else {
|
||||
php_dom_throw_error(errorcode, dom_get_strict_error(intern->document));
|
||||
}
|
||||
|
||||
xmlFree(localname);
|
||||
xmlFree(prefix);
|
||||
}
|
||||
/* }}} end dom_document_create_element_ns */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrAttrNS
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-createattributens
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, createAttributeNS)
|
||||
PHP_METHOD(DOMDocument, createAttributeNS)
|
||||
{
|
||||
zval *id;
|
||||
xmlDocPtr docp;
|
||||
|
@ -885,7 +1018,7 @@ PHP_METHOD(DOM_Document, createAttributeNS)
|
|||
xmlNsPtr nsptr;
|
||||
int ret;
|
||||
zend_string *name, *uri;
|
||||
char *localname = NULL, *prefix = NULL;
|
||||
xmlChar *localname = NULL, *prefix = NULL;
|
||||
dom_object *intern;
|
||||
int errorcode;
|
||||
|
||||
|
@ -896,44 +1029,28 @@ PHP_METHOD(DOM_Document, createAttributeNS)
|
|||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
|
||||
if (UNEXPECTED(uri == NULL)) {
|
||||
uri = zend_empty_string;
|
||||
}
|
||||
size_t uri_len = ZSTR_LEN(uri);
|
||||
|
||||
root = xmlDocGetRootElement(docp);
|
||||
if (root != NULL) {
|
||||
errorcode = dom_check_qname(ZSTR_VAL(name), &localname, &prefix, uri_len, ZSTR_LEN(name));
|
||||
if (root != NULL || php_dom_follow_spec_intern(intern)) {
|
||||
errorcode = dom_validate_and_extract(uri, name, &localname, &prefix);
|
||||
if (UNEXPECTED(errorcode != 0)) {
|
||||
goto error;
|
||||
}
|
||||
if (UNEXPECTED(xmlValidateName((xmlChar *) localname, 0) != 0)) {
|
||||
errorcode = INVALID_CHARACTER_ERR;
|
||||
goto error;
|
||||
}
|
||||
/* If prefix is "xml" and namespace is not the XML namespace, then throw a "NamespaceError" DOMException. */
|
||||
if (UNEXPECTED(!zend_string_equals_literal(uri, "http://www.w3.org/XML/1998/namespace") && xmlStrEqual(BAD_CAST prefix, BAD_CAST "xml"))) {
|
||||
if (!php_dom_follow_spec_intern(intern)) {
|
||||
/* legacy behaviour */
|
||||
errorcode = NAMESPACE_ERR;
|
||||
goto error;
|
||||
}
|
||||
/* If either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace, then throw a "NamespaceError" DOMException. */
|
||||
if (UNEXPECTED((zend_string_equals_literal(name, "xmlns") || xmlStrEqual(BAD_CAST prefix, BAD_CAST "xmlns")) && !zend_string_equals_literal(uri, "http://www.w3.org/2000/xmlns/"))) {
|
||||
errorcode = NAMESPACE_ERR;
|
||||
goto error;
|
||||
}
|
||||
/* If namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns", then throw a "NamespaceError" DOMException. */
|
||||
if (UNEXPECTED(zend_string_equals_literal(uri, "http://www.w3.org/2000/xmlns/") && !zend_string_equals_literal(name, "xmlns") && !xmlStrEqual(BAD_CAST prefix, BAD_CAST "xmlns"))) {
|
||||
errorcode = NAMESPACE_ERR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nodep = (xmlNodePtr) xmlNewDocProp(docp, (xmlChar *) localname, NULL);
|
||||
nodep = (xmlNodePtr) xmlNewDocProp(docp, localname, NULL);
|
||||
if (UNEXPECTED(nodep == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (uri_len > 0) {
|
||||
if (uri != NULL && ZSTR_LEN(uri) > 0) {
|
||||
if (php_dom_follow_spec_intern(intern)) {
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
|
||||
nsptr = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
|
||||
} else {
|
||||
nsptr = xmlSearchNsByHref(docp, root, BAD_CAST ZSTR_VAL(uri));
|
||||
|
||||
if (zend_string_equals_literal(name, "xmlns") || xmlStrEqual(BAD_CAST prefix, BAD_CAST "xml")) {
|
||||
|
@ -943,13 +1060,14 @@ PHP_METHOD(DOM_Document, createAttributeNS)
|
|||
}
|
||||
} else {
|
||||
if (nsptr == NULL || nsptr->prefix == NULL) {
|
||||
nsptr = dom_get_ns_unchecked(root, ZSTR_VAL(uri), prefix ? prefix : "default");
|
||||
nsptr = dom_get_ns_unchecked(root, ZSTR_VAL(uri), prefix ? (char *) prefix : "default");
|
||||
if (UNEXPECTED(nsptr == NULL)) {
|
||||
errorcode = NAMESPACE_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlSetNs(nodep, nsptr);
|
||||
}
|
||||
nodep->ns = nsptr;
|
||||
}
|
||||
} else {
|
||||
php_error_docref(NULL, E_WARNING, "Document Missing Root Element");
|
||||
|
@ -958,9 +1076,7 @@ PHP_METHOD(DOM_Document, createAttributeNS)
|
|||
|
||||
error:
|
||||
xmlFree(localname);
|
||||
if (prefix != NULL) {
|
||||
xmlFree(prefix);
|
||||
}
|
||||
|
||||
if (errorcode != 0) {
|
||||
xmlFreeProp((xmlAttrPtr) nodep);
|
||||
|
@ -972,31 +1088,10 @@ error:
|
|||
}
|
||||
/* }}} end dom_document_create_attribute_ns */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBTNNS
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, getElementsByTagNameNS)
|
||||
{
|
||||
size_t uri_len, name_len;
|
||||
dom_object *intern, *namednode;
|
||||
char *uri, *name;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_THIS_INTERN(intern);
|
||||
|
||||
php_dom_create_iterator(return_value, DOM_NODELIST);
|
||||
namednode = Z_DOMOBJ_P(return_value);
|
||||
dom_namednode_iter(intern, 0, namednode, NULL, name, name_len, uri ? uri : "", uri_len);
|
||||
}
|
||||
/* }}} end dom_document_get_elements_by_tag_name_ns */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBId
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, getElementById)
|
||||
PHP_METHOD(DOMDocument, getElementById)
|
||||
{
|
||||
zval *id;
|
||||
xmlDocPtr docp;
|
||||
|
@ -1061,18 +1156,66 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
|
|||
}
|
||||
}
|
||||
|
||||
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */
|
||||
#if LIBXML_VERSION < 21000
|
||||
static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_dict, xmlChar *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (xmlDictOwns(src_dict, str) == 1) {
|
||||
if (dst_dict == NULL) {
|
||||
return xmlStrdup(str);
|
||||
}
|
||||
return BAD_CAST xmlDictLookup(dst_dict, str, -1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void libxml_fixup_name_and_content(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
|
||||
{
|
||||
if (src_doc != NULL && dst_doc != src_doc && src_doc->dict != NULL) {
|
||||
node->name = libxml_copy_dicted_string(src_doc->dict, dst_doc->dict, BAD_CAST node->name);
|
||||
node->content = libxml_copy_dicted_string(src_doc->dict, NULL, node->content);
|
||||
}
|
||||
}
|
||||
|
||||
static void libxml_fixup_name_and_content_element(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
|
||||
{
|
||||
libxml_fixup_name_and_content(src_doc, dst_doc, node);
|
||||
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
|
||||
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
|
||||
}
|
||||
|
||||
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
|
||||
libxml_fixup_name_and_content_element(src_doc, dst_doc, child);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document)
|
||||
{
|
||||
php_libxml_invalidate_node_list_cache_from_doc(nodep->doc);
|
||||
xmlDocPtr original_document = nodep->doc;
|
||||
php_libxml_invalidate_node_list_cache_from_doc(original_document);
|
||||
if (nodep->doc != new_document) {
|
||||
php_libxml_invalidate_node_list_cache(dom_object_new_document->document);
|
||||
|
||||
/* Note for ATTRIBUTE_NODE: specified is always true in ext/dom,
|
||||
* and since this unlink it; the owner element will be unset (i.e. parentNode). */
|
||||
int ret = xmlDOMWrapAdoptNode(NULL, nodep->doc, nodep, new_document, NULL, /* options, unused */ 0);
|
||||
if (php_dom_follow_spec_intern(dom_object_new_document)) {
|
||||
xmlUnlinkNode(nodep);
|
||||
xmlSetTreeDoc(nodep, new_document);
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(dom_object_new_document);
|
||||
php_dom_libxml_reconcile_modern(ns_mapper, nodep);
|
||||
#if LIBXML_VERSION < 21000
|
||||
libxml_fixup_name_and_content_element(original_document, new_document, nodep);
|
||||
#endif
|
||||
} else {
|
||||
int ret = xmlDOMWrapAdoptNode(NULL, original_document, nodep, new_document, NULL, /* options, unused */ 0);
|
||||
if (UNEXPECTED(ret != 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
php_dom_transfer_document_ref(nodep, dom_object_new_document->document);
|
||||
} else {
|
||||
|
@ -1085,10 +1228,10 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
|
|||
Since: DOM Level 3
|
||||
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-adoptnode
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, adoptNode)
|
||||
static void dom_document_adopt_node(INTERNAL_FUNCTION_PARAMETERS, bool modern)
|
||||
{
|
||||
zval *node_zval;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node_zval, dom_node_class_entry) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node_zval, dom_get_node_ce(modern)) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -1112,17 +1255,31 @@ PHP_METHOD(DOM_Document, adoptNode)
|
|||
DOM_GET_OBJ(new_document, new_document_zval, xmlDocPtr, dom_object_new_document);
|
||||
|
||||
if (!php_dom_adopt_node(nodep, dom_object_new_document, new_document)) {
|
||||
if (modern) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_OBJ_COPY(&dom_object_nodep->std);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMDocument, adoptNode)
|
||||
{
|
||||
dom_document_adopt_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, adoptNode)
|
||||
{
|
||||
dom_document_adopt_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
/* }}} end dom_document_adopt_node */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-normalizeDocument
|
||||
Since: DOM Level 3
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, normalizeDocument)
|
||||
PHP_METHOD(DOMDocument, normalizeDocument)
|
||||
{
|
||||
zval *id;
|
||||
xmlDocPtr docp;
|
||||
|
@ -1135,9 +1292,7 @@ PHP_METHOD(DOM_Document, normalizeDocument)
|
|||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
|
||||
php_libxml_invalidate_node_list_cache(intern->document);
|
||||
|
||||
dom_normalize((xmlNodePtr) docp);
|
||||
php_dom_normalize_legacy((xmlNodePtr) docp);
|
||||
}
|
||||
/* }}} end dom_document_normalize_document */
|
||||
|
||||
|
@ -1274,7 +1429,6 @@ xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source,
|
|||
if (file_dest) {
|
||||
ctxt = xmlCreateFileParserCtxt(file_dest);
|
||||
}
|
||||
|
||||
} else {
|
||||
ctxt = xmlCreateMemoryParserCtxt(source, source_len);
|
||||
}
|
||||
|
@ -1350,7 +1504,7 @@ xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source,
|
|||
ret->URL = xmlStrdup((xmlChar *) ctxt->directory);
|
||||
}
|
||||
} else {
|
||||
ret = NULL;
|
||||
ret = DOM_DOCUMENT_MALFORMED;
|
||||
xmlFreeDoc(ctxt->myDoc);
|
||||
ctxt->myDoc = NULL;
|
||||
}
|
||||
|
@ -1369,13 +1523,13 @@ static void php_dom_finish_loading_document(zval *this, zval *return_value, xmlD
|
|||
dom_object *intern = Z_DOMOBJ_P(this);
|
||||
size_t old_modification_nr = 0;
|
||||
if (intern != NULL) {
|
||||
bool is_modern_api_class = false;
|
||||
php_libxml_class_type class_type = PHP_LIBXML_CLASS_LEGACY;
|
||||
xmlDocPtr docp = (xmlDocPtr) dom_object_get_node(intern);
|
||||
dom_doc_propsptr doc_prop = NULL;
|
||||
if (docp != NULL) {
|
||||
const php_libxml_ref_obj *doc_ptr = intern->document;
|
||||
ZEND_ASSERT(doc_ptr != NULL); /* Must exist, we have a document */
|
||||
is_modern_api_class = doc_ptr->is_modern_api_class;
|
||||
class_type = doc_ptr->class_type;
|
||||
old_modification_nr = doc_ptr->cache_tag.modification_nr;
|
||||
php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
|
||||
doc_prop = intern->document->doc_props;
|
||||
|
@ -1390,7 +1544,7 @@ static void php_dom_finish_loading_document(zval *this, zval *return_value, xmlD
|
|||
RETURN_FALSE;
|
||||
}
|
||||
intern->document->doc_props = doc_prop;
|
||||
intern->document->is_modern_api_class = is_modern_api_class;
|
||||
intern->document->class_type = class_type;
|
||||
}
|
||||
|
||||
php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
|
||||
|
@ -1427,6 +1581,9 @@ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode)
|
|||
}
|
||||
|
||||
xmlDocPtr newdoc = dom_document_parser(ZEND_THIS, mode, source, source_len, options, NULL);
|
||||
if (newdoc == DOM_DOCUMENT_MALFORMED) {
|
||||
newdoc = NULL;
|
||||
}
|
||||
php_dom_finish_loading_document(ZEND_THIS, return_value, newdoc);
|
||||
}
|
||||
|
||||
|
@ -1493,9 +1650,9 @@ PHP_METHOD(DOMDocument, save)
|
|||
/* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
|
||||
Since: DOM Level 3
|
||||
*/
|
||||
PHP_METHOD(DOMDocument, saveXML)
|
||||
static void dom_document_save_xml(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *node_ce)
|
||||
{
|
||||
zval *id, *nodep = NULL;
|
||||
zval *nodep = NULL;
|
||||
xmlDoc *docp;
|
||||
xmlNode *node;
|
||||
xmlBufferPtr buf;
|
||||
|
@ -1504,16 +1661,16 @@ PHP_METHOD(DOMDocument, saveXML)
|
|||
int size, format, old_xml_save_no_empty_tags;
|
||||
zend_long options = 0;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!l", &nodep, dom_node_class_entry, &options) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!l", &nodep, node_ce, &options) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
|
||||
DOM_GET_OBJ(docp, ZEND_THIS, xmlDocPtr, intern);
|
||||
|
||||
libxml_doc_props const* doc_props = dom_get_doc_props_read_only(intern->document);
|
||||
format = doc_props->formatoutput;
|
||||
|
||||
int status = -1;
|
||||
if (nodep != NULL) {
|
||||
/* Dump contents of Node */
|
||||
DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
|
||||
|
@ -1530,7 +1687,22 @@ PHP_METHOD(DOMDocument, saveXML)
|
|||
/* Save libxml2 global, override its vaule, and restore after saving. */
|
||||
old_xml_save_no_empty_tags = xmlSaveNoEmptyTags;
|
||||
xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0;
|
||||
xmlNodeDump(buf, docp, node, 0, format);
|
||||
if (php_dom_follow_spec_intern(intern)) {
|
||||
xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(buf, (const char *) docp->encoding, XML_SAVE_AS_XML);
|
||||
if (EXPECTED(ctxt != NULL)) {
|
||||
xmlCharEncodingHandlerPtr handler = xmlFindCharEncodingHandler((const char *) docp->encoding);
|
||||
xmlOutputBufferPtr out = xmlOutputBufferCreateBuffer(buf, handler);
|
||||
if (EXPECTED(out != NULL)) {
|
||||
status = dom_xml_serialize(ctxt, out, node, format);
|
||||
status |= xmlOutputBufferFlush(out);
|
||||
status |= xmlOutputBufferClose(out);
|
||||
}
|
||||
(void) xmlSaveClose(ctxt);
|
||||
xmlCharEncCloseFunc(handler);
|
||||
}
|
||||
} else {
|
||||
status = xmlNodeDump(buf, docp, node, 0, format);
|
||||
}
|
||||
xmlSaveNoEmptyTags = old_xml_save_no_empty_tags;
|
||||
} else {
|
||||
buf = xmlBufferCreate();
|
||||
|
@ -1557,15 +1729,26 @@ PHP_METHOD(DOMDocument, saveXML)
|
|||
php_error_docref(NULL, E_WARNING, "Could not create save context");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (UNEXPECTED(xmlSaveDoc(ctxt, docp) < 0)) {
|
||||
if (php_dom_follow_spec_intern(intern)) {
|
||||
xmlCharEncodingHandlerPtr handler = xmlFindCharEncodingHandler((const char *) docp->encoding);
|
||||
xmlOutputBufferPtr out = xmlOutputBufferCreateBuffer(buf, handler);
|
||||
if (EXPECTED(out != NULL)) {
|
||||
status = dom_xml_serialize(ctxt, out, (xmlNodePtr) docp, format);
|
||||
status |= xmlOutputBufferFlush(out);
|
||||
status |= xmlOutputBufferClose(out);
|
||||
} else {
|
||||
xmlCharEncCloseFunc(handler);
|
||||
}
|
||||
} else {
|
||||
status = xmlSaveDoc(ctxt, docp);
|
||||
}
|
||||
(void) xmlSaveClose(ctxt);
|
||||
}
|
||||
if (UNEXPECTED(status < 0)) {
|
||||
xmlBufferFree(buf);
|
||||
php_error_docref(NULL, E_WARNING, "Could not save document");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
(void) xmlSaveFlush(ctxt);
|
||||
(void) xmlSaveClose(ctxt);
|
||||
}
|
||||
mem = xmlBufferContent(buf);
|
||||
if (!mem) {
|
||||
xmlBufferFree(buf);
|
||||
|
@ -1575,6 +1758,16 @@ PHP_METHOD(DOMDocument, saveXML)
|
|||
RETVAL_STRINGL((const char *) mem, size);
|
||||
xmlBufferFree(buf);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMDocument, saveXML)
|
||||
{
|
||||
dom_document_save_xml(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_node_class_entry);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_XMLDocument, saveXML)
|
||||
{
|
||||
dom_document_save_xml(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_node_class_entry);
|
||||
}
|
||||
/* }}} end dom_document_savexml */
|
||||
|
||||
static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
|
||||
|
@ -1800,14 +1993,14 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
|
|||
/* }}} */
|
||||
|
||||
/* {{{ */
|
||||
PHP_METHOD(DOM_Document, schemaValidate)
|
||||
PHP_METHOD(DOMDocument, schemaValidate)
|
||||
{
|
||||
_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
|
||||
}
|
||||
/* }}} end dom_document_schema_validate_file */
|
||||
|
||||
/* {{{ */
|
||||
PHP_METHOD(DOM_Document, schemaValidateSource)
|
||||
PHP_METHOD(DOMDocument, schemaValidateSource)
|
||||
{
|
||||
_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
|
||||
}
|
||||
|
@ -1897,14 +2090,14 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ
|
|||
/* }}} */
|
||||
|
||||
/* {{{ */
|
||||
PHP_METHOD(DOM_Document, relaxNGValidate)
|
||||
PHP_METHOD(DOMDocument, relaxNGValidate)
|
||||
{
|
||||
_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
|
||||
}
|
||||
/* }}} end dom_document_relaxNG_validate_file */
|
||||
|
||||
/* {{{ */
|
||||
PHP_METHOD(DOM_Document, relaxNGValidateSource)
|
||||
PHP_METHOD(DOMDocument, relaxNGValidateSource)
|
||||
{
|
||||
_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
|
||||
}
|
||||
|
@ -2110,9 +2303,9 @@ PHP_METHOD(DOMDocument, saveHTML)
|
|||
#endif /* defined(LIBXML_HTML_ENABLED) */
|
||||
|
||||
/* {{{ Register extended class used to create base node type */
|
||||
PHP_METHOD(DOM_Document, registerNodeClass)
|
||||
static void dom_document_register_node_class(INTERNAL_FUNCTION_PARAMETERS, bool modern)
|
||||
{
|
||||
zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
|
||||
zend_class_entry *basece = dom_get_node_ce(modern), *ce = NULL;
|
||||
dom_object *intern;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "CC!", &basece, &ce) == FAILURE) {
|
||||
|
@ -2131,17 +2324,31 @@ PHP_METHOD(DOM_Document, registerNodeClass)
|
|||
}
|
||||
DOM_GET_THIS_INTERN(intern);
|
||||
dom_set_doc_classmap(intern->document, basece, ce);
|
||||
RETURN_TRUE;
|
||||
if (!modern) {
|
||||
RETVAL_TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
zend_argument_error(NULL, 2, "must be a class name derived from %s or null, %s given", ZSTR_VAL(basece->name), ZSTR_VAL(ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
PHP_METHOD(DOMDocument, registerNodeClass)
|
||||
{
|
||||
dom_document_register_node_class(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Document, registerNodeClass)
|
||||
{
|
||||
dom_document_register_node_class(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-replacechildren
|
||||
Since:
|
||||
*/
|
||||
PHP_METHOD(DOM_Document, replaceChildren)
|
||||
PHP_METHOD(DOMDocument, replaceChildren)
|
||||
{
|
||||
uint32_t argc = 0;
|
||||
zval *args;
|
||||
|
|
|
@ -60,7 +60,7 @@ zend_result dom_documenttype_entities_read(dom_object *obj, zval *retval)
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
php_dom_create_iterator(retval, DOM_NAMEDNODEMAP);
|
||||
php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, php_dom_follow_spec_intern(obj));
|
||||
|
||||
entityht = (xmlHashTable *) doctypep->entities;
|
||||
|
||||
|
@ -88,7 +88,7 @@ zend_result dom_documenttype_notations_read(dom_object *obj, zval *retval)
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
php_dom_create_iterator(retval, DOM_NAMEDNODEMAP);
|
||||
php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, php_dom_follow_spec_intern(obj));
|
||||
|
||||
notationht = (xmlHashTable *) doctypep->notations;
|
||||
|
||||
|
@ -184,7 +184,7 @@ zend_result dom_documenttype_internal_subset_read(dom_object *obj, zval *retval)
|
|||
}
|
||||
|
||||
if (ret_buf.s) {
|
||||
ZVAL_STR(retval, smart_str_extract(&ret_buf));
|
||||
ZVAL_NEW_STR(retval, smart_str_extract(&ret_buf));
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,28 +19,51 @@
|
|||
#define DOM_CE_H
|
||||
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_node_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_node_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_domexception_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_parentnode_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_parentnode_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_childnode_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_childnode_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_domimplementation_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_domimplementation_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_documentfragment_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_documentfragment_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_document_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_html_document_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_xml_document_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_nodelist_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_nodelist_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_namednodemap_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_namednodemap_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_dtd_namednodemap_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_html_collection_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_characterdata_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_characterdata_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_attr_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_attr_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_element_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_text_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_comment_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_cdatasection_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_cdatasection_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_documenttype_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_documenttype_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_notation_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_notation_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_entity_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_entity_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_entityreference_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_entityreference_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_processinginstruction_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_processinginstruction_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_abstract_base_document_class_entry;
|
||||
#ifdef LIBXML_XPATH_ENABLED
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry;
|
||||
#endif
|
||||
extern PHP_DOM_EXPORT zend_class_entry *dom_namespace_node_class_entry;
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */
|
|||
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node;
|
||||
}
|
||||
curnode = dom_get_elements_by_tag_name_ns_raw(
|
||||
basenode, curnode, (char *) objmap->ns, (char *) objmap->local, &previndex, iter->index);
|
||||
basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iter->index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -316,7 +316,7 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i
|
|||
nodep = nodep->children;
|
||||
}
|
||||
curnode = dom_get_elements_by_tag_name_ns_raw(
|
||||
basep, nodep, (char *) objmap->ns, (char *) objmap->local, &curindex, 0);
|
||||
basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &curindex, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -34,6 +34,7 @@ zend_result dom_characterdata_length_read(dom_object *obj, zval *retval);
|
|||
/* document properties */
|
||||
zend_result dom_document_doctype_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_document_implementation_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_modern_document_implementation_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_document_document_element_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_document_actual_encoding_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_document_actual_encoding_write(dom_object *obj, zval *newval);
|
||||
|
@ -115,6 +116,7 @@ zend_result dom_node_is_connected_read(dom_object *obj, zval *retval);
|
|||
zend_result dom_node_owner_document_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_node_namespace_uri_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_node_prefix_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_modern_node_prefix_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_node_prefix_write(dom_object *obj, zval *newval);
|
||||
zend_result dom_node_local_name_read(dom_object *obj, zval *retval);
|
||||
zend_result dom_node_base_uri_read(dom_object *obj, zval *retval);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "namespace_compat.h"
|
||||
|
||||
/*
|
||||
* class DOMImplementation
|
||||
|
@ -46,6 +47,7 @@ PHP_METHOD(DOMImplementation, hasFeature)
|
|||
/* }}} end dom_domimplementation_has_feature */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocType
|
||||
Modern URL: https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
|
||||
Since: DOM Level 2
|
||||
*/
|
||||
PHP_METHOD(DOMImplementation, createDocumentType)
|
||||
|
@ -91,10 +93,6 @@ PHP_METHOD(DOMImplementation, createDocumentType)
|
|||
localname = xmlStrdup((xmlChar *) name);
|
||||
}
|
||||
|
||||
/* TODO: Test that localname has no invalid chars
|
||||
php_dom_throw_error(INVALID_CHARACTER_ERR,);
|
||||
*/
|
||||
|
||||
if (uri) {
|
||||
xmlFreeURI(uri);
|
||||
}
|
||||
|
@ -109,6 +107,41 @@ PHP_METHOD(DOMImplementation, createDocumentType)
|
|||
|
||||
DOM_RET_OBJ((xmlNodePtr) doctype, &ret, NULL);
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Implementation, createDocumentType)
|
||||
{
|
||||
size_t name_len, publicid_len = 0, systemid_len = 0;
|
||||
const char *name, *publicid = NULL, *systemid = NULL;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppp", &name, &name_len, &publicid, &publicid_len, &systemid, &systemid_len) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
/* 1. Validate qualifiedName. */
|
||||
if (xmlValidateQName(BAD_CAST name, 0) != 0) {
|
||||
php_dom_throw_error(NAMESPACE_ERR, true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
/* 2. Return a new doctype, with qualifiedName as its name, publicId as its public ID, and systemId as its system ID ... */
|
||||
xmlDtdPtr doctype = xmlCreateIntSubset(
|
||||
NULL,
|
||||
BAD_CAST name,
|
||||
publicid_len ? BAD_CAST publicid : NULL,
|
||||
systemid_len ? BAD_CAST systemid : NULL
|
||||
);
|
||||
if (UNEXPECTED(doctype == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
php_dom_instantiate_object_helper(
|
||||
return_value,
|
||||
dom_modern_documenttype_class_entry,
|
||||
(xmlNodePtr) doctype,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
/* }}} end dom_domimplementation_create_document_type */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Level-2-Core-DOM-createDocument
|
||||
|
@ -216,8 +249,170 @@ PHP_METHOD(DOMImplementation, createDocument)
|
|||
php_libxml_increment_doc_ref((php_libxml_node_object *)doctobj, docp);
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_Implementation, createDocument)
|
||||
{
|
||||
zval *dtd = NULL;
|
||||
xmlDtdPtr doctype = NULL;
|
||||
zend_string *uri = NULL, *qualified_name = zend_empty_string;
|
||||
dom_object *doctobj;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P!P|O!", &uri, &qualified_name, &dtd, dom_modern_documenttype_class_entry) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (dtd != NULL) {
|
||||
DOM_GET_OBJ(doctype, dtd, xmlDtdPtr, doctobj);
|
||||
}
|
||||
|
||||
xmlDocPtr document = NULL;
|
||||
xmlChar *localname = NULL, *prefix = NULL;
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_libxml_ns_mapper_create();
|
||||
|
||||
/* 1. Let document be a new XMLDocument. */
|
||||
document = xmlNewDoc(BAD_CAST "1.0");
|
||||
if (UNEXPECTED(document == NULL)) {
|
||||
goto oom;
|
||||
}
|
||||
document->encoding = xmlStrdup(BAD_CAST "UTF-8");
|
||||
|
||||
/* 2. Let element be null. */
|
||||
xmlNodePtr element = NULL;
|
||||
|
||||
/* 3. If qualifiedName is not the empty string, then set element to the result of running the internal createElementNS steps. */
|
||||
if (ZSTR_LEN(qualified_name) != 0) {
|
||||
int errorcode = dom_validate_and_extract(uri, qualified_name, &localname, &prefix);
|
||||
|
||||
if (EXPECTED(errorcode == 0)) {
|
||||
xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
|
||||
element = xmlNewDocNode(document, ns, localname, NULL);
|
||||
if (UNEXPECTED(element == NULL)) {
|
||||
goto oom;
|
||||
}
|
||||
xmlFree(localname);
|
||||
xmlFree(prefix);
|
||||
localname = NULL;
|
||||
prefix = NULL;
|
||||
} else {
|
||||
php_dom_throw_error(errorcode, /* strict */ true);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* 8. Return document.
|
||||
* => This is done here already to gain access to the dom_object */
|
||||
dom_object *intern = php_dom_instantiate_object_helper(
|
||||
return_value,
|
||||
dom_xml_document_class_entry,
|
||||
(xmlNodePtr) document,
|
||||
NULL
|
||||
);
|
||||
intern->document->class_type = PHP_LIBXML_CLASS_MODERN;
|
||||
intern->document->private_data = php_dom_libxml_ns_mapper_header(ns_mapper);
|
||||
|
||||
/* 4. If doctype is non-null, append doctype to document. */
|
||||
if (doctype != NULL) {
|
||||
php_dom_adopt_node((xmlNodePtr) doctype, intern, document);
|
||||
xmlAddChild((xmlNodePtr) document, (xmlNodePtr) doctype);
|
||||
doctype->doc = document;
|
||||
document->intSubset = (xmlDtdPtr) doctype;
|
||||
ZEND_ASSERT(doctype->parent == document);
|
||||
}
|
||||
|
||||
/* 5. If element is non-null, append element to document. */
|
||||
if (element != NULL) {
|
||||
xmlAddChild((xmlNodePtr) document, element);
|
||||
}
|
||||
|
||||
/* 6. document’s origin is this’s associated document’s origin.
|
||||
* => We don't store the origin in ext/dom. */
|
||||
|
||||
/* 7. document’s content type is determined by namespace:
|
||||
* => We don't store the content type in ext/dom. */
|
||||
|
||||
return;
|
||||
|
||||
oom:
|
||||
php_dom_throw_error(INVALID_STATE_ERR, true);
|
||||
error:
|
||||
xmlFree(localname);
|
||||
xmlFree(prefix);
|
||||
xmlFreeDoc(document);
|
||||
php_dom_libxml_ns_mapper_destroy(ns_mapper);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
/* }}} end dom_domimplementation_create_document */
|
||||
|
||||
/* {{{ URL: https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument */
|
||||
PHP_METHOD(DOM_Implementation, createHTMLDocument)
|
||||
{
|
||||
const char *title = NULL;
|
||||
size_t title_len = 0;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!", &title, &title_len) != SUCCESS) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
/* 1. Let doc be a new document that is an HTML document. */
|
||||
xmlDocPtr doc = php_dom_create_html_doc();
|
||||
if (UNEXPECTED(doc == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, true);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
doc->encoding = xmlStrdup(BAD_CAST "UTF-8");
|
||||
|
||||
/* 2. Set doc’s content type to "text/html".
|
||||
* => We don't store the content type in ext/dom. */
|
||||
|
||||
/* 3. Append a new doctype, with "html" as its name and with its node document set to doc, to doc. */
|
||||
xmlDtdPtr dtd = xmlCreateIntSubset(doc, BAD_CAST "html", NULL, NULL);
|
||||
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_libxml_ns_mapper_create();
|
||||
xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper);
|
||||
|
||||
/* 4. Append the result of creating an element given doc, html, and the HTML namespace, to doc. */
|
||||
xmlNodePtr html_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "html", NULL);
|
||||
xmlAddChild((xmlNodePtr) doc, html_element);
|
||||
|
||||
/* 5. Append the result of creating an element given doc, head, and the HTML namespace, to the html element created earlier. */
|
||||
xmlNodePtr head_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "head", NULL);
|
||||
xmlAddChild(html_element, head_element);
|
||||
|
||||
/* 6. If title is given: */
|
||||
xmlNodePtr title_element = NULL;
|
||||
if (title != NULL) {
|
||||
/* 6.1. Append the result of creating an element given doc, title, and the HTML namespace, to the head element created earlier. */
|
||||
/* 6.2. Append the result of creating a text node given doc and title, to the title element created earlier. */
|
||||
title_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "title", BAD_CAST title);
|
||||
xmlAddChild(head_element, title_element);
|
||||
}
|
||||
|
||||
/* 7. Append the result of creating an element given doc, body, and the HTML namespace, to the html element created earlier. */
|
||||
xmlNodePtr body_element = xmlNewDocRawNode(doc, html_ns, BAD_CAST "body", NULL);
|
||||
xmlAddChild(html_element, body_element);
|
||||
|
||||
/* 8. doc’s origin is this’s associated document’s origin.
|
||||
* => We don't store the origin in ext/dom. */
|
||||
|
||||
if (UNEXPECTED(dtd == NULL || html_element == NULL || head_element == NULL || (title != NULL && title_element == NULL) || body_element == NULL)) {
|
||||
php_dom_throw_error(INVALID_STATE_ERR, true);
|
||||
xmlFreeDoc(doc);
|
||||
php_dom_libxml_ns_mapper_destroy(ns_mapper);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
/* 9. Return doc. */
|
||||
dom_object *intern = php_dom_instantiate_object_helper(
|
||||
return_value,
|
||||
dom_html_document_class_entry,
|
||||
(xmlNodePtr) doc,
|
||||
NULL
|
||||
);
|
||||
intern->document->class_type = PHP_LIBXML_CLASS_MODERN;
|
||||
intern->document->private_data = php_dom_libxml_ns_mapper_header(ns_mapper);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#DOMImplementation3-getFeature
|
||||
Since: DOM Level 3
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,11 +20,10 @@
|
|||
|
||||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "html5_parser.h"
|
||||
#include "namespace_compat.h"
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/html/interfaces/element.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/parserInternals.h>
|
||||
#include <libxml/HTMLtree.h>
|
||||
#include <Zend/zend.h>
|
||||
|
@ -63,14 +62,14 @@ static unsigned short sanitize_line_nr(size_t line)
|
|||
return (unsigned short) line;
|
||||
}
|
||||
|
||||
static const xmlChar *get_libxml_namespace_href(uintptr_t lexbor_namespace)
|
||||
static const php_dom_ns_magic_token *get_libxml_namespace_href(uintptr_t lexbor_namespace)
|
||||
{
|
||||
if (lexbor_namespace == LXB_NS_SVG) {
|
||||
return (const xmlChar *) DOM_SVG_NS_URI;
|
||||
return php_dom_ns_is_svg_magic_token;
|
||||
} else if (lexbor_namespace == LXB_NS_MATH) {
|
||||
return (const xmlChar *) DOM_MATHML_NS_URI;
|
||||
return php_dom_ns_is_mathml_magic_token;
|
||||
} else {
|
||||
return (const xmlChar *) DOM_XHTML_NS_URI;
|
||||
return php_dom_ns_is_html_magic_token;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,11 +97,16 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
|
|||
lxb_dom_node_t *start_node,
|
||||
xmlDocPtr lxml_doc,
|
||||
bool compact_text_nodes,
|
||||
bool create_default_ns
|
||||
bool create_default_ns,
|
||||
php_dom_libxml_ns_mapper *ns_mapper
|
||||
)
|
||||
{
|
||||
lexbor_libxml2_bridge_status retval = LEXBOR_LIBXML2_BRIDGE_STATUS_OK;
|
||||
|
||||
xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper);
|
||||
xmlNsPtr xlink_ns = NULL;
|
||||
xmlNsPtr prefixed_xmlns_ns = NULL;
|
||||
|
||||
lexbor_array_obj_t work_list;
|
||||
lexbor_array_obj_init(&work_list, WORK_LIST_INIT_SIZE, sizeof(work_list_item));
|
||||
|
||||
|
@ -135,7 +139,17 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
|
|||
uintptr_t entering_namespace = element->node.ns;
|
||||
xmlNsPtr current_lxml_ns = current_stack_item->lxml_ns;
|
||||
if (create_default_ns && UNEXPECTED(entering_namespace != current_stack_item->current_active_namespace)) {
|
||||
current_lxml_ns = xmlNewNs(lxml_element, get_libxml_namespace_href(entering_namespace), NULL);
|
||||
if (entering_namespace == LXB_NS_HTML) {
|
||||
current_lxml_ns = html_ns;
|
||||
} else {
|
||||
const php_dom_ns_magic_token *magic_token = get_libxml_namespace_href(entering_namespace);
|
||||
zend_string *uri = zend_string_init((char *) magic_token, strlen((char *) magic_token), false);
|
||||
current_lxml_ns = php_dom_libxml_ns_mapper_get_ns(ns_mapper, NULL, uri);
|
||||
zend_string_release_ex(uri, false);
|
||||
if (EXPECTED(current_lxml_ns != NULL)) {
|
||||
current_lxml_ns->_private = (void *) magic_token;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Instead of xmlSetNs() because we know the arguments are valid. Prevents overhead. */
|
||||
lxml_element->ns = current_lxml_ns;
|
||||
|
@ -181,6 +195,25 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
|
|||
}
|
||||
|
||||
lxml_attr->children = lxml_attr->last = lxml_text;
|
||||
lxml_text->parent = (xmlNodePtr) lxml_attr;
|
||||
|
||||
if (attr->node.ns == LXB_NS_XMLNS) {
|
||||
if (strcmp((const char *) local_name, "xmlns") != 0) {
|
||||
if (prefixed_xmlns_ns == NULL) {
|
||||
prefixed_xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xmlns", DOM_XMLNS_NS_URI);
|
||||
}
|
||||
lxml_attr->ns = prefixed_xmlns_ns;
|
||||
} else {
|
||||
lxml_attr->ns = php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(ns_mapper);
|
||||
}
|
||||
lxml_attr->ns->_private = (void *) php_dom_ns_is_xmlns_magic_token;
|
||||
} else if (attr->node.ns == LXB_NS_XLINK) {
|
||||
if (xlink_ns == NULL) {
|
||||
xlink_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xlink", DOM_XLINK_NS_URI);
|
||||
xlink_ns->_private = (void *) php_dom_ns_is_xlink_magic_token;
|
||||
}
|
||||
lxml_attr->ns = xlink_ns;
|
||||
}
|
||||
|
||||
if (last_added_attr == NULL) {
|
||||
lxml_element->properties = lxml_attr;
|
||||
|
@ -270,29 +303,20 @@ lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert_document(
|
|||
lxb_html_document_t *document,
|
||||
xmlDocPtr *doc_out,
|
||||
bool compact_text_nodes,
|
||||
bool create_default_ns
|
||||
bool create_default_ns,
|
||||
php_dom_libxml_ns_mapper *ns_mapper
|
||||
)
|
||||
{
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
xmlDocPtr lxml_doc = htmlNewDocNoDtD(NULL, NULL);
|
||||
xmlDocPtr lxml_doc = php_dom_create_html_doc();
|
||||
if (UNEXPECTED(!lxml_doc)) {
|
||||
return LEXBOR_LIBXML2_BRIDGE_STATUS_OOM;
|
||||
}
|
||||
#else
|
||||
/* If HTML support is not enabled, then htmlNewDocNoDtD() is not available.
|
||||
* This code mimics the behaviour. */
|
||||
xmlDocPtr lxml_doc = xmlNewDoc((const xmlChar *) "1.0");
|
||||
if (UNEXPECTED(!lxml_doc)) {
|
||||
return LEXBOR_LIBXML2_BRIDGE_STATUS_OOM;
|
||||
}
|
||||
lxml_doc->type = XML_HTML_DOCUMENT_NODE;
|
||||
#endif
|
||||
lxml_doc->dict = xmlDictCreate();
|
||||
lexbor_libxml2_bridge_status status = lexbor_libxml2_bridge_convert(
|
||||
lxb_dom_interface_node(document)->last_child,
|
||||
lxml_doc,
|
||||
compact_text_nodes,
|
||||
create_default_ns
|
||||
create_default_ns,
|
||||
ns_mapper
|
||||
);
|
||||
if (status != LEXBOR_LIBXML2_BRIDGE_STATUS_OK) {
|
||||
xmlFreeDoc(lxml_doc);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef HTML5_PARSER_H
|
||||
#define HTML5_PARSER_H
|
||||
|
||||
#include "namespace_compat.h"
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <Zend/zend_portability.h>
|
||||
|
@ -68,7 +69,8 @@ lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert_document(
|
|||
lxb_html_document_t *document,
|
||||
xmlDocPtr *doc_out,
|
||||
bool compact_text_nodes,
|
||||
bool create_default_ns
|
||||
bool create_default_ns,
|
||||
php_dom_libxml_ns_mapper *ns_mapper
|
||||
);
|
||||
void lexbor_libxml2_bridge_report_errors(
|
||||
const lexbor_libxml2_bridge_parse_context *ctx,
|
||||
|
|
|
@ -23,25 +23,15 @@
|
|||
#include "php_dom.h"
|
||||
#include "html5_serializer.h"
|
||||
#include "namespace_compat.h"
|
||||
#include "serialize_common.h"
|
||||
#include <lexbor/encoding/encoding.h>
|
||||
|
||||
/* This file implements the HTML 5 serialization algorithm.
|
||||
* https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments (Date 2023-12-14)
|
||||
*/
|
||||
|
||||
#define TRY(x) do { if (UNEXPECTED((x) != SUCCESS)) { return FAILURE; } } while (0)
|
||||
|
||||
static bool dom_is_ns(const xmlNode *node, const char *uri)
|
||||
{
|
||||
return node->ns != NULL && strcmp((const char *) node->ns->href, uri) == 0;
|
||||
}
|
||||
|
||||
static bool dom_is_html_ns(const xmlNode *node)
|
||||
{
|
||||
return node->ns == NULL || dom_is_ns(node, DOM_XHTML_NS_URI);
|
||||
}
|
||||
|
||||
static bool dom_local_name_compare_ex(const xmlNode *node, const char *tag, size_t tag_length, size_t name_length)
|
||||
{
|
||||
return name_length == tag_length && zend_binary_strcmp((const char *) node->name, name_length, tag, tag_length) == 0;
|
||||
}
|
||||
|
||||
static zend_result dom_html5_serialize_doctype(dom_html5_serialize_context *ctx, const xmlDtd *dtd)
|
||||
{
|
||||
TRY(ctx->write_string_len(ctx->application_data, "<!DOCTYPE ", strlen("<!DOCTYPE ")));
|
||||
|
@ -61,10 +51,19 @@ static zend_result dom_html5_serialize_processing_instruction(dom_html5_serializ
|
|||
TRY(ctx->write_string_len(ctx->application_data, "<?", strlen("<?")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) node->name));
|
||||
TRY(ctx->write_string_len(ctx->application_data, " ", strlen(" ")));
|
||||
if (node->content) {
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) node->content));
|
||||
}
|
||||
return ctx->write_string_len(ctx->application_data, ">", strlen(">"));
|
||||
}
|
||||
|
||||
static zend_result dom_html5_serialize_entity_ref(dom_html5_serialize_context *ctx, const xmlNode *node)
|
||||
{
|
||||
TRY(ctx->write_string_len(ctx->application_data, "&", strlen("&")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) node->name));
|
||||
return ctx->write_string_len(ctx->application_data, ";", strlen(";"));
|
||||
}
|
||||
|
||||
/* https://html.spec.whatwg.org/multipage/parsing.html#escapingString */
|
||||
static zend_result dom_html5_escape_string(dom_html5_serialize_context *ctx, const char *content, bool attribute_mode)
|
||||
{
|
||||
|
@ -132,7 +131,7 @@ static zend_result dom_html5_escape_string(dom_html5_serialize_context *ctx, con
|
|||
|
||||
static zend_result dom_html5_serialize_text_node(dom_html5_serialize_context *ctx, const xmlNode *node)
|
||||
{
|
||||
if (node->parent->type == XML_ELEMENT_NODE && dom_is_html_ns(node->parent)) {
|
||||
if (node->parent->type == XML_ELEMENT_NODE && php_dom_ns_is_fast(node->parent, php_dom_ns_is_html_magic_token)) {
|
||||
const xmlNode *parent = node->parent;
|
||||
size_t name_length = strlen((const char *) parent->name);
|
||||
/* Spec tells us to only emit noscript content as-is if scripting is enabled.
|
||||
|
@ -156,7 +155,7 @@ static zend_result dom_html5_serialize_element_tag_name(dom_html5_serialize_cont
|
|||
{
|
||||
/* Note: it is not the serializer's responsibility to care about uppercase/lowercase (see createElement() note) */
|
||||
if (node->ns != NULL && node->ns->prefix != NULL
|
||||
&& !(dom_is_html_ns(node) || dom_is_ns(node, DOM_MATHML_NS_URI) || dom_is_ns(node, DOM_SVG_NS_URI))) {
|
||||
&& !(php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) || php_dom_ns_is_fast(node, php_dom_ns_is_mathml_magic_token) || php_dom_ns_is_fast(node, php_dom_ns_is_svg_magic_token))) {
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) node->ns->prefix));
|
||||
TRY(ctx->write_string_len(ctx->application_data, ":", strlen(":")));
|
||||
}
|
||||
|
@ -170,32 +169,15 @@ static zend_result dom_html5_serialize_element_start(dom_html5_serialize_context
|
|||
|
||||
/* We don't support the "is" value during element creation, so no handling here. */
|
||||
|
||||
/* Some namespace declarations are also attributes (see https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token) */
|
||||
for (const xmlNs *ns = node->nsDef; ns != NULL; ns = ns->next) {
|
||||
if (!dom_ns_is_also_an_attribute(ns)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ns->prefix != NULL) {
|
||||
TRY(ctx->write_string_len(ctx->application_data, " xmlns:", strlen(" xmlns:")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) ns->prefix));
|
||||
TRY(ctx->write_string_len(ctx->application_data, "=\"", strlen("=\"")));
|
||||
} else {
|
||||
TRY(ctx->write_string_len(ctx->application_data, " xmlns=\"", strlen(" xmlns=\"")));
|
||||
}
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) ns->href));
|
||||
TRY(ctx->write_string_len(ctx->application_data, "\"", strlen("\"")));
|
||||
}
|
||||
|
||||
for (const xmlAttr *attr = node->properties; attr; attr = attr->next) {
|
||||
TRY(ctx->write_string_len(ctx->application_data, " ", strlen(" ")));
|
||||
if (attr->ns == NULL) {
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) attr->name));
|
||||
} else {
|
||||
if (dom_is_ns((const xmlNode *) attr, DOM_XML_NS_URI)) {
|
||||
if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xml_magic_token)) {
|
||||
TRY(ctx->write_string_len(ctx->application_data, "xml:", strlen("xml:")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) attr->name));
|
||||
} else if (dom_is_ns((const xmlNode *) attr, DOM_XMLNS_NS_URI)) {
|
||||
} else if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) {
|
||||
/* Compatibility for real attributes */
|
||||
if (strcmp((const char *) attr->name, "xmlns") == 0) {
|
||||
TRY(ctx->write_string_len(ctx->application_data, "xmlns", strlen("xmlns")));
|
||||
|
@ -203,7 +185,7 @@ static zend_result dom_html5_serialize_element_start(dom_html5_serialize_context
|
|||
TRY(ctx->write_string_len(ctx->application_data, "xmlns:", strlen("xmlns:")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) attr->name));
|
||||
}
|
||||
} else if (dom_is_ns((const xmlNode *) attr, DOM_XLINK_NS_URI)) {
|
||||
} else if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xlink_magic_token)) {
|
||||
TRY(ctx->write_string_len(ctx->application_data, "xlink:", strlen("xlink:")));
|
||||
TRY(ctx->write_string(ctx->application_data, (const char *) attr->name));
|
||||
} else if (attr->ns->prefix == NULL) {
|
||||
|
@ -233,7 +215,7 @@ static zend_result dom_html5_serialize_element_start(dom_html5_serialize_context
|
|||
* https://html.spec.whatwg.org/multipage/parsing.html#serializes-as-void */
|
||||
static bool dom_html5_serializes_as_void(const xmlNode *node)
|
||||
{
|
||||
if (dom_is_html_ns(node)) {
|
||||
if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token)) {
|
||||
size_t name_length = strlen((const char *) node->name);
|
||||
if (/* These are the void elements from https://html.spec.whatwg.org/multipage/syntax.html#void-elements */
|
||||
dom_local_name_compare_ex(node, "area", strlen("area"), name_length)
|
||||
|
@ -311,6 +293,12 @@ static zend_result dom_html5_serialize_node(dom_html5_serialize_context *ctx, co
|
|||
break;
|
||||
}
|
||||
|
||||
/* Only exists for compatibility with XML and old DOM. */
|
||||
case XML_ENTITY_REF_NODE: {
|
||||
TRY(dom_html5_serialize_entity_ref(ctx, node));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -335,8 +323,7 @@ static zend_result dom_html5_serialize_node(dom_html5_serialize_context *ctx, co
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments (Date 2023-10-18)
|
||||
* Note: this serializes the _children_, excluding the node itself! */
|
||||
/* Note: this serializes the _children_, excluding the node itself! */
|
||||
zend_result dom_html5_serialize(dom_html5_serialize_context *ctx, const xmlNode *node)
|
||||
{
|
||||
/* Step 1. Note that this algorithm serializes children. Only elements, documents, and fragments can have children. */
|
||||
|
@ -357,4 +344,22 @@ zend_result dom_html5_serialize(dom_html5_serialize_context *ctx, const xmlNode
|
|||
return dom_html5_serialize_node(ctx, node->children, node);
|
||||
}
|
||||
|
||||
/* Variant on the above that is equivalent to the "outer HTML". */
|
||||
zend_result dom_html5_serialize_outer(dom_html5_serialize_context *ctx, const xmlNode *node)
|
||||
{
|
||||
if (node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE || node->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
node = node->children;
|
||||
if (!node) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return dom_html5_serialize_node(ctx, node, node->parent);
|
||||
} else {
|
||||
xmlNodePtr old_next = node->next;
|
||||
((xmlNodePtr) node)->next = NULL;
|
||||
zend_result result = dom_html5_serialize_node(ctx, node, node->parent);
|
||||
((xmlNodePtr) node)->next = old_next;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBXML && HAVE_DOM */
|
||||
|
|
|
@ -27,5 +27,6 @@ typedef struct {
|
|||
} dom_html5_serialize_context;
|
||||
|
||||
zend_result dom_html5_serialize(dom_html5_serialize_context *ctx, const xmlNode *node);
|
||||
zend_result dom_html5_serialize_outer(dom_html5_serialize_context *ctx, const xmlNode *node);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -78,6 +78,28 @@ typedef struct _dom_decoding_encoding_ctx {
|
|||
lxb_codepoint_t codepoints[4096];
|
||||
} dom_decoding_encoding_ctx;
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-document-implementation */
|
||||
zend_result dom_modern_document_implementation_read(dom_object *obj, zval *retval)
|
||||
{
|
||||
const uint32_t PROP_INDEX = 14;
|
||||
|
||||
#if ZEND_DEBUG
|
||||
zend_string *implementation_str = ZSTR_INIT_LITERAL("implementation", false);
|
||||
const zend_property_info *prop_info = zend_get_property_info(dom_abstract_base_document_class_entry, implementation_str, 0);
|
||||
zend_string_release_ex(implementation_str, false);
|
||||
ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == PROP_INDEX);
|
||||
#endif
|
||||
|
||||
zval *cached_implementation = OBJ_PROP_NUM(&obj->std, PROP_INDEX);
|
||||
if (Z_ISUNDEF_P(cached_implementation)) {
|
||||
php_dom_create_implementation(cached_implementation, true);
|
||||
}
|
||||
|
||||
ZVAL_OBJ_COPY(retval, Z_OBJ_P(cached_implementation));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void dom_decoding_encoding_ctx_init(dom_decoding_encoding_ctx *ctx)
|
||||
{
|
||||
ctx->encode_data = lxb_encoding_data(LXB_ENCODING_UTF_8);
|
||||
|
@ -279,7 +301,7 @@ static void dom_lexbor_libxml2_bridge_tree_error_reporter(
|
|||
return;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(len <= 1)) {
|
||||
if (len <= 1) {
|
||||
/* Possible with EOF, or single-character tokens, don't use a range in the error display in this case */
|
||||
php_libxml_pretend_ctx_error_ex(
|
||||
application_data->input_name,
|
||||
|
@ -350,23 +372,7 @@ static void dom_post_process_html5_loading(
|
|||
dom_place_remove_element_and_hoist_children(html_node, "body");
|
||||
}
|
||||
if (!observations->has_explicit_html_tag) {
|
||||
/* The HTML node has a single namespace declaration, that we must preserve after removing the node.
|
||||
* However, it's possible the namespace is NULL if DOM\HTML_NO_DEFAULT_NS was set. */
|
||||
if (!(options & DOM_HTML_NO_DEFAULT_NS)) {
|
||||
php_libxml_set_old_ns(lxml_doc, html_node->nsDef);
|
||||
html_node->nsDef = NULL;
|
||||
}
|
||||
dom_place_remove_element_and_hoist_children((xmlNodePtr) lxml_doc, "html");
|
||||
if (!(options & DOM_HTML_NO_DEFAULT_NS) && EXPECTED(lxml_doc->children != NULL)) {
|
||||
xmlNodePtr node = lxml_doc->children;
|
||||
while (node) {
|
||||
/* Fine to use the DOM wrap reconciliation here because it's the "modern" world of DOM,
|
||||
* and no user manipulation happened yet. */
|
||||
xmlDOMWrapCtxt dummy_ctxt = {0};
|
||||
xmlDOMWrapReconcileNamespaces(&dummy_ctxt, node, /* options */ 0);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -720,18 +726,10 @@ PHP_METHOD(DOM_HTMLDocument, createEmpty)
|
|||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
xmlDocPtr lxml_doc = htmlNewDocNoDtD(NULL, NULL);
|
||||
xmlDocPtr lxml_doc = php_dom_create_html_doc();
|
||||
if (UNEXPECTED(lxml_doc == NULL)) {
|
||||
goto oom;
|
||||
}
|
||||
#else
|
||||
xmlDocPtr lxml_doc = xmlNewDoc((const xmlChar *) "1.0");
|
||||
if (UNEXPECTED(lxml_doc == NULL)) {
|
||||
goto oom;
|
||||
}
|
||||
lxml_doc->type = XML_HTML_DOCUMENT_NODE;
|
||||
#endif
|
||||
|
||||
lxml_doc->encoding = xmlStrdup((const xmlChar *) encoding);
|
||||
|
||||
|
@ -741,7 +739,8 @@ PHP_METHOD(DOM_HTMLDocument, createEmpty)
|
|||
(xmlNodePtr) lxml_doc,
|
||||
NULL
|
||||
);
|
||||
intern->document->is_modern_api_class = true;
|
||||
intern->document->class_type = PHP_LIBXML_CLASS_MODERN;
|
||||
intern->document->private_data = php_dom_libxml_ns_mapper_header(php_dom_libxml_ns_mapper_create());
|
||||
return;
|
||||
|
||||
oom:
|
||||
|
@ -852,15 +851,19 @@ PHP_METHOD(DOM_HTMLDocument, createFromString)
|
|||
goto fail_oom;
|
||||
}
|
||||
|
||||
php_dom_libxml_ns_mapper *ns_mapper = php_dom_libxml_ns_mapper_create();
|
||||
|
||||
xmlDocPtr lxml_doc;
|
||||
lexbor_libxml2_bridge_status bridge_status = lexbor_libxml2_bridge_convert_document(
|
||||
document,
|
||||
&lxml_doc,
|
||||
options & XML_PARSE_COMPACT,
|
||||
!(options & DOM_HTML_NO_DEFAULT_NS)
|
||||
!(options & DOM_HTML_NO_DEFAULT_NS),
|
||||
ns_mapper
|
||||
);
|
||||
lexbor_libxml2_bridge_copy_observations(parser->tree, &ctx.observations);
|
||||
if (UNEXPECTED(bridge_status != LEXBOR_LIBXML2_BRIDGE_STATUS_OK)) {
|
||||
php_dom_libxml_ns_mapper_destroy(ns_mapper);
|
||||
php_libxml_ctx_error(
|
||||
NULL,
|
||||
"%s in %s",
|
||||
|
@ -886,7 +889,8 @@ PHP_METHOD(DOM_HTMLDocument, createFromString)
|
|||
(xmlNodePtr) lxml_doc,
|
||||
NULL
|
||||
);
|
||||
intern->document->is_modern_api_class = true;
|
||||
intern->document->class_type = PHP_LIBXML_CLASS_MODERN;
|
||||
intern->document->private_data = php_dom_libxml_ns_mapper_header(ns_mapper);
|
||||
return;
|
||||
|
||||
fail_oom:
|
||||
|
@ -898,6 +902,7 @@ fail_oom:
|
|||
PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
||||
{
|
||||
const char *filename, *override_encoding = NULL;
|
||||
php_dom_libxml_ns_mapper *ns_mapper = NULL;
|
||||
size_t filename_len, override_encoding_len;
|
||||
zend_long options = 0;
|
||||
php_stream *stream = NULL;
|
||||
|
@ -958,7 +963,8 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
|||
dom_setup_parser_encoding_manually((const lxb_char_t *) buf, encoding_data, &decoding_encoding_ctx, &application_data);
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper_ex(filename, "rb", REPORT_ERRORS, /* opened_path */ NULL, php_libxml_get_stream_context());
|
||||
zend_string *opened_path = NULL;
|
||||
stream = php_stream_open_wrapper_ex(filename, "rb", REPORT_ERRORS, &opened_path, php_libxml_get_stream_context());
|
||||
if (!stream) {
|
||||
if (!EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Cannot open file '%s'", filename);
|
||||
|
@ -1035,19 +1041,21 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
|||
goto fail_oom;
|
||||
}
|
||||
|
||||
ns_mapper = php_dom_libxml_ns_mapper_create();
|
||||
|
||||
xmlDocPtr lxml_doc;
|
||||
lexbor_libxml2_bridge_status bridge_status = lexbor_libxml2_bridge_convert_document(
|
||||
document,
|
||||
&lxml_doc,
|
||||
options & XML_PARSE_COMPACT,
|
||||
!(options & DOM_HTML_NO_DEFAULT_NS)
|
||||
!(options & DOM_HTML_NO_DEFAULT_NS),
|
||||
ns_mapper
|
||||
);
|
||||
lexbor_libxml2_bridge_copy_observations(parser->tree, &ctx.observations);
|
||||
if (UNEXPECTED(bridge_status != LEXBOR_LIBXML2_BRIDGE_STATUS_OK)) {
|
||||
php_libxml_ctx_error(NULL, "%s in %s", dom_lexbor_libxml2_bridge_status_code_to_string(bridge_status), filename);
|
||||
lxb_html_document_destroy(document);
|
||||
php_stream_close(stream);
|
||||
RETURN_FALSE;
|
||||
RETVAL_FALSE;
|
||||
goto fail_general;
|
||||
}
|
||||
lxb_html_document_destroy(document);
|
||||
|
||||
|
@ -1059,8 +1067,8 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
|||
lxml_doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
|
||||
}
|
||||
|
||||
if (stream->wrapper == &php_plain_files_wrapper) {
|
||||
xmlChar *converted = xmlPathToURI((const xmlChar *) filename);
|
||||
if (stream->wrapper == &php_plain_files_wrapper && opened_path != NULL) {
|
||||
xmlChar *converted = xmlPathToURI((const xmlChar *) ZSTR_VAL(opened_path));
|
||||
if (UNEXPECTED(!converted)) {
|
||||
goto fail_oom;
|
||||
}
|
||||
|
@ -1080,12 +1088,18 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
|||
xmlFree(converted);
|
||||
lxml_doc->URL = new_buffer;
|
||||
} else {
|
||||
#if PHP_WIN32
|
||||
converted = php_dom_libxml_fix_file_path(converted);
|
||||
#endif
|
||||
lxml_doc->URL = converted;
|
||||
}
|
||||
} else {
|
||||
lxml_doc->URL = xmlStrdup((const xmlChar *) filename);
|
||||
}
|
||||
|
||||
if (opened_path != NULL) {
|
||||
zend_string_release_ex(opened_path, false);
|
||||
}
|
||||
php_stream_close(stream);
|
||||
stream = NULL;
|
||||
|
||||
|
@ -1095,16 +1109,21 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
|
|||
(xmlNodePtr) lxml_doc,
|
||||
NULL
|
||||
);
|
||||
intern->document->is_modern_api_class = true;
|
||||
intern->document->class_type = PHP_LIBXML_CLASS_MODERN;
|
||||
intern->document->private_data = php_dom_libxml_ns_mapper_header(ns_mapper);
|
||||
return;
|
||||
|
||||
fail_oom:
|
||||
php_dom_throw_error(INVALID_STATE_ERR, 1);
|
||||
lxb_html_document_destroy(document);
|
||||
if (stream) {
|
||||
php_stream_close(stream);
|
||||
fail_general:
|
||||
if (ns_mapper != NULL) {
|
||||
php_dom_libxml_ns_mapper_destroy(ns_mapper);
|
||||
}
|
||||
lxb_html_document_destroy(document);
|
||||
php_stream_close(stream);
|
||||
if (opened_path != NULL) {
|
||||
zend_string_release_ex(opened_path, false);
|
||||
}
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
static zend_result dom_write_output_smart_str(void *ctx, const char *buf, size_t size)
|
||||
|
@ -1189,7 +1208,7 @@ static zend_result dom_common_save(dom_output_ctx *output_ctx, const xmlDoc *doc
|
|||
ctx.write_string_len = dom_saveHTML_write_string_len;
|
||||
ctx.write_string = dom_saveHTML_write_string;
|
||||
ctx.application_data = output_ctx;
|
||||
if (UNEXPECTED(dom_html5_serialize(&ctx, node) != SUCCESS)) {
|
||||
if (UNEXPECTED(dom_html5_serialize_outer(&ctx, node) != SUCCESS)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -1265,7 +1284,7 @@ PHP_METHOD(DOM_HTMLDocument, saveHTML)
|
|||
const xmlNode *node;
|
||||
dom_object *intern, *nodeobj;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &nodep, dom_node_class_entry) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &nodep, dom_modern_node_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -1292,12 +1311,6 @@ PHP_METHOD(DOM_HTMLDocument, saveHTML)
|
|||
RETURN_STR(smart_str_extract(&buf));
|
||||
}
|
||||
|
||||
PHP_METHOD(DOM_HTMLDocument, __construct)
|
||||
{
|
||||
/* Private constructor cannot be called. */
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|
||||
zend_result dom_html_document_encoding_write(dom_object *obj, zval *newval)
|
||||
{
|
||||
xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
|
||||
|
|
66
ext/dom/internal_helpers.h
Normal file
66
ext/dom/internal_helpers.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Niels Dossche <nielsdos@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef DOM_INTERNAL_HELPERS
|
||||
#define DOM_INTERNAL_HELPERS
|
||||
|
||||
/* We're using the type flags of the zval to store an extra flag. */
|
||||
#define DOM_Z_OWNED(z, v) ZVAL_PTR(z, (void *) v)
|
||||
#define DOM_Z_UNOWNED(z, v) ZVAL_INDIRECT(z, (void *) v)
|
||||
#define DOM_Z_IS_OWNED(z) (Z_TYPE_P(z) == IS_PTR)
|
||||
|
||||
#ifdef DOM_CE_H
|
||||
|
||||
#define DOM_DEF_GET_CE_FUNC(name) \
|
||||
static zend_always_inline zend_class_entry *dom_get_##name##_ce(bool modern) \
|
||||
{ \
|
||||
return modern ? dom_modern_##name##_class_entry : dom_##name##_class_entry; \
|
||||
}
|
||||
|
||||
static zend_always_inline zend_class_entry *dom_get_html_document_ce(bool modern)
|
||||
{
|
||||
return modern ? dom_html_document_class_entry : dom_document_class_entry;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_class_entry *dom_get_xml_document_ce(bool modern)
|
||||
{
|
||||
return modern ? dom_xml_document_class_entry : dom_document_class_entry;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_class_entry *dom_get_dtd_namednodemap_ce(bool modern)
|
||||
{
|
||||
return modern ? dom_modern_dtd_namednodemap_class_entry : dom_namednodemap_class_entry;
|
||||
}
|
||||
|
||||
DOM_DEF_GET_CE_FUNC(node)
|
||||
DOM_DEF_GET_CE_FUNC(documenttype)
|
||||
DOM_DEF_GET_CE_FUNC(element)
|
||||
DOM_DEF_GET_CE_FUNC(attr)
|
||||
DOM_DEF_GET_CE_FUNC(entity)
|
||||
DOM_DEF_GET_CE_FUNC(entityreference)
|
||||
DOM_DEF_GET_CE_FUNC(processinginstruction)
|
||||
DOM_DEF_GET_CE_FUNC(comment)
|
||||
DOM_DEF_GET_CE_FUNC(text)
|
||||
DOM_DEF_GET_CE_FUNC(cdatasection)
|
||||
DOM_DEF_GET_CE_FUNC(notation)
|
||||
DOM_DEF_GET_CE_FUNC(documentfragment)
|
||||
DOM_DEF_GET_CE_FUNC(namednodemap)
|
||||
DOM_DEF_GET_CE_FUNC(nodelist)
|
||||
DOM_DEF_GET_CE_FUNC(domimplementation)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -71,7 +71,7 @@ zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval)
|
|||
|
||||
/* }}} */
|
||||
|
||||
xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const char *named, bool may_transform)
|
||||
xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const zend_string *named, bool may_transform)
|
||||
{
|
||||
xmlNodePtr itemnode = NULL;
|
||||
if (objmap != NULL) {
|
||||
|
@ -79,9 +79,9 @@ xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, co
|
|||
objmap->nodetype == XML_ENTITY_NODE) {
|
||||
if (objmap->ht) {
|
||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, (const xmlChar *) named);
|
||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, BAD_CAST ZSTR_VAL(named));
|
||||
} else {
|
||||
xmlNotationPtr notep = xmlHashLookup(objmap->ht, (const xmlChar *) named);
|
||||
xmlNotationPtr notep = xmlHashLookup(objmap->ht, BAD_CAST ZSTR_VAL(named));
|
||||
if (notep) {
|
||||
if (may_transform) {
|
||||
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
||||
|
@ -94,14 +94,18 @@ xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, co
|
|||
} else {
|
||||
xmlNodePtr nodep = dom_object_get_node(objmap->baseobj);
|
||||
if (nodep) {
|
||||
itemnode = (xmlNodePtr)xmlHasProp(nodep, (const xmlChar *) named);
|
||||
if (php_dom_follow_spec_intern(objmap->baseobj)) {
|
||||
itemnode = (xmlNodePtr) php_dom_get_attribute_node(nodep, BAD_CAST ZSTR_VAL(named), ZSTR_LEN(named));
|
||||
} else {
|
||||
itemnode = (xmlNodePtr) xmlHasProp(nodep, BAD_CAST ZSTR_VAL(named));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemnode;
|
||||
}
|
||||
|
||||
void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const char *named, zval *return_value)
|
||||
void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, zval *return_value)
|
||||
{
|
||||
int ret;
|
||||
xmlNodePtr itemnode = php_dom_named_node_map_get_named_item(objmap, named, true);
|
||||
|
@ -117,10 +121,9 @@ Since:
|
|||
*/
|
||||
PHP_METHOD(DOMNamedNodeMap, getNamedItem)
|
||||
{
|
||||
size_t namedlen;
|
||||
char *named;
|
||||
zend_string *named;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &named, &namedlen) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &named) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
|
@ -221,9 +224,9 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS)
|
|||
objmap->nodetype == XML_ENTITY_NODE) {
|
||||
if (objmap->ht) {
|
||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, (xmlChar *) named);
|
||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, BAD_CAST named);
|
||||
} else {
|
||||
notep = (xmlNotation *)xmlHashLookup(objmap->ht, (xmlChar *) named);
|
||||
notep = (xmlNotation *)xmlHashLookup(objmap->ht, BAD_CAST named);
|
||||
if (notep) {
|
||||
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
||||
}
|
||||
|
@ -232,7 +235,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS)
|
|||
} else {
|
||||
nodep = dom_object_get_node(objmap->baseobj);
|
||||
if (nodep) {
|
||||
itemnode = (xmlNodePtr)xmlHasNsProp(nodep, (xmlChar *) named, (xmlChar *) uri);
|
||||
itemnode = (xmlNodePtr)xmlHasNsProp(nodep, BAD_CAST named, BAD_CAST uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,32 +22,514 @@
|
|||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "namespace_compat.h"
|
||||
#include "internal_helpers.h"
|
||||
|
||||
bool dom_ns_is_also_an_attribute(const xmlNs *ns) {
|
||||
return ns->_private != NULL;
|
||||
}
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_html_magic_token = (const php_dom_ns_magic_token *) DOM_XHTML_NS_URI;
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_mathml_magic_token = (const php_dom_ns_magic_token *) DOM_MATHML_NS_URI;
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_svg_magic_token = (const php_dom_ns_magic_token *) DOM_SVG_NS_URI;
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_xlink_magic_token = (const php_dom_ns_magic_token *) DOM_XLINK_NS_URI;
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_xml_magic_token = (const php_dom_ns_magic_token *) DOM_XML_NS_URI;
|
||||
PHP_DOM_EXPORT const php_dom_ns_magic_token *php_dom_ns_is_xmlns_magic_token = (const php_dom_ns_magic_token *) DOM_XMLNS_NS_URI;
|
||||
|
||||
void dom_ns_compat_mark_attribute(xmlNsPtr ns) {
|
||||
ns->_private = (void *) 1;
|
||||
}
|
||||
struct _php_dom_libxml_ns_mapper {
|
||||
php_libxml_private_data_header header;
|
||||
/* This is used almost all the time for HTML documents, so it makes sense to cache this. */
|
||||
xmlNsPtr html_ns;
|
||||
/* Used for every prefixless namespace declaration in XML, so also very common. */
|
||||
xmlNsPtr prefixless_xmlns_ns;
|
||||
HashTable uri_to_prefix_map;
|
||||
};
|
||||
|
||||
void dom_ns_compat_mark_attribute_list(xmlNsPtr ns) {
|
||||
while (ns != NULL) {
|
||||
dom_ns_compat_mark_attribute(ns);
|
||||
ns = ns->next;
|
||||
static void php_dom_libxml_ns_mapper_prefix_map_element_dtor(zval *zv)
|
||||
{
|
||||
if (DOM_Z_IS_OWNED(zv)) {
|
||||
efree(Z_PTR_P(zv));
|
||||
}
|
||||
}
|
||||
|
||||
void dom_ns_compat_copy_attribute_list_mark(xmlNsPtr copy, const xmlNs *original) {
|
||||
/* It's possible that the original list is shorter than the copy list
|
||||
* because of additional namespace copies from within a fragment. */
|
||||
while (original != NULL) {
|
||||
ZEND_ASSERT(copy != NULL);
|
||||
if (dom_ns_is_also_an_attribute(original)) {
|
||||
dom_ns_compat_mark_attribute(copy);
|
||||
static HashTable *php_dom_libxml_ns_mapper_ensure_prefix_map(php_dom_libxml_ns_mapper *mapper, zend_string **uri)
|
||||
{
|
||||
zval *zv = zend_hash_find(&mapper->uri_to_prefix_map, *uri);
|
||||
HashTable *prefix_map;
|
||||
if (zv == NULL) {
|
||||
prefix_map = emalloc(sizeof(HashTable));
|
||||
zend_hash_init(prefix_map, 0, NULL, php_dom_libxml_ns_mapper_prefix_map_element_dtor, false);
|
||||
zval zv;
|
||||
ZVAL_ARR(&zv, prefix_map);
|
||||
zend_hash_add_new(&mapper->uri_to_prefix_map, *uri, &zv);
|
||||
} else {
|
||||
/* cast to Bucket* only works if this holds, I would prefer a static assert but we're stuck at C99. */
|
||||
ZEND_ASSERT(XtOffsetOf(Bucket, val) == 0);
|
||||
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
|
||||
Bucket *bucket = (Bucket *) zv;
|
||||
/* Make sure we take the value from the key string that lives long enough. */
|
||||
*uri = bucket->key;
|
||||
prefix_map = Z_ARRVAL_P(zv);
|
||||
}
|
||||
copy = copy->next;
|
||||
original = original->next;
|
||||
return prefix_map;
|
||||
}
|
||||
|
||||
static void php_dom_libxml_ns_mapper_header_destroy(php_libxml_private_data_header *header)
|
||||
{
|
||||
php_dom_libxml_ns_mapper_destroy((php_dom_libxml_ns_mapper *) header);
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT php_dom_libxml_ns_mapper *php_dom_libxml_ns_mapper_create(void)
|
||||
{
|
||||
php_dom_libxml_ns_mapper *mapper = emalloc(sizeof(*mapper));
|
||||
mapper->header.dtor = php_dom_libxml_ns_mapper_header_destroy;
|
||||
mapper->html_ns = NULL;
|
||||
mapper->prefixless_xmlns_ns = NULL;
|
||||
zend_hash_init(&mapper->uri_to_prefix_map, 0, NULL, ZVAL_PTR_DTOR, false);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
void php_dom_libxml_ns_mapper_destroy(php_dom_libxml_ns_mapper *mapper)
|
||||
{
|
||||
zend_hash_destroy(&mapper->uri_to_prefix_map);
|
||||
efree(mapper);
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
if (EXPECTED(*ptr != NULL)) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
zend_string *uri_str = zend_string_init(uri, length, false);
|
||||
*ptr = php_dom_libxml_ns_mapper_get_ns(mapper, NULL, uri_str);
|
||||
(*ptr)->_private = (void *) token;
|
||||
zend_string_release_ex(uri_str, false);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_html_ns(php_dom_libxml_ns_mapper *mapper)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(php_dom_libxml_ns_mapper *mapper)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static xmlNsPtr dom_create_owned_ns(zend_string *prefix, zend_string *uri)
|
||||
{
|
||||
ZEND_ASSERT(prefix != NULL);
|
||||
ZEND_ASSERT(uri != NULL);
|
||||
|
||||
xmlNsPtr ns = emalloc(sizeof(*ns));
|
||||
memset(ns, 0, sizeof(*ns));
|
||||
ns->type = XML_LOCAL_NAMESPACE;
|
||||
/* These two strings are kept alive because they're the hash table keys that lead to this entry. */
|
||||
ns->prefix = ZSTR_LEN(prefix) == 0 ? NULL : BAD_CAST ZSTR_VAL(prefix);
|
||||
ns->href = BAD_CAST ZSTR_VAL(uri);
|
||||
/* Note ns->context is unused in libxml2 at the moment, and if it were used it would be for
|
||||
* LIBXML_NAMESPACE_DICT which is opt-in anyway. */
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns(php_dom_libxml_ns_mapper *mapper, zend_string *prefix, zend_string *uri)
|
||||
{
|
||||
if (uri == NULL) {
|
||||
uri = zend_empty_string;
|
||||
}
|
||||
|
||||
if (prefix == NULL) {
|
||||
prefix = zend_empty_string;
|
||||
}
|
||||
|
||||
if (ZSTR_LEN(prefix) == 0 && ZSTR_LEN(uri) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HashTable *prefix_map = php_dom_libxml_ns_mapper_ensure_prefix_map(mapper, &uri);
|
||||
xmlNsPtr found = zend_hash_find_ptr(prefix_map, prefix);
|
||||
if (found != NULL) {
|
||||
return found;
|
||||
}
|
||||
|
||||
xmlNsPtr ns = dom_create_owned_ns(prefix, uri);
|
||||
|
||||
zval new_zv;
|
||||
DOM_Z_OWNED(&new_zv, ns);
|
||||
zend_hash_add_new(prefix_map, prefix, &new_zv);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
xmlNsPtr ns;
|
||||
if (prefix_len == 0) {
|
||||
/* Fast path */
|
||||
ns = php_dom_libxml_ns_mapper_get_ns(mapper, zend_empty_string, uri);
|
||||
} else {
|
||||
zend_string *prefix_str = zend_string_init((const char *) prefix, prefix_len, false);
|
||||
ns = php_dom_libxml_ns_mapper_get_ns(mapper, prefix_str, uri);
|
||||
zend_string_release_ex(prefix_str, false);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
zend_string *prefix_str = zend_string_init(prefix, prefix_len, false);
|
||||
zend_string *uri_str = zend_string_init(uri, uri_len, false);
|
||||
xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns(mapper, prefix_str, uri_str);
|
||||
zend_string_release_ex(prefix_str, false);
|
||||
zend_string_release_ex(uri_str, false);
|
||||
return ns;
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
return php_dom_libxml_ns_mapper_get_ns_raw_strings_ex(mapper, prefix, strlen(prefix), uri, strlen(uri));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (prefix == NULL) {
|
||||
prefix = "";
|
||||
}
|
||||
if (uri == NULL) {
|
||||
uri = "";
|
||||
}
|
||||
return php_dom_libxml_ns_mapper_get_ns_raw_strings(mapper, prefix, uri);
|
||||
}
|
||||
|
||||
static xmlNsPtr php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(php_dom_libxml_ns_mapper *mapper, xmlNsPtr ns)
|
||||
{
|
||||
ZEND_ASSERT(ns != NULL);
|
||||
|
||||
zend_string *href_str = zend_string_init((const char *) ns->href, xmlStrlen(ns->href), false);
|
||||
zend_string *href_str_orig = href_str;
|
||||
HashTable *prefix_map = php_dom_libxml_ns_mapper_ensure_prefix_map(mapper, &href_str);
|
||||
zend_string_release_ex(href_str_orig, false);
|
||||
|
||||
const char *prefix = (const char *) ns->prefix;
|
||||
size_t prefix_len;
|
||||
if (prefix == NULL) {
|
||||
prefix = "";
|
||||
prefix_len = 0;
|
||||
} else {
|
||||
prefix_len = xmlStrlen(ns->prefix);
|
||||
}
|
||||
|
||||
zval *zv = zend_hash_str_find_ptr(prefix_map, prefix, prefix_len);
|
||||
if (zv != NULL) {
|
||||
return Z_PTR_P(zv);
|
||||
}
|
||||
|
||||
zval new_zv;
|
||||
DOM_Z_UNOWNED(&new_zv, ns);
|
||||
zend_hash_str_add_new(prefix_map, prefix, prefix_len, &new_zv);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT php_libxml_private_data_header *php_dom_libxml_ns_mapper_header(php_dom_libxml_ns_mapper *mapper)
|
||||
{
|
||||
return mapper == NULL ? NULL : &mapper->header;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/* Fast lookup for created mappings. */
|
||||
HashTable old_ns_to_new_ns_ptr;
|
||||
/* It is common that the last created mapping will be used for a while,
|
||||
* cache it too to bypass the hash table. */
|
||||
xmlNsPtr last_mapped_src, last_mapped_dst;
|
||||
php_dom_libxml_ns_mapper *ns_mapper;
|
||||
} dom_libxml_reconcile_ctx;
|
||||
|
||||
PHP_DOM_EXPORT xmlAttrPtr php_dom_ns_compat_mark_attribute(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node, xmlNsPtr ns)
|
||||
{
|
||||
xmlNsPtr xmlns_ns;
|
||||
const xmlChar *name;
|
||||
if (ns->prefix != NULL) {
|
||||
xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings(mapper, "xmlns", DOM_XMLNS_NS_URI);
|
||||
name = ns->prefix;
|
||||
} else {
|
||||
xmlns_ns = php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(mapper);
|
||||
name = BAD_CAST "xmlns";
|
||||
}
|
||||
|
||||
ZEND_ASSERT(xmlns_ns != NULL);
|
||||
|
||||
return xmlSetNsProp(node, xmlns_ns, name, ns->href);
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT void php_dom_ns_compat_mark_attribute_list(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node)
|
||||
{
|
||||
if (node->nsDef == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We want to prepend at the front, but in order of the namespace definitions.
|
||||
* So temporarily unlink the existing properties and add them again at the end. */
|
||||
xmlAttrPtr attr = node->properties;
|
||||
node->properties = NULL;
|
||||
|
||||
xmlNsPtr ns = node->nsDef;
|
||||
xmlAttrPtr last_added = NULL;
|
||||
do {
|
||||
last_added = php_dom_ns_compat_mark_attribute(mapper, node, ns);
|
||||
php_dom_libxml_ns_mapper_store_and_normalize_parsed_ns(mapper, ns);
|
||||
xmlNsPtr next = ns->next;
|
||||
ns->next = NULL;
|
||||
php_libxml_set_old_ns(node->doc, ns);
|
||||
ns = next;
|
||||
} while (ns != NULL);
|
||||
|
||||
if (last_added != NULL) {
|
||||
/* node->properties now points to the first namespace declaration attribute. */
|
||||
if (attr != NULL) {
|
||||
last_added->next = attr;
|
||||
attr->prev = last_added;
|
||||
}
|
||||
} else {
|
||||
/* Nothing added, so nothing changed. Only really possible on OOM. */
|
||||
node->properties = attr;
|
||||
}
|
||||
|
||||
node->nsDef = NULL;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT bool php_dom_ns_is_fast_ex(xmlNsPtr ns, const php_dom_ns_magic_token *magic_token)
|
||||
{
|
||||
ZEND_ASSERT(ns != NULL);
|
||||
/* cached for fast checking */
|
||||
if (ns->_private == magic_token) {
|
||||
return true;
|
||||
} else if (ns->_private != NULL) {
|
||||
/* Other token stored */
|
||||
return false;
|
||||
}
|
||||
/* Slow path */
|
||||
if (xmlStrEqual(ns->href, BAD_CAST magic_token)) {
|
||||
ns->_private = (void *) magic_token;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT bool php_dom_ns_is_fast(const xmlNode *nodep, const php_dom_ns_magic_token *magic_token)
|
||||
{
|
||||
ZEND_ASSERT(nodep != NULL);
|
||||
xmlNsPtr ns = nodep->ns;
|
||||
if (ns != NULL) {
|
||||
return php_dom_ns_is_fast_ex(ns, magic_token);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT bool php_dom_ns_is_html_and_document_is_html(const xmlNode *nodep)
|
||||
{
|
||||
ZEND_ASSERT(nodep != NULL);
|
||||
return nodep->doc && nodep->doc->type == XML_HTML_DOCUMENT_NODE && php_dom_ns_is_fast(nodep, php_dom_ns_is_html_magic_token);
|
||||
}
|
||||
|
||||
/* will rename prefixes if there is a declaration with the same prefix but different uri. */
|
||||
PHP_DOM_EXPORT void php_dom_reconcile_attribute_namespace_after_insertion(xmlAttrPtr attrp)
|
||||
{
|
||||
ZEND_ASSERT(attrp != NULL);
|
||||
|
||||
if (attrp->ns != NULL) {
|
||||
/* Try to link to an existing namespace. If that won't work, reconcile. */
|
||||
xmlNodePtr nodep = attrp->parent;
|
||||
xmlNsPtr matching_ns = xmlSearchNs(nodep->doc, nodep, attrp->ns->prefix);
|
||||
if (matching_ns && xmlStrEqual(matching_ns->href, attrp->ns->href)) {
|
||||
/* Doesn't leak because this doesn't define the declaration. */
|
||||
attrp->ns = matching_ns;
|
||||
} else {
|
||||
if (attrp->ns->prefix != NULL) {
|
||||
/* Note: explicitly use the legacy reconciliation as it mostly (i.e. as good as it gets for legacy DOM)
|
||||
* does the right thing for attributes. */
|
||||
xmlReconciliateNs(nodep->doc, nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline zend_long dom_mangle_pointer_for_key(void *ptr)
|
||||
{
|
||||
zend_ulong value = (zend_ulong) (uintptr_t) ptr;
|
||||
/* Shift 3/4 for better hash distribution because the low 3/4 bits are always 0. */
|
||||
#if SIZEOF_ZEND_LONG == 8
|
||||
return value >> 4;
|
||||
#else
|
||||
return value >> 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_always_inline void php_dom_libxml_reconcile_modern_single_node(dom_libxml_reconcile_ctx *ctx, xmlNodePtr ns_holder, xmlNodePtr node)
|
||||
{
|
||||
ZEND_ASSERT(node->ns != NULL);
|
||||
|
||||
if (node->ns == ctx->last_mapped_src) {
|
||||
node->ns = ctx->last_mapped_dst;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the namespace is the same as in the map, we're good. */
|
||||
xmlNsPtr new_ns = zend_hash_index_find_ptr(&ctx->old_ns_to_new_ns_ptr, dom_mangle_pointer_for_key(node->ns));
|
||||
if (new_ns == NULL) {
|
||||
/* We have to create an alternative declaration, and we'll add it to the map. */
|
||||
const char *prefix = (const char *) node->ns->prefix;
|
||||
const char *href = (const char *) node->ns->href;
|
||||
new_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ctx->ns_mapper, prefix, href);
|
||||
zend_hash_index_add_new_ptr(&ctx->old_ns_to_new_ns_ptr, dom_mangle_pointer_for_key(node->ns), new_ns);
|
||||
ctx->last_mapped_src = node->ns;
|
||||
ctx->last_mapped_dst = new_ns;
|
||||
node->ns = new_ns;
|
||||
} else if (node->ns != new_ns) {
|
||||
/* The namespace is different, so we have to replace it. */
|
||||
node->ns = new_ns;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline bool dom_libxml_reconcile_fast_element_skip(xmlNodePtr node)
|
||||
{
|
||||
/* Fast path: this is a lone element and the namespace is defined by the node (or the namespace is NULL). */
|
||||
ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
|
||||
return node->children == NULL && node->properties == NULL && node->ns == node->nsDef;
|
||||
}
|
||||
|
||||
static zend_always_inline void php_dom_libxml_reconcile_modern_single_element_node(dom_libxml_reconcile_ctx *ctx, xmlNodePtr node)
|
||||
{
|
||||
ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
|
||||
|
||||
/* Since this is modern DOM, the declarations are not on the node and thus there's nothing to add from nsDef. */
|
||||
ZEND_ASSERT(node->nsDef == NULL);
|
||||
|
||||
if (node->ns != NULL) {
|
||||
php_dom_libxml_reconcile_modern_single_node(ctx, node, node);
|
||||
}
|
||||
|
||||
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
|
||||
if (attr->ns != NULL) {
|
||||
php_dom_libxml_reconcile_modern_single_node(ctx, node, (xmlNodePtr) attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT void php_dom_libxml_reconcile_modern(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node)
|
||||
{
|
||||
if (node->type == XML_ATTRIBUTE_NODE) {
|
||||
if (node->ns != NULL) {
|
||||
node->ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, (const char *) node->ns->prefix, (const char *) node->ns->href);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE || dom_libxml_reconcile_fast_element_skip(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dom_libxml_reconcile_ctx ctx;
|
||||
zend_hash_init(&ctx.old_ns_to_new_ns_ptr, 0, NULL, NULL, 0);
|
||||
ctx.last_mapped_src = NULL;
|
||||
ctx.last_mapped_dst = NULL;
|
||||
ctx.ns_mapper = ns_mapper;
|
||||
|
||||
php_dom_libxml_reconcile_modern_single_element_node(&ctx, node);
|
||||
|
||||
xmlNodePtr base = node;
|
||||
node = node->children;
|
||||
while (node != NULL) {
|
||||
ZEND_ASSERT(node != base);
|
||||
|
||||
if (node->type == XML_ELEMENT_NODE) {
|
||||
php_dom_libxml_reconcile_modern_single_element_node(&ctx, node);
|
||||
|
||||
if (node->children) {
|
||||
node = node->children;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
node = php_dom_next_in_tree_order(node, base);
|
||||
}
|
||||
|
||||
zend_hash_destroy(&ctx.old_ns_to_new_ns_ptr);
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node)
|
||||
{
|
||||
ZEND_ASSERT(node != NULL);
|
||||
|
||||
php_dom_in_scope_ns in_scope_ns;
|
||||
in_scope_ns.origin_is_ns_compat = true;
|
||||
|
||||
/* libxml fetches all nsDef items from bottom to top - left to right, ignoring prefixes already in the list.
|
||||
* We don't have nsDef, but we can use the ns pointer (as that is necessarily in scope),
|
||||
* and check the xmlns attributes. */
|
||||
HashTable tmp_prefix_to_ns_table;
|
||||
zend_hash_init(&tmp_prefix_to_ns_table, 0, NULL, NULL, false);
|
||||
zend_hash_real_init_mixed(&tmp_prefix_to_ns_table);
|
||||
|
||||
for (const xmlNode *cur = node; cur != NULL; cur = cur->parent) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
/* Register namespace of element */
|
||||
if (cur->ns != NULL && cur->ns->prefix != NULL) {
|
||||
const char *prefix = (const char *) cur->ns->prefix;
|
||||
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), cur->ns);
|
||||
}
|
||||
|
||||
/* Register xmlns attributes */
|
||||
for (const xmlAttr *attr = cur->properties; attr != NULL; attr = attr->next) {
|
||||
if (attr->ns != NULL && attr->ns->prefix != NULL && php_dom_ns_is_fast_ex(attr->ns, php_dom_ns_is_xmlns_magic_token)
|
||||
&& attr->children != NULL && attr->children->content != NULL) {
|
||||
/* This attribute declares a namespace, get the relevant instance.
|
||||
* The declared namespace is not the same as the namespace of this attribute (which is xmlns). */
|
||||
const char *prefix = (const char *) attr->name;
|
||||
xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_strings(ns_mapper, prefix, (const char *) attr->children->content);
|
||||
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_scope_ns.count = zend_hash_num_elements(&tmp_prefix_to_ns_table);
|
||||
in_scope_ns.list = safe_emalloc(in_scope_ns.count, sizeof(xmlNsPtr), 0);
|
||||
|
||||
size_t index = 0;
|
||||
xmlNsPtr ns;
|
||||
ZEND_HASH_MAP_FOREACH_PTR(&tmp_prefix_to_ns_table, ns) {
|
||||
in_scope_ns.list[index++] = ns;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_destroy(&tmp_prefix_to_ns_table);
|
||||
|
||||
return in_scope_ns;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns_legacy(const xmlNode *node)
|
||||
{
|
||||
ZEND_ASSERT(node != NULL);
|
||||
|
||||
php_dom_in_scope_ns in_scope_ns;
|
||||
in_scope_ns.origin_is_ns_compat = false;
|
||||
in_scope_ns.list = xmlGetNsList(node->doc, node);
|
||||
in_scope_ns.count = 0;
|
||||
|
||||
if (in_scope_ns.list != NULL) {
|
||||
while (in_scope_ns.list[in_scope_ns.count] != NULL) {
|
||||
in_scope_ns.count++;
|
||||
}
|
||||
}
|
||||
|
||||
return in_scope_ns;
|
||||
}
|
||||
|
||||
PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns)
|
||||
{
|
||||
ZEND_ASSERT(in_scope_ns != NULL);
|
||||
if (in_scope_ns->origin_is_ns_compat) {
|
||||
efree(in_scope_ns->list);
|
||||
} else {
|
||||
xmlFree(in_scope_ns->list);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#ifndef NAMESPACE_COMPAT_H
|
||||
#define NAMESPACE_COMPAT_H
|
||||
|
||||
#include <libxml/tree.h>
|
||||
#include "xml_common.h"
|
||||
|
||||
/* https://infra.spec.whatwg.org/#namespaces */
|
||||
#define DOM_XHTML_NS_URI "http://www.w3.org/1999/xhtml"
|
||||
|
@ -27,13 +27,51 @@
|
|||
#define DOM_XML_NS_URI "http://www.w3.org/XML/1998/namespace"
|
||||
#define DOM_XMLNS_NS_URI "http://www.w3.org/2000/xmlns/"
|
||||
|
||||
/* These functions make it possible to make a namespace declaration also visible as an attribute by
|
||||
* setting a flag that can be checked with dom_ns_is_also_an_attribute().
|
||||
* This is used in the serializer for example. */
|
||||
struct php_dom_ns_magic_token;
|
||||
typedef struct php_dom_ns_magic_token php_dom_ns_magic_token;
|
||||
|
||||
bool dom_ns_is_also_an_attribute(const xmlNs *ns);
|
||||
void dom_ns_compat_mark_attribute(xmlNsPtr ns);
|
||||
void dom_ns_compat_mark_attribute_list(xmlNsPtr ns);
|
||||
void dom_ns_compat_copy_attribute_list_mark(xmlNsPtr copy, const xmlNs *original);
|
||||
struct _php_dom_libxml_ns_mapper;
|
||||
typedef struct _php_dom_libxml_ns_mapper php_dom_libxml_ns_mapper;
|
||||
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_html_magic_token;
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_mathml_magic_token;
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_svg_magic_token;
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_xlink_magic_token;
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_xml_magic_token;
|
||||
PHP_DOM_EXPORT extern const php_dom_ns_magic_token *php_dom_ns_is_xmlns_magic_token;
|
||||
|
||||
typedef struct _php_libxml_private_data_header php_libxml_private_data_header;
|
||||
struct _php_libxml_private_data_header;
|
||||
|
||||
/* These functions make it possible to make a namespace declaration also visible as an attribute by
|
||||
* creating an equivalent attribute node. */
|
||||
|
||||
PHP_DOM_EXPORT php_dom_libxml_ns_mapper *php_dom_libxml_ns_mapper_create(void);
|
||||
PHP_DOM_EXPORT void php_dom_libxml_ns_mapper_destroy(php_dom_libxml_ns_mapper *mapper);
|
||||
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_html_ns(php_dom_libxml_ns_mapper *mapper);
|
||||
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(php_dom_libxml_ns_mapper *mapper);
|
||||
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 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_get_ns_raw_strings_nullsafe(php_dom_libxml_ns_mapper *mapper, const char *prefix, const char *uri);
|
||||
|
||||
PHP_DOM_EXPORT php_libxml_private_data_header *php_dom_libxml_ns_mapper_header(php_dom_libxml_ns_mapper *mapper);
|
||||
PHP_DOM_EXPORT void php_dom_ns_compat_mark_attribute_list(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node);
|
||||
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 xmlAttrPtr php_dom_ns_compat_mark_attribute(php_dom_libxml_ns_mapper *mapper, xmlNodePtr node, xmlNsPtr ns);
|
||||
|
||||
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_fast_ex(xmlNsPtr ns, const php_dom_ns_magic_token *magic_token);
|
||||
PHP_DOM_EXPORT bool php_dom_ns_is_html_and_document_is_html(const xmlNode *nodep);
|
||||
|
||||
typedef struct _php_dom_in_scope_ns {
|
||||
xmlNsPtr *list;
|
||||
size_t count;
|
||||
bool origin_is_ns_compat;
|
||||
} php_dom_in_scope_ns;
|
||||
|
||||
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node);
|
||||
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns_legacy(const xmlNode *node);
|
||||
PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns);
|
||||
|
||||
#endif
|
||||
|
|
793
ext/dom/node.c
793
ext/dom/node.c
File diff suppressed because it is too large
Load diff
|
@ -99,7 +99,7 @@ int php_dom_get_nodelist_length(dom_object *obj)
|
|||
nodep = nodep->children;
|
||||
}
|
||||
dom_get_elements_by_tag_name_ns_raw(
|
||||
basep, nodep, (char *) objmap->ns, (char *) objmap->local, &count, INT_MAX - 1 /* because of <= */);
|
||||
basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, INT_MAX - 1 /* because of <= */);
|
||||
}
|
||||
|
||||
objmap->cached_length = count;
|
||||
|
@ -200,7 +200,7 @@ void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long
|
|||
nodep = basep->children;
|
||||
}
|
||||
}
|
||||
itemnode = dom_get_elements_by_tag_name_ns_raw(basep, nodep, (char *) objmap->ns, (char *) objmap->local, &count, relative_index);
|
||||
itemnode = dom_get_elements_by_tag_name_ns_raw(basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, relative_index);
|
||||
}
|
||||
cache_itemnode = true;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Benjamin Eberlei <beberlei@php.net> |
|
||||
| Niels Dossche <nielsdos@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "internal_helpers.h"
|
||||
|
||||
/* {{{ firstElementChild DomParentNode
|
||||
readonly=yes
|
||||
|
@ -39,7 +41,7 @@ zend_result dom_parent_node_first_element_child_read(dom_object *obj, zval *retv
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(nodep) == SUCCESS) {
|
||||
if (dom_node_children_valid(nodep)) {
|
||||
first = nodep->children;
|
||||
|
||||
while (first && first->type != XML_ELEMENT_NODE) {
|
||||
|
@ -72,7 +74,7 @@ zend_result dom_parent_node_last_element_child_read(dom_object *obj, zval *retva
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(nodep) == SUCCESS) {
|
||||
if (dom_node_children_valid(nodep)) {
|
||||
last = nodep->last;
|
||||
|
||||
while (last && last->type != XML_ELEMENT_NODE) {
|
||||
|
@ -106,7 +108,7 @@ zend_result dom_parent_node_child_element_count(dom_object *obj, zval *retval)
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(nodep) == SUCCESS) {
|
||||
if (dom_node_children_valid(nodep)) {
|
||||
first = nodep->children;
|
||||
|
||||
while (first != NULL) {
|
||||
|
@ -146,75 +148,20 @@ static xmlDocPtr dom_doc_from_context_node(xmlNodePtr contextNode)
|
|||
}
|
||||
}
|
||||
|
||||
xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, int nodesc)
|
||||
{
|
||||
xmlDoc *documentNode;
|
||||
xmlNode *fragment;
|
||||
xmlNode *newNode;
|
||||
dom_object *newNodeObj;
|
||||
|
||||
documentNode = dom_doc_from_context_node(contextNode);
|
||||
|
||||
fragment = xmlNewDocFragment(documentNode);
|
||||
|
||||
if (!fragment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < nodesc; i++) {
|
||||
if (Z_TYPE(nodes[i]) == IS_OBJECT) {
|
||||
newNodeObj = Z_DOMOBJ_P(&nodes[i]);
|
||||
newNode = dom_object_get_node(newNodeObj);
|
||||
|
||||
if (newNode->parent != NULL) {
|
||||
xmlUnlinkNode(newNode);
|
||||
}
|
||||
|
||||
newNodeObj->document = document;
|
||||
xmlSetTreeDoc(newNode, documentNode);
|
||||
|
||||
/* Citing from the docs (https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/libxml2-tree.html#xmlAddChild):
|
||||
* "Add a new node to @parent, at the end of the child (or property) list merging adjacent TEXT nodes (in which case @cur is freed)".
|
||||
* So we must take a copy if this situation arises to prevent a use-after-free. */
|
||||
bool will_free = newNode->type == XML_TEXT_NODE && fragment->last && fragment->last->type == XML_TEXT_NODE;
|
||||
if (will_free) {
|
||||
newNode = xmlCopyNode(newNode, 1);
|
||||
}
|
||||
|
||||
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
/* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */
|
||||
newNode = newNode->children;
|
||||
while (newNode) {
|
||||
xmlNodePtr next = newNode->next;
|
||||
xmlUnlinkNode(newNode);
|
||||
if (!xmlAddChild(fragment, newNode)) {
|
||||
goto err;
|
||||
}
|
||||
newNode = next;
|
||||
}
|
||||
} else if (!xmlAddChild(fragment, newNode)) {
|
||||
if (will_free) {
|
||||
xmlFreeNode(newNode);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
* So we must use a custom way of adding that does not merge. */
|
||||
static void dom_add_child_without_merging(xmlNodePtr parent, xmlNodePtr child)
|
||||
{
|
||||
if (parent->children == NULL) {
|
||||
parent->children = child;
|
||||
} else {
|
||||
ZEND_ASSERT(Z_TYPE(nodes[i]) == IS_STRING);
|
||||
|
||||
newNode = xmlNewDocText(documentNode, (xmlChar *) Z_STRVAL(nodes[i]));
|
||||
|
||||
if (!xmlAddChild(fragment, newNode)) {
|
||||
xmlFreeNode(newNode);
|
||||
goto err;
|
||||
xmlNodePtr last = parent->last;
|
||||
last->next = child;
|
||||
child->prev = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fragment;
|
||||
|
||||
err:
|
||||
xmlFreeNode(fragment);
|
||||
return NULL;
|
||||
parent->last = child;
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fragment)
|
||||
|
@ -229,43 +176,294 @@ static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fr
|
|||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
fragment->children = NULL;
|
||||
fragment->last = NULL;
|
||||
}
|
||||
|
||||
static zend_result dom_sanity_check_node_list_for_insertion(php_libxml_ref_obj *document, xmlNodePtr parentNode, zval *nodes, int nodesc)
|
||||
/* This part is common logic between the pre-insertion validity and replaceChild code. */
|
||||
static bool dom_fragment_common_hierarchy_check_part(xmlNodePtr node, bool *seen_element)
|
||||
{
|
||||
if (UNEXPECTED(parentNode == NULL)) {
|
||||
/* No error required, this must be a no-op per spec */
|
||||
return FAILURE;
|
||||
/* If node has more than one element child or has a Text node child. */
|
||||
xmlNodePtr iter = node->children;
|
||||
*seen_element = false;
|
||||
while (iter != NULL) {
|
||||
if (iter->type == XML_ELEMENT_NODE) {
|
||||
if (*seen_element) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot have more than one element child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
*seen_element = true;
|
||||
} else if (iter->type == XML_TEXT_NODE || iter->type == XML_CDATA_SECTION_NODE) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot insert text as a child of a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
xmlDocPtr documentNode = dom_doc_from_context_node(parentNode);
|
||||
/* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
||||
* DocumentFragment validation part. */
|
||||
bool php_dom_fragment_insertion_hierarchy_check_pre_insertion(xmlNodePtr parent, xmlNodePtr node, xmlNodePtr child)
|
||||
{
|
||||
bool seen_element;
|
||||
if (!dom_fragment_common_hierarchy_check_part(node, &seen_element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise, if node has one element child
|
||||
* and either parent has an element child, child is a doctype, or child is non-null and a doctype is following child. */
|
||||
if (seen_element) {
|
||||
if (php_dom_has_child_of_type(parent, XML_ELEMENT_NODE)) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot have more than one element child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child != NULL && (child->type == XML_DTD_NODE || php_dom_has_sibling_following_node(child, XML_DTD_NODE))) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Document types must be the first child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-replace
|
||||
* DocumentFragment validation part. */
|
||||
bool php_dom_fragment_insertion_hierarchy_check_replace(xmlNodePtr parent, xmlNodePtr node, xmlNodePtr child)
|
||||
{
|
||||
bool seen_element;
|
||||
if (!dom_fragment_common_hierarchy_check_part(node, &seen_element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise, if node has one element child
|
||||
* and either parent has an element child that is not child or a doctype is following child. */
|
||||
if (seen_element) {
|
||||
xmlNodePtr iter = parent->children;
|
||||
while (iter != NULL) {
|
||||
if (iter->type == XML_ELEMENT_NODE && iter != child) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot have more than one element child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
ZEND_ASSERT(child != NULL);
|
||||
if (php_dom_has_sibling_following_node(child, XML_DTD_NODE)) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Document types must be the first child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity */
|
||||
bool php_dom_pre_insert_is_parent_invalid(xmlNodePtr parent)
|
||||
{
|
||||
return parent->type != XML_DOCUMENT_NODE
|
||||
&& parent->type != XML_HTML_DOCUMENT_NODE
|
||||
&& parent->type != XML_ELEMENT_NODE
|
||||
&& parent->type != XML_DOCUMENT_FRAG_NODE;
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity */
|
||||
static bool dom_is_pre_insert_valid_without_step_1(php_libxml_ref_obj *document, xmlNodePtr parentNode, xmlNodePtr node, xmlNodePtr child, xmlDocPtr documentNode)
|
||||
{
|
||||
ZEND_ASSERT(parentNode != NULL);
|
||||
|
||||
/* 1. If parent is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
|
||||
* => Impossible */
|
||||
ZEND_ASSERT(!php_dom_pre_insert_is_parent_invalid(parentNode));
|
||||
|
||||
if (node->doc != documentNode) {
|
||||
php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(document));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 3. If child is non-null and its parent is not parent, then throw a "NotFoundError" DOMException. */
|
||||
if (child != NULL && child->parent != parentNode) {
|
||||
php_dom_throw_error(NOT_FOUND_ERR, dom_get_strict_error(document));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parent_is_document = parentNode->type == XML_DOCUMENT_NODE || parentNode->type == XML_HTML_DOCUMENT_NODE;
|
||||
|
||||
if (/* 2. If node is a host-including inclusive ancestor of parent, then throw a "HierarchyRequestError" DOMException. */
|
||||
dom_hierarchy(parentNode, node) != SUCCESS
|
||||
/* 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException. */
|
||||
|| node->type == XML_ATTRIBUTE_NODE
|
||||
|| (php_dom_follow_spec_doc_ref(document) && (
|
||||
node->type == XML_ENTITY_REF_NODE
|
||||
|| node->type == XML_ENTITY_NODE
|
||||
|| node->type == XML_NOTATION_NODE
|
||||
|| node->type == XML_DOCUMENT_NODE
|
||||
|| node->type == XML_HTML_DOCUMENT_NODE
|
||||
|| node->type >= XML_ELEMENT_DECL))) {
|
||||
php_dom_throw_error(HIERARCHY_REQUEST_ERR, dom_get_strict_error(document));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (php_dom_follow_spec_doc_ref(document)) {
|
||||
/* 5. If either node is a Text node and parent is a document... */
|
||||
if (parent_is_document && (node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE)) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot insert text as a child of a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 5. ..., or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException. */
|
||||
if (!parent_is_document && node->type == XML_DTD_NODE) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot insert a document type into anything other than a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 6. If parent is a document, and any of the statements below, switched on the interface node implements,
|
||||
* are true, then throw a "HierarchyRequestError" DOMException. */
|
||||
if (parent_is_document) {
|
||||
/* DocumentFragment */
|
||||
if (node->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
if (!php_dom_fragment_insertion_hierarchy_check_pre_insertion(parentNode, node, child)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Element */
|
||||
else if (node->type == XML_ELEMENT_NODE) {
|
||||
/* parent has an element child, child is a doctype, or child is non-null and a doctype is following child. */
|
||||
if (php_dom_has_child_of_type(parentNode, XML_ELEMENT_NODE)) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot have more than one element child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
if (child != NULL && (child->type == XML_DTD_NODE || php_dom_has_sibling_following_node(child, XML_DTD_NODE))) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Document types must be the first child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* DocumentType */
|
||||
else if (node->type == XML_DTD_NODE) {
|
||||
/* parent has a doctype child, child is non-null and an element is preceding child, or child is null and parent has an element child. */
|
||||
if (php_dom_has_child_of_type(parentNode, XML_DTD_NODE)) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Cannot have more than one document type", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
if ((child != NULL && php_dom_has_sibling_preceding_node(child, XML_ELEMENT_NODE))
|
||||
|| (child == NULL && php_dom_has_child_of_type(parentNode, XML_ELEMENT_NODE))) {
|
||||
php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Document types must be the first child in a document", /* strict */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dom_free_node_after_zval_single_node_creation(xmlNodePtr node)
|
||||
{
|
||||
/* For the object cases, the user did provide them, so they don't have to be freed as there are still references.
|
||||
* For the newly created text nodes, we do have to free them. */
|
||||
xmlNodePtr next;
|
||||
for (xmlNodePtr child = node->children; child != NULL; child = next) {
|
||||
next = child->next;
|
||||
xmlUnlinkNode(child);
|
||||
if (child->_private == NULL) {
|
||||
xmlFreeNode(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#converting-nodes-into-a-node */
|
||||
xmlNode* dom_zvals_to_single_node(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
xmlDoc *documentNode;
|
||||
xmlNode *newNode;
|
||||
dom_object *newNodeObj;
|
||||
|
||||
documentNode = dom_doc_from_context_node(contextNode);
|
||||
|
||||
/* 1. Let node be null. */
|
||||
xmlNodePtr node = NULL;
|
||||
|
||||
/* 2. => handled in the loop. */
|
||||
|
||||
/* 3. If nodes contains one node, then set node to nodes[0]. */
|
||||
if (nodesc == 1) {
|
||||
/* ... and return */
|
||||
if (Z_TYPE_P(nodes) == IS_OBJECT) {
|
||||
return dom_object_get_node(Z_DOMOBJ_P(nodes));
|
||||
} else {
|
||||
ZEND_ASSERT(Z_TYPE_P(nodes) == IS_STRING);
|
||||
return xmlNewDocTextLen(documentNode, BAD_CAST Z_STRVAL_P(nodes), Z_STRLEN_P(nodes));
|
||||
}
|
||||
}
|
||||
|
||||
node = xmlNewDocFragment(documentNode);
|
||||
if (UNEXPECTED(!node)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 4. Otherwise, set node to a new DocumentFragment node whose node document is document,
|
||||
* and then append each node in nodes, if any, to it. */
|
||||
for (uint32_t i = 0; i < nodesc; i++) {
|
||||
if (Z_TYPE(nodes[i]) == IS_OBJECT) {
|
||||
newNodeObj = Z_DOMOBJ_P(&nodes[i]);
|
||||
newNode = dom_object_get_node(newNodeObj);
|
||||
|
||||
if (!dom_is_pre_insert_valid_without_step_1(document, node, newNode, NULL, documentNode)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (newNode->parent != NULL) {
|
||||
xmlUnlinkNode(newNode);
|
||||
}
|
||||
|
||||
newNodeObj->document = document;
|
||||
xmlSetTreeDoc(newNode, documentNode);
|
||||
|
||||
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
/* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */
|
||||
newNode = newNode->children;
|
||||
while (newNode) {
|
||||
xmlNodePtr next = newNode->next;
|
||||
xmlUnlinkNode(newNode);
|
||||
dom_add_child_without_merging(node, newNode);
|
||||
newNode = next;
|
||||
}
|
||||
} else {
|
||||
dom_add_child_without_merging(node, newNode);
|
||||
}
|
||||
} else {
|
||||
/* 2. Replace each string in nodes with a new Text node whose data is the string and node document is document. */
|
||||
ZEND_ASSERT(Z_TYPE(nodes[i]) == IS_STRING);
|
||||
|
||||
/* Text nodes can't violate the hierarchy at this point. */
|
||||
newNode = xmlNewDocTextLen(documentNode, BAD_CAST Z_STRVAL(nodes[i]), Z_STRLEN(nodes[i]));
|
||||
dom_add_child_without_merging(node, newNode);
|
||||
}
|
||||
}
|
||||
|
||||
/* 5. Return node. */
|
||||
return node;
|
||||
|
||||
err:
|
||||
/* For the object cases, the user did provide them, so they don't have to be freed as there are still references.
|
||||
* For the newly created text nodes, we do have to free them. */
|
||||
dom_free_node_after_zval_single_node_creation(node);
|
||||
xmlFree(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static zend_result dom_sanity_check_node_list_types(zval *nodes, int nodesc, zend_class_entry *node_ce)
|
||||
{
|
||||
for (uint32_t i = 0; i < nodesc; i++) {
|
||||
zend_uchar type = Z_TYPE(nodes[i]);
|
||||
if (type == IS_OBJECT) {
|
||||
const zend_class_entry *ce = Z_OBJCE(nodes[i]);
|
||||
|
||||
if (instanceof_function(ce, dom_node_class_entry)) {
|
||||
xmlNodePtr node = dom_object_get_node(Z_DOMOBJ_P(nodes + i));
|
||||
|
||||
if (node->doc != documentNode) {
|
||||
php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(document));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (node->type == XML_ATTRIBUTE_NODE || dom_hierarchy(parentNode, node) != SUCCESS) {
|
||||
php_dom_throw_error(HIERARCHY_REQUEST_ERR, dom_get_strict_error(document));
|
||||
return FAILURE;
|
||||
}
|
||||
} else {
|
||||
zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_type_name(&nodes[i]));
|
||||
if (!instanceof_function(ce, node_ce)) {
|
||||
zend_argument_type_error(i + 1, "must be of type %s|string, %s given", ZSTR_VAL(node_ce->name), zend_zval_type_name(&nodes[i]));
|
||||
return FAILURE;
|
||||
}
|
||||
} else if (type != IS_STRING) {
|
||||
zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_type_name(&nodes[i]));
|
||||
zend_argument_type_error(i + 1, "must be of type %s|string, %s given", ZSTR_VAL(node_ce->name), zend_zval_type_name(&nodes[i]));
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +471,7 @@ static zend_result dom_sanity_check_node_list_for_insertion(php_libxml_ref_obj *
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xmlNodePtr newchild, xmlNodePtr fragment)
|
||||
static void php_dom_pre_insert_helper(xmlNodePtr insertion_point, xmlNodePtr parentNode, xmlNodePtr newchild, xmlNodePtr last)
|
||||
{
|
||||
if (!insertion_point) {
|
||||
/* Place it as last node */
|
||||
|
@ -285,61 +483,136 @@ static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xm
|
|||
/* No children, because they moved out when they became a fragment */
|
||||
parentNode->children = newchild;
|
||||
}
|
||||
parentNode->last = fragment->last;
|
||||
parentNode->last = last;
|
||||
} else {
|
||||
/* Insert fragment before insertion_point */
|
||||
fragment->last->next = insertion_point;
|
||||
last->next = insertion_point;
|
||||
if (insertion_point->prev) {
|
||||
insertion_point->prev->next = newchild;
|
||||
newchild->prev = insertion_point->prev;
|
||||
}
|
||||
insertion_point->prev = fragment->last;
|
||||
insertion_point->prev = last;
|
||||
if (parentNode->children == insertion_point) {
|
||||
parentNode->children = newchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dom_parent_node_append(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
static void dom_insert_node_list_cleanup(xmlNodePtr node)
|
||||
{
|
||||
xmlNode *parentNode = dom_object_get_node(context);
|
||||
xmlNodePtr newchild, prevsib;
|
||||
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
|
||||
if (node->_private != NULL) {
|
||||
/* Not a temporary node. */
|
||||
return;
|
||||
}
|
||||
if (node->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
dom_free_node_after_zval_single_node_creation(node);
|
||||
xmlFree(node); /* Don't free the children, now-empty fragment! */
|
||||
} else if (node->type == XML_TEXT_NODE) {
|
||||
ZEND_ASSERT(node->parent == NULL);
|
||||
xmlFreeNode(node);
|
||||
} else {
|
||||
/* Must have been a directly-passed node. */
|
||||
ZEND_ASSERT(node->_private != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-pre-insert */
|
||||
static void dom_insert_node_list_unchecked(php_libxml_ref_obj *document, xmlNodePtr node, xmlNodePtr parent, xmlNodePtr insertion_point)
|
||||
{
|
||||
/* Step 1 should be checked by the caller. */
|
||||
|
||||
if (node->type == XML_DOCUMENT_FRAG_NODE) {
|
||||
/* Steps 2-3 are not applicable here, the condition is impossible. */
|
||||
|
||||
xmlNodePtr newchild = node->children;
|
||||
|
||||
/* 4. Insert node into parent before referenceChild (i.e. insertion_point here because of the impossible condition). */
|
||||
if (newchild) {
|
||||
xmlNodePtr last = node->last;
|
||||
php_dom_pre_insert_helper(insertion_point, parent, newchild, last);
|
||||
dom_fragment_assign_parent_node(parent, node);
|
||||
if (!php_dom_follow_spec_doc_ref(document)) {
|
||||
dom_reconcile_ns_list(parent->doc, newchild, last);
|
||||
}
|
||||
if (parent->doc && newchild->type == XML_DTD_NODE) {
|
||||
parent->doc->intSubset = (xmlDtdPtr) newchild;
|
||||
newchild->parent = (xmlNodePtr) parent->doc;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->_private == NULL) {
|
||||
xmlFree(node);
|
||||
} else {
|
||||
node->children = NULL;
|
||||
node->last = NULL;
|
||||
}
|
||||
} else {
|
||||
/* 2. Let referenceChild be child.
|
||||
* 3. If referenceChild is node, then set referenceChild to node’s next sibling. */
|
||||
if (insertion_point == node) {
|
||||
insertion_point = node->next;
|
||||
}
|
||||
|
||||
/* 4. Insert node into parent before referenceChild. */
|
||||
xmlUnlinkNode(node);
|
||||
php_dom_pre_insert_helper(insertion_point, parent, node, node);
|
||||
node->parent = parent;
|
||||
if (parent->doc && node->type == XML_DTD_NODE) {
|
||||
parent->doc->intSubset = (xmlDtdPtr) node;
|
||||
node->parent = (xmlNodePtr) parent->doc;
|
||||
} else {
|
||||
if (!php_dom_follow_spec_doc_ref(document)) {
|
||||
dom_reconcile_ns(parent->doc, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-pre-insert */
|
||||
bool php_dom_pre_insert(php_libxml_ref_obj *document, xmlNodePtr node, xmlNodePtr parent, xmlNodePtr insertion_point)
|
||||
{
|
||||
if (UNEXPECTED(node == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Step 1 checked here, other steps delegated to other function. */
|
||||
if (dom_is_pre_insert_valid_without_step_1(document, parent, node, insertion_point, parent->doc)) {
|
||||
dom_insert_node_list_unchecked(document, node, parent, insertion_point);
|
||||
return true;
|
||||
} else {
|
||||
dom_insert_node_list_cleanup(node);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#concept-node-append */
|
||||
void php_dom_node_append(php_libxml_ref_obj *document, xmlNodePtr node, xmlNodePtr parent)
|
||||
{
|
||||
php_dom_pre_insert(document, node, parent, NULL);
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-parentnode-append */
|
||||
void dom_parent_node_append(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNode *parentNode = dom_object_get_node(context);
|
||||
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
/* 1. Let node be the result of converting nodes into a node given nodes and this’s node document. */
|
||||
xmlNodePtr node = dom_zvals_to_single_node(context->document, parentNode, nodes, nodesc);
|
||||
if (UNEXPECTED(node == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
newchild = fragment->children;
|
||||
prevsib = parentNode->last;
|
||||
|
||||
if (newchild) {
|
||||
if (prevsib != NULL) {
|
||||
prevsib->next = newchild;
|
||||
} else {
|
||||
parentNode->children = newchild;
|
||||
}
|
||||
|
||||
xmlNodePtr last = fragment->last;
|
||||
parentNode->last = last;
|
||||
|
||||
newchild->prev = prevsib;
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
|
||||
dom_reconcile_ns_list(parentNode->doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
/* 2. Append node to this. */
|
||||
php_dom_node_append(context->document, node, parentNode);
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-parentnode-prepend */
|
||||
void dom_parent_node_prepend(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
xmlNode *parentNode = dom_object_get_node(context);
|
||||
|
@ -349,141 +622,91 @@ void dom_parent_node_prepend(dom_object *context, zval *nodes, uint32_t nodesc)
|
|||
return;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
/* 1. Let node be the result of converting nodes into a node given nodes and this’s node document. */
|
||||
xmlNodePtr node = dom_zvals_to_single_node(context->document, parentNode, nodes, nodesc);
|
||||
if (UNEXPECTED(node == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNode *newchild = fragment->children;
|
||||
|
||||
if (newchild) {
|
||||
xmlNodePtr last = fragment->last;
|
||||
|
||||
dom_pre_insert(parentNode->children, parentNode, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
|
||||
dom_reconcile_ns_list(parentNode->doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
/* 2. Pre-insert node into this before this’s first child. */
|
||||
php_dom_pre_insert(context->document, node, parentNode, parentNode->children);
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-childnode-after */
|
||||
void dom_parent_node_after(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-after */
|
||||
|
||||
xmlNode *prevsib = dom_object_get_node(context);
|
||||
xmlNodePtr newchild, parentNode;
|
||||
xmlNode *fragment;
|
||||
xmlDoc *doc;
|
||||
|
||||
/* Spec step 1 */
|
||||
parentNode = prevsib->parent;
|
||||
|
||||
/* Sanity check for fragment, includes spec step 2 */
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 3: find first following child not in nodes; otherwise null */
|
||||
xmlNodePtr viable_next_sibling = prevsib->next;
|
||||
while (viable_next_sibling) {
|
||||
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
|
||||
break;
|
||||
xmlNode *thisp = dom_object_get_node(context);
|
||||
|
||||
/* 1. Let parent be this’s parent. */
|
||||
xmlNodePtr parentNode = thisp->parent;
|
||||
|
||||
/* 2. If parent is null, then return. */
|
||||
if (UNEXPECTED(parentNode == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null. */
|
||||
xmlNodePtr viable_next_sibling = thisp->next;
|
||||
while (viable_next_sibling && dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
|
||||
viable_next_sibling = viable_next_sibling->next;
|
||||
}
|
||||
|
||||
doc = prevsib->doc;
|
||||
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
/* Spec step 4: convert nodes into fragment */
|
||||
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
/* 4. Let node be the result of converting nodes into a node, given nodes and this’s node document. */
|
||||
xmlNodePtr fragment = dom_zvals_to_single_node(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
newchild = fragment->children;
|
||||
|
||||
if (newchild) {
|
||||
xmlNodePtr last = fragment->last;
|
||||
|
||||
/* Step 5: place fragment into the parent before viable_next_sibling */
|
||||
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns_list(doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
/* 5. Pre-insert node into parent before viableNextSibling. */
|
||||
php_dom_pre_insert(context->document, fragment, parentNode, viable_next_sibling);
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-childnode-before */
|
||||
void dom_parent_node_before(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-before */
|
||||
|
||||
xmlNode *nextsib = dom_object_get_node(context);
|
||||
xmlNodePtr newchild, parentNode;
|
||||
xmlNode *fragment;
|
||||
xmlDoc *doc;
|
||||
|
||||
/* Spec step 1 */
|
||||
parentNode = nextsib->parent;
|
||||
|
||||
/* Sanity check for fragment, includes spec step 2 */
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 3: find first following child not in nodes; otherwise null */
|
||||
xmlNodePtr viable_previous_sibling = nextsib->prev;
|
||||
while (viable_previous_sibling) {
|
||||
if (!dom_is_node_in_list(nodes, nodesc, viable_previous_sibling)) {
|
||||
break;
|
||||
xmlNode *thisp = dom_object_get_node(context);
|
||||
|
||||
/* 1. Let parent be this’s parent. */
|
||||
xmlNodePtr parentNode = thisp->parent;
|
||||
|
||||
/* 2. If parent is null, then return. */
|
||||
if (UNEXPECTED(parentNode == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 3. Let viablePreviousSibling be this’s first preceding sibling not in nodes; otherwise null. */
|
||||
xmlNodePtr viable_previous_sibling = thisp->prev;
|
||||
while (viable_previous_sibling && dom_is_node_in_list(nodes, nodesc, viable_previous_sibling)) {
|
||||
viable_previous_sibling = viable_previous_sibling->prev;
|
||||
}
|
||||
|
||||
doc = nextsib->doc;
|
||||
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
/* Spec step 4: convert nodes into fragment */
|
||||
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
/* 4. Let node be the result of converting nodes into a node, given nodes and this’s node document. */
|
||||
xmlNodePtr fragment = dom_zvals_to_single_node(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
newchild = fragment->children;
|
||||
|
||||
if (newchild) {
|
||||
xmlNodePtr last = fragment->last;
|
||||
|
||||
/* Step 5: if viable_previous_sibling is null, set it to the parent's first child, otherwise viable_previous_sibling's next sibling */
|
||||
/* 5. If viable_previous_sibling is null, set it to the parent's first child, otherwise viable_previous_sibling's next sibling. */
|
||||
if (!viable_previous_sibling) {
|
||||
viable_previous_sibling = parentNode->children;
|
||||
} else {
|
||||
viable_previous_sibling = viable_previous_sibling->next;
|
||||
}
|
||||
/* Step 6: place fragment into the parent after viable_previous_sibling */
|
||||
dom_pre_insert(viable_previous_sibling, parentNode, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns_list(doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
/* 6. Pre-insert node into parent before viablePreviousSibling. */
|
||||
php_dom_pre_insert(context->document, fragment, parentNode, viable_previous_sibling);
|
||||
}
|
||||
|
||||
static zend_result dom_child_removal_preconditions(const xmlNodePtr child, int stricterror)
|
||||
|
@ -499,7 +722,7 @@ static zend_result dom_child_removal_preconditions(const xmlNodePtr child, int s
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(child->parent) == FAILURE) {
|
||||
if (!dom_node_children_valid(child->parent)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -528,95 +751,80 @@ void dom_child_node_remove(dom_object *context)
|
|||
xmlUnlinkNode(child);
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-childnode-replacewith */
|
||||
void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-replacewith */
|
||||
|
||||
xmlNodePtr child = dom_object_get_node(context);
|
||||
|
||||
/* Spec step 1 */
|
||||
xmlNodePtr parentNode = child->parent;
|
||||
|
||||
/* Sanity check for fragment, includes spec step 2 */
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int stricterror = dom_get_strict_error(context->document);
|
||||
xmlNodePtr child = dom_object_get_node(context);
|
||||
|
||||
/* 1. Let parent be this’s parent. */
|
||||
xmlNodePtr parentNode = child->parent;
|
||||
|
||||
/* 2. If parent is null, then return. */
|
||||
if (UNEXPECTED(parentNode == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null. */
|
||||
xmlNodePtr viable_next_sibling = child->next;
|
||||
while (viable_next_sibling && dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
|
||||
viable_next_sibling = viable_next_sibling->next;
|
||||
}
|
||||
|
||||
bool stricterror = dom_get_strict_error(context->document);
|
||||
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 3: find first following child not in nodes; otherwise null */
|
||||
xmlNodePtr viable_next_sibling = child->next;
|
||||
while (viable_next_sibling) {
|
||||
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
|
||||
break;
|
||||
}
|
||||
viable_next_sibling = viable_next_sibling->next;
|
||||
}
|
||||
|
||||
xmlDocPtr doc = parentNode->doc;
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
/* Spec step 4: convert nodes into fragment */
|
||||
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
if (UNEXPECTED(fragment == NULL)) {
|
||||
/* 4. Let node be the result of converting nodes into a node, given nodes and this’s node document. */
|
||||
xmlNodePtr node = dom_zvals_to_single_node(context->document, parentNode, nodes, nodesc);
|
||||
if (UNEXPECTED(node == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 5: perform the replacement */
|
||||
|
||||
xmlNodePtr newchild = fragment->children;
|
||||
|
||||
/* Spec step 5-6: perform the replacement */
|
||||
if (dom_is_pre_insert_valid_without_step_1(context->document, parentNode, node, viable_next_sibling, parentNode->doc)) {
|
||||
/* Unlink it unless it became a part of the fragment.
|
||||
* Freeing will be taken care of by the lifetime of the returned dom object. */
|
||||
if (child->parent != fragment) {
|
||||
if (child->parent != node) {
|
||||
xmlUnlinkNode(child);
|
||||
}
|
||||
|
||||
if (newchild) {
|
||||
xmlNodePtr last = fragment->last;
|
||||
|
||||
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns_list(doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
dom_insert_node_list_unchecked(context->document, node, parentNode, viable_next_sibling);
|
||||
} else {
|
||||
dom_insert_node_list_cleanup(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* https://dom.spec.whatwg.org/#dom-parentnode-replacechildren */
|
||||
void dom_parent_node_replace_children(dom_object *context, zval *nodes, uint32_t nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-parentnode-replacechildren */
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_types(nodes, nodesc, dom_get_node_ce(php_dom_follow_spec_doc_ref(context->document))) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNodePtr thisp = dom_object_get_node(context);
|
||||
/* Note: Only rule 2 of pre-insertion validity can be broken */
|
||||
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, thisp, nodes, nodesc) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, thisp, nodes, nodesc);
|
||||
if (UNEXPECTED(fragment == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
php_libxml_invalidate_node_list_cache(context->document);
|
||||
|
||||
dom_remove_all_children(thisp);
|
||||
|
||||
xmlNodePtr newchild = fragment->children;
|
||||
if (newchild) {
|
||||
xmlNodePtr last = fragment->last;
|
||||
|
||||
dom_pre_insert(NULL, thisp, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(thisp, fragment);
|
||||
dom_reconcile_ns_list(thisp->doc, newchild, last);
|
||||
/* 1. Let node be the result of converting nodes into a node given nodes and this’s node document. */
|
||||
xmlNodePtr node = dom_zvals_to_single_node(context->document, thisp, nodes, nodesc);
|
||||
if (UNEXPECTED(node == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
/* Spec steps 2-3: replace all */
|
||||
if (dom_is_pre_insert_valid_without_step_1(context->document, thisp, node, NULL, thisp->doc)) {
|
||||
dom_remove_all_children(thisp);
|
||||
php_dom_pre_insert(context->document, node, thisp, NULL);
|
||||
} else {
|
||||
dom_insert_node_list_cleanup(node);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1165
ext/dom/php_dom.c
1165
ext/dom/php_dom.c
File diff suppressed because it is too large
Load diff
|
@ -83,7 +83,7 @@ typedef struct _dom_nnodemap_object {
|
|||
int nodetype;
|
||||
int cached_length;
|
||||
xmlHashTable *ht;
|
||||
xmlChar *local;
|
||||
xmlChar *local, *local_lower;
|
||||
xmlChar *ns;
|
||||
php_libxml_cache_tag cache_tag;
|
||||
dom_object *cached_obj;
|
||||
|
@ -107,6 +107,16 @@ typedef struct {
|
|||
dom_object dom;
|
||||
} dom_object_namespace_node;
|
||||
|
||||
typedef enum _dom_iterator_type {
|
||||
DOM_NODELIST,
|
||||
DOM_NAMEDNODEMAP,
|
||||
DOM_DTD_NAMEDNODEMAP,
|
||||
DOM_HTMLCOLLECTION,
|
||||
} dom_iterator_type;
|
||||
|
||||
struct _php_dom_libxml_ns_mapper;
|
||||
typedef struct _php_dom_libxml_ns_mapper php_dom_libxml_ns_mapper;
|
||||
|
||||
static inline dom_object_namespace_node *php_dom_namespace_node_obj_from_obj(zend_object *obj) {
|
||||
return (dom_object_namespace_node*)((char*)(obj) - XtOffsetOf(dom_object_namespace_node, dom.std));
|
||||
}
|
||||
|
@ -133,14 +143,15 @@ xmlNsPtr dom_get_ns_unchecked(xmlNodePtr nodep, char *uri, char *prefix);
|
|||
void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep);
|
||||
void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last);
|
||||
xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName);
|
||||
void dom_normalize (xmlNodePtr nodep);
|
||||
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, char *ns, char *local, int *cur, int index);
|
||||
void php_dom_create_implementation(zval *retval);
|
||||
void php_dom_normalize_legacy(xmlNodePtr nodep);
|
||||
void php_dom_normalize_modern(xmlNodePtr nodep);
|
||||
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr basep, xmlNodePtr nodep, xmlChar *ns, xmlChar *local, xmlChar *local_lower, int *cur, int index);
|
||||
void php_dom_create_implementation(zval *retval, bool modern);
|
||||
int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child);
|
||||
bool dom_has_feature(zend_string *feature, zend_string *version);
|
||||
int dom_node_is_read_only(xmlNodePtr node);
|
||||
int dom_node_children_valid(xmlNodePtr node);
|
||||
void php_dom_create_iterator(zval *return_value, int ce_type);
|
||||
bool dom_node_children_valid(xmlNodePtr node);
|
||||
void php_dom_create_iterator(zval *return_value, dom_iterator_type iterator_type, bool modern);
|
||||
void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xmlHashTablePtr ht, const char *local, size_t local_len, const char *ns, size_t ns_len);
|
||||
xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID);
|
||||
xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index);
|
||||
|
@ -150,21 +161,51 @@ void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece
|
|||
xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern);
|
||||
void php_dom_get_content_into_zval(const xmlNode *nodep, zval *target, bool default_is_null);
|
||||
zend_string *dom_node_concatenated_name_helper(size_t name_len, const char *name, size_t prefix_len, const char *prefix);
|
||||
zend_string *dom_node_get_node_name_attribute_or_element(const xmlNode *nodep);
|
||||
zend_string *dom_node_get_node_name_attribute_or_element(const xmlNode *nodep, bool uppercase);
|
||||
bool php_dom_is_node_connected(const xmlNode *node);
|
||||
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document);
|
||||
xmlNsPtr dom_get_ns_resolve_prefix_conflict(xmlNodePtr tree, const char *uri);
|
||||
void php_dom_reconcile_attribute_namespace_after_insertion(xmlAttrPtr attrp);
|
||||
|
||||
int dom_validate_and_extract(const zend_string *namespace, const zend_string *qname, xmlChar **localName, xmlChar **prefix);
|
||||
bool dom_match_qualified_name_according_to_spec(const xmlChar *qname, const xmlNode *nodep);
|
||||
bool php_dom_has_sibling_following_node(xmlNodePtr node, xmlElementType type);
|
||||
bool php_dom_has_sibling_preceding_node(xmlNodePtr node, xmlElementType type);
|
||||
bool php_dom_has_child_of_type(xmlNodePtr node, xmlElementType type);
|
||||
void php_dom_update_document_after_clone(dom_object *original, xmlNodePtr original_node, dom_object *clone, xmlNodePtr cloned_node);
|
||||
void php_dom_document_constructor(INTERNAL_FUNCTION_PARAMETERS);
|
||||
|
||||
xmlAttrPtr php_dom_get_attribute_node(xmlNodePtr elem, const xmlChar *name, size_t name_len);
|
||||
xmlChar *php_dom_libxml_fix_file_path(xmlChar *path);
|
||||
void dom_document_convert_to_modern(php_libxml_ref_obj *document, xmlDocPtr lxml_doc);
|
||||
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);
|
||||
|
||||
static zend_always_inline xmlNodePtr php_dom_next_in_tree_order(const xmlNode *nodep, const xmlNode *basep)
|
||||
{
|
||||
if (nodep->next) {
|
||||
return nodep->next;
|
||||
} else {
|
||||
/* Go upwards, until we find a parent node with a next sibling, or until we hit the base. */
|
||||
do {
|
||||
nodep = nodep->parent;
|
||||
if (nodep == basep) {
|
||||
return NULL;
|
||||
}
|
||||
/* This shouldn't happen, unless there's an invalidation bug somewhere. */
|
||||
if (UNEXPECTED(nodep == NULL)) {
|
||||
zend_throw_error(NULL, "Current node in traversal is not in the document. Please report this as a bug in php-src.");
|
||||
return NULL;
|
||||
}
|
||||
} while (nodep->next == NULL);
|
||||
return nodep->next;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
DOM_LOAD_STRING = 0,
|
||||
DOM_LOAD_FILE = 1,
|
||||
} dom_load_mode;
|
||||
|
||||
#define DOM_DOCUMENT_MALFORMED ((xmlDocPtr) -1)
|
||||
|
||||
xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source, size_t source_len, size_t options, xmlCharEncodingHandlerPtr encoding);
|
||||
|
||||
/* parentnode */
|
||||
|
@ -175,20 +216,23 @@ void dom_parent_node_before(dom_object *context, zval *nodes, uint32_t nodesc);
|
|||
void dom_parent_node_replace_children(dom_object *context, zval *nodes, uint32_t nodesc);
|
||||
void dom_child_node_remove(dom_object *context);
|
||||
void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc);
|
||||
|
||||
void dom_remove_all_children(xmlNodePtr nodep);
|
||||
bool php_dom_fragment_insertion_hierarchy_check_pre_insertion(xmlNodePtr parent, xmlNodePtr node, xmlNodePtr child);
|
||||
bool php_dom_fragment_insertion_hierarchy_check_replace(xmlNodePtr parent, xmlNodePtr node, xmlNodePtr child);
|
||||
void php_dom_node_append(php_libxml_ref_obj *document, xmlNodePtr node, xmlNodePtr parent);
|
||||
bool php_dom_pre_insert(php_libxml_ref_obj *document, xmlNodePtr node, xmlNodePtr parent, xmlNodePtr insertion_point);
|
||||
bool php_dom_pre_insert_is_parent_invalid(xmlNodePtr parent);
|
||||
|
||||
/* nodemap and nodelist APIs */
|
||||
xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const char *named, bool may_transform);
|
||||
void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const char *named, zval *return_value);
|
||||
xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const zend_string *named, bool may_transform);
|
||||
void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, zval *return_value);
|
||||
xmlNodePtr php_dom_named_node_map_get_item(dom_nnodemap_object *objmap, zend_long index);
|
||||
void php_dom_named_node_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value);
|
||||
void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value);
|
||||
int php_dom_get_namednodemap_length(dom_object *obj);
|
||||
int php_dom_get_nodelist_length(dom_object *obj);
|
||||
|
||||
xmlNodePtr dom_clone_node(xmlNodePtr node, xmlDocPtr doc, const dom_object *intern, bool recursive);
|
||||
void dom_mark_namespaces_for_copy_based_on_copy(xmlNodePtr copy, const xmlNode *original);
|
||||
xmlNodePtr dom_clone_node(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node, xmlDocPtr doc, bool recursive);
|
||||
|
||||
#define DOM_GET_INTERN(__id, __intern) { \
|
||||
__intern = Z_DOMOBJ_P(__id); \
|
||||
|
@ -205,9 +249,6 @@ void dom_mark_namespaces_for_copy_based_on_copy(xmlNodePtr copy, const xmlNode *
|
|||
__ptr = (__prtype)((php_libxml_node_ptr *)__intern->ptr)->node; \
|
||||
}
|
||||
|
||||
#define DOM_NODELIST 0
|
||||
#define DOM_NAMEDNODEMAP 1
|
||||
|
||||
static zend_always_inline bool php_dom_is_cache_tag_stale_from_doc_ptr(const php_libxml_cache_tag *cache_tag, const php_libxml_ref_obj *doc_ptr)
|
||||
{
|
||||
ZEND_ASSERT(cache_tag != NULL);
|
||||
|
@ -223,11 +264,11 @@ static zend_always_inline bool php_dom_is_cache_tag_stale_from_doc_ptr(const php
|
|||
static zend_always_inline bool php_dom_is_cache_tag_stale_from_node(const php_libxml_cache_tag *cache_tag, const xmlNodePtr node)
|
||||
{
|
||||
ZEND_ASSERT(node != NULL);
|
||||
php_libxml_node_ptr *private = node->_private;
|
||||
if (!private) {
|
||||
php_libxml_node_ptr *_private = node->_private;
|
||||
if (!_private) {
|
||||
return true;
|
||||
}
|
||||
php_libxml_node_object *object_private = private->_private;
|
||||
php_libxml_node_object *object_private = _private->_private;
|
||||
if (!object_private || !object_private->document) {
|
||||
return true;
|
||||
}
|
||||
|
@ -237,15 +278,45 @@ static zend_always_inline bool php_dom_is_cache_tag_stale_from_node(const php_li
|
|||
static zend_always_inline void php_dom_mark_cache_tag_up_to_date_from_node(php_libxml_cache_tag *cache_tag, const xmlNodePtr node)
|
||||
{
|
||||
ZEND_ASSERT(cache_tag != NULL);
|
||||
php_libxml_node_ptr *private = node->_private;
|
||||
if (private) {
|
||||
php_libxml_node_object *object_private = private->_private;
|
||||
php_libxml_node_ptr *_private = node->_private;
|
||||
if (_private) {
|
||||
php_libxml_node_object *object_private = _private->_private;
|
||||
if (object_private->document) {
|
||||
cache_tag->modification_nr = object_private->document->cache_tag.modification_nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline bool php_dom_follow_spec_doc_ref(const php_libxml_ref_obj *document)
|
||||
{
|
||||
return document != NULL && document->class_type == PHP_LIBXML_CLASS_MODERN;
|
||||
}
|
||||
|
||||
static zend_always_inline bool php_dom_follow_spec_intern(const dom_object *intern)
|
||||
{
|
||||
ZEND_ASSERT(intern != NULL);
|
||||
return php_dom_follow_spec_doc_ref(intern->document);
|
||||
}
|
||||
|
||||
static zend_always_inline bool php_dom_follow_spec_node(const xmlNode *node)
|
||||
{
|
||||
ZEND_ASSERT(node != NULL);
|
||||
php_libxml_node_ptr *_private = node->_private;
|
||||
if (_private) {
|
||||
php_libxml_node_object *object_private = _private->_private;
|
||||
if (object_private->document) {
|
||||
return php_dom_follow_spec_doc_ref(object_private->document);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static zend_always_inline php_dom_libxml_ns_mapper *php_dom_get_ns_mapper(dom_object *intern)
|
||||
{
|
||||
ZEND_ASSERT(intern->document != NULL);
|
||||
return (php_dom_libxml_ns_mapper *) intern->document->private_data;
|
||||
}
|
||||
|
||||
PHP_MINIT_FUNCTION(dom);
|
||||
PHP_MSHUTDOWN_FUNCTION(dom);
|
||||
PHP_MINFO_FUNCTION(dom);
|
||||
|
|
File diff suppressed because it is too large
Load diff
1766
ext/dom/php_dom_arginfo.h
generated
1766
ext/dom/php_dom_arginfo.h
generated
File diff suppressed because it is too large
Load diff
28
ext/dom/serialize_common.h
Normal file
28
ext/dom/serialize_common.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Niels Dossche <nielsdos@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef SERIALIZE_COMMON_H
|
||||
#define SERIALIZE_COMMON_H
|
||||
|
||||
#include <Zend/zend_types.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
static zend_always_inline bool dom_local_name_compare_ex(const xmlNode *node, const char *tag, size_t tag_length, size_t name_length)
|
||||
{
|
||||
return name_length == tag_length && zend_binary_strcmp((const char *) node->name, name_length, tag, tag_length) == 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@ dom
|
|||
<?php
|
||||
require_once("dom_test.inc");
|
||||
|
||||
function test($method) {
|
||||
$dom1 = new DOMDocument;
|
||||
$dom1->loadXML('<test/>');
|
||||
|
||||
|
@ -15,25 +16,17 @@ $dom2->loadXML('<test><foo /></test>');
|
|||
$element = $dom1->documentElement;
|
||||
|
||||
try {
|
||||
$element->after($dom2->documentElement->firstChild);
|
||||
$element->$method($dom2->documentElement->firstChild);
|
||||
echo "FAIL";
|
||||
} catch (DOMException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$element->before($dom2->documentElement->firstChild);
|
||||
echo "FAIL";
|
||||
} catch (DOMException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$element->replaceWith($dom2->documentElement->firstChild);
|
||||
echo "FAIL";
|
||||
} catch (DOMException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
test("after");
|
||||
test("before");
|
||||
test("replaceWith");
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Wrong Document Error
|
||||
|
|
|
@ -6,6 +6,7 @@ dom
|
|||
<?php
|
||||
require_once("dom_test.inc");
|
||||
|
||||
function test($method) {
|
||||
$dom1 = new DOMDocument;
|
||||
$dom1->loadXML('<test/>');
|
||||
|
||||
|
@ -15,18 +16,15 @@ $dom2->loadXML('<test><foo /></test>');
|
|||
$element = $dom1->documentElement;
|
||||
|
||||
try {
|
||||
$element->append($dom2->documentElement->firstChild);
|
||||
$element->$method($dom2->documentElement->firstChild);
|
||||
echo "FAIL";
|
||||
} catch (DOMException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$element->prepend($dom2->documentElement->firstChild);
|
||||
echo "FAIL";
|
||||
} catch (DOMException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
|
||||
test("append");
|
||||
test("prepend");
|
||||
?>
|
||||
--EXPECT--
|
||||
Wrong Document Error
|
||||
|
|
|
@ -141,7 +141,7 @@ string(27) "<?xml version="1.0"?>
|
|||
Not Supported Error
|
||||
-- Adopt a document (strict error off) --
|
||||
|
||||
Warning: DOM\Document::adoptNode(): Not Supported Error in %s on line %d
|
||||
Warning: DOMDocument::adoptNode(): Not Supported Error in %s on line %d
|
||||
-- Adopt an attribute --
|
||||
bool(true)
|
||||
bool(true)
|
||||
|
|
|
@ -35,5 +35,5 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::relaxNGValidateSource(): Did not expect element pear there in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidateSource(): Did not expect element pear there in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -31,7 +31,7 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::relaxNGValidateSource(): xmlRelaxNGParseElement: element has no content in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidateSource(): xmlRelaxNGParseElement: element has no content in %s on line %d
|
||||
|
||||
Warning: DOM\Document::relaxNGValidateSource(): Invalid RelaxNG in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidateSource(): Invalid RelaxNG in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -20,5 +20,5 @@ $result = $doc->relaxNGValidate($rng);
|
|||
var_dump($result);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::relaxNGValidate(): Did not expect element pear there in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidate(): Did not expect element pear there in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -20,9 +20,9 @@ $result = $doc->relaxNGValidate($rng);
|
|||
var_dump($result);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::relaxNGValidate(): I/O warning : failed to load external entity "%s/foo.rng" in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidate(): I/O warning : failed to load external entity "%s/foo.rng" in %s on line %d
|
||||
|
||||
Warning: DOM\Document::relaxNGValidate(): xmlRelaxNGParse: could not load %s/foo.rng in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidate(): xmlRelaxNGParse: could not load %s/foo.rng in %s on line %d
|
||||
|
||||
Warning: DOM\Document::relaxNGValidate(): Invalid RelaxNG in %s on line %d
|
||||
Warning: DOMDocument::relaxNGValidate(): Invalid RelaxNG in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -17,13 +17,13 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::schemaValidateSource(): Entity: line 1: parser error : Start tag expected, '<' not found in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): Entity: line 1: parser error : Start tag expected, '<' not found in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidateSource(): string that is not a schema in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): string that is not a schema in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidateSource(): ^ in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): ^ in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidateSource(): Failed to parse the XML resource 'in_memory_buffer'. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): Failed to parse the XML resource 'in_memory_buffer'. in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidateSource(): Invalid Schema in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): Invalid Schema in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -19,5 +19,5 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::schemaValidateSource(): Element 'books': No matching global declaration available for the validation root. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidateSource(): Element 'books': No matching global declaration available for the validation root. in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -20,4 +20,4 @@ try {
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
DOM\Document::schemaValidateSource(): Argument #1 ($source) must not be empty
|
||||
DOMDocument::schemaValidateSource(): Argument #1 ($source) must not be empty
|
||||
|
|
|
@ -17,13 +17,13 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::schemaValidate(): %s/book-not-a-schema.xsd:1: parser error : Start tag expected, '<' not found in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): %sbook-not-a-schema.xsd:1: parser error : Start tag expected, '<' not found in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Let's see what happens upon parsing a file that doesn't contain a schema. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Let's see what happens upon parsing a file that doesn't contain a schema. in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): ^ in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): ^ in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Failed to parse the XML resource '%s/book-not-a-schema.xsd'. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Failed to parse the XML resource '%sbook-not-a-schema.xsd'. in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Invalid Schema in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Invalid Schema in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -17,5 +17,5 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::schemaValidate(): Element 'books': No matching global declaration available for the validation root. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Element 'books': No matching global declaration available for the validation root. in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -20,4 +20,4 @@ try {
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
DOM\Document::schemaValidate(): Argument #1 ($filename) must not be empty
|
||||
DOMDocument::schemaValidate(): Argument #1 ($filename) must not be empty
|
||||
|
|
|
@ -17,9 +17,9 @@ var_dump($result);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\Document::schemaValidate(): I/O warning : failed to load external entity "%s/non-existent-file" in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): I/O warning : failed to load external entity "%snon-existent-file" in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Failed to locate the main schema resource at '%s/non-existent-file'. in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Failed to locate the main schema resource at '%snon-existent-file'. in %s on line %d
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Invalid Schema in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Invalid Schema in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -19,7 +19,7 @@ var_dump($doc->schemaValidate(str_repeat(" ", PHP_MAXPATHLEN + 1)));
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
DOM\Document::schemaValidate(): Argument #1 ($filename) must not contain any null bytes
|
||||
DOMDocument::schemaValidate(): Argument #1 ($filename) must not contain any null bytes
|
||||
|
||||
Warning: DOM\Document::schemaValidate(): Invalid Schema file source in %s on line %d
|
||||
Warning: DOMDocument::schemaValidate(): Invalid Schema file source in %s on line %d
|
||||
bool(false)
|
||||
|
|
|
@ -56,4 +56,4 @@ See if strictErrorChecking is off
|
|||
bool(false)
|
||||
Should raise PHP error because strictErrorChecking is off
|
||||
|
||||
Warning: DOM\Document::createAttribute(): Invalid Character Error in %s on line %d
|
||||
Warning: DOMDocument::createAttribute(): Invalid Character Error in %s on line %d
|
||||
|
|
|
@ -22,6 +22,13 @@ $b_world = $b_hello->nextSibling;
|
|||
$b_hello->append($b_world->firstChild);
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Append hello with world's child and text --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
$b_world = $b_hello->nextSibling;
|
||||
$b_hello->append($b_world->firstChild, "foo");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Append world's child with hello --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
|
@ -39,6 +46,16 @@ try {
|
|||
}
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Append hello with itself and text --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
try {
|
||||
$b_hello->append($b_hello, "foo");
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Append world's i tag with the parent --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
|
@ -70,6 +87,9 @@ string(39) "<p><b>hello<b><i>world</i></b></b></p>
|
|||
-- Append hello with world's child --
|
||||
string(39) "<p><b>hello<i>world</i></b><b></b></p>
|
||||
"
|
||||
-- Append hello with world's child and text --
|
||||
string(42) "<p><b>hello<i>world</i>foo</b><b></b></p>
|
||||
"
|
||||
-- Append world's child with hello --
|
||||
string(39) "<p><b><i>world<b>hello</b></i></b></p>
|
||||
"
|
||||
|
@ -77,6 +97,10 @@ string(39) "<p><b><i>world<b>hello</b></i></b></p>
|
|||
Hierarchy Request Error
|
||||
string(39) "<p><b>hello</b><b><i>world</i></b></p>
|
||||
"
|
||||
-- Append hello with itself and text --
|
||||
Hierarchy Request Error
|
||||
string(27) "<p><b><i>world</i></b></p>
|
||||
"
|
||||
-- Append world's i tag with the parent --
|
||||
Hierarchy Request Error
|
||||
string(39) "<p><b>hello</b><b><i>world</i></b></p>
|
||||
|
|
21
ext/dom/tests/DOMElement_get_or_has_attribute_ns_xmlns.phpt
Normal file
21
ext/dom/tests/DOMElement_get_or_has_attribute_ns_xmlns.phpt
Normal file
|
@ -0,0 +1,21 @@
|
|||
--TEST--
|
||||
DOMElement::{get,has}AttributeNS() with xmlns
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadXML('<root xmlns:a="urn:a"/>');
|
||||
|
||||
var_dump($dom->documentElement->getAttributeNS('http://www.w3.org/2000/xmlns/', 'a'));
|
||||
var_dump($dom->documentElement->getAttributeNS('http://www.w3.org/2000/xmlns/', 'b'));
|
||||
var_dump($dom->documentElement->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'a'));
|
||||
var_dump($dom->documentElement->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'b'));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(5) "urn:a"
|
||||
string(0) ""
|
||||
bool(true)
|
||||
bool(false)
|
|
@ -78,4 +78,4 @@ Syntax Error
|
|||
--- Normal cases starting from empty element ---
|
||||
<empty>A</empty>
|
||||
<empty>BA</empty>
|
||||
string(2) "BA"
|
||||
string(1) "A"
|
||||
|
|
|
@ -22,6 +22,13 @@ $b_world = $b_hello->nextSibling;
|
|||
$b_hello->prepend($b_world->firstChild);
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend hello with world's child and text --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
$b_world = $b_hello->nextSibling;
|
||||
$b_hello->prepend($b_world->firstChild, "foo");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend world's child with hello --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
|
@ -29,6 +36,13 @@ $b_world = $b_hello->nextSibling;
|
|||
$b_world->firstChild->prepend($b_hello);
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend world's child with hello and text --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
$b_world = $b_hello->nextSibling;
|
||||
$b_world->firstChild->prepend($b_hello, "foo");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend hello with itself --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
|
@ -39,6 +53,16 @@ try {
|
|||
}
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend hello with itself and text --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
try {
|
||||
$b_hello->prepend($b_hello, "foo");
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
echo "-- Prepend world's i tag with the parent --\n";
|
||||
$dom = clone $dom_original;
|
||||
$b_hello = $dom->firstChild->firstChild;
|
||||
|
@ -70,13 +94,23 @@ string(39) "<p><b><b><i>world</i></b>hello</b></p>
|
|||
-- Prepend hello with world's child --
|
||||
string(39) "<p><b><i>world</i>hello</b><b></b></p>
|
||||
"
|
||||
-- Prepend hello with world's child and text --
|
||||
string(42) "<p><b><i>world</i>foohello</b><b></b></p>
|
||||
"
|
||||
-- Prepend world's child with hello --
|
||||
string(39) "<p><b><i><b>hello</b>world</i></b></p>
|
||||
"
|
||||
-- Prepend world's child with hello and text --
|
||||
string(42) "<p><b><i><b>hello</b>fooworld</i></b></p>
|
||||
"
|
||||
-- Prepend hello with itself --
|
||||
Hierarchy Request Error
|
||||
string(39) "<p><b>hello</b><b><i>world</i></b></p>
|
||||
"
|
||||
-- Prepend hello with itself and text --
|
||||
Hierarchy Request Error
|
||||
string(27) "<p><b><i>world</i></b></p>
|
||||
"
|
||||
-- Prepend world's i tag with the parent --
|
||||
Hierarchy Request Error
|
||||
string(39) "<p><b>hello</b><b><i>world</i></b></p>
|
||||
|
|
32
ext/dom/tests/DOMNode_normalize_advanced.phpt
Normal file
32
ext/dom/tests/DOMNode_normalize_advanced.phpt
Normal file
|
@ -0,0 +1,32 @@
|
|||
--TEST--
|
||||
DOMNode::normalize() advanced
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom = new DOMDocument;
|
||||
$root = $dom->appendChild($dom->createElement("root"));
|
||||
$child1 = $root->appendChild($dom->createElement("child1"));
|
||||
$child2 = $root->appendChild($dom->createElement("child2"));
|
||||
|
||||
$child1->appendChild($dom->createTextNode("abc"));
|
||||
$child1->appendChild($dom->createTextNode(""));
|
||||
$child1->appendChild($dom->createTextNode("def"));
|
||||
|
||||
$child2->appendChild($dom->createTextNode(""));
|
||||
$child2->setAttribute("foo", "bar");
|
||||
|
||||
echo $dom->saveXML();
|
||||
|
||||
$root->normalize();
|
||||
|
||||
var_dump($child1->childNodes[0]->textContent);
|
||||
var_dump($child2->childNodes[0]);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
<?xml version="1.0"?>
|
||||
<root><child1>abcdef</child1><child2 foo="bar"></child2></root>
|
||||
string(6) "abcdef"
|
||||
NULL
|
|
@ -12,6 +12,13 @@ if(!$s) {
|
|||
}
|
||||
$dom = dom_import_simplexml($s);
|
||||
print $dom->ownerDocument->saveXML();
|
||||
|
||||
// This should fail because it has been imported already above in legacy DOM
|
||||
try {
|
||||
DOM\import_simplexml($s);
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
<?xml version="1.0"?>
|
||||
|
@ -25,3 +32,4 @@ print $dom->ownerDocument->saveXML();
|
|||
<author>John Steinbeck</author>
|
||||
</book>
|
||||
</books>
|
||||
DOM\import_simplexml(): Argument #1 ($node) must not be already imported as a DOMNode
|
||||
|
|
|
@ -20,12 +20,14 @@ object(DOMDocument)#1 (41) {
|
|||
["dynamicProperty"]=>
|
||||
object(stdClass)#2 (0) {
|
||||
}
|
||||
["doctype"]=>
|
||||
NULL
|
||||
["implementation"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["documentElement"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["actualEncoding"]=>
|
||||
NULL
|
||||
["config"]=>
|
||||
NULL
|
||||
["encoding"]=>
|
||||
NULL
|
||||
["xmlEncoding"]=>
|
||||
|
@ -38,6 +40,12 @@ object(DOMDocument)#1 (41) {
|
|||
string(3) "1.0"
|
||||
["xmlVersion"]=>
|
||||
string(3) "1.0"
|
||||
["strictErrorChecking"]=>
|
||||
bool(true)
|
||||
["documentURI"]=>
|
||||
string(%d) "%s"
|
||||
["config"]=>
|
||||
NULL
|
||||
["formatOutput"]=>
|
||||
bool(false)
|
||||
["validateOnParse"]=>
|
||||
|
@ -50,14 +58,6 @@ object(DOMDocument)#1 (41) {
|
|||
bool(false)
|
||||
["substituteEntities"]=>
|
||||
bool(false)
|
||||
["doctype"]=>
|
||||
NULL
|
||||
["documentElement"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["strictErrorChecking"]=>
|
||||
bool(true)
|
||||
["documentURI"]=>
|
||||
string(%d) "%s"
|
||||
["firstElementChild"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["lastElementChild"]=>
|
||||
|
|
|
@ -4,6 +4,7 @@ GH-11830 (ParentNode methods should perform their checks upfront) - document var
|
|||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
function test($method) {
|
||||
$otherDoc = new DOMDocument;
|
||||
$otherDoc->loadXML(<<<XML
|
||||
<?xml version="1.0"?>
|
||||
|
@ -24,48 +25,59 @@ XML);
|
|||
$testElement = $doc->documentElement->firstElementChild->nextElementSibling->firstElementChild;
|
||||
|
||||
try {
|
||||
$doc->documentElement->firstElementChild->prepend($testElement, $otherElement);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$doc->documentElement->firstElementChild->append($testElement, $otherElement);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$doc->documentElement->firstElementChild->before($testElement, $otherElement);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$doc->documentElement->firstElementChild->after($testElement, $otherElement);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$doc->documentElement->firstElementChild->replaceWith($testElement, $otherElement);
|
||||
$doc->documentElement->firstElementChild->$method($testElement, $otherElement);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
echo $otherDoc->saveXML();
|
||||
echo $doc->saveXML();
|
||||
}
|
||||
|
||||
test("prepend");
|
||||
test("append");
|
||||
test("before");
|
||||
test("after");
|
||||
test("replaceWith");
|
||||
?>
|
||||
--EXPECT--
|
||||
Wrong Document Error
|
||||
Wrong Document Error
|
||||
Wrong Document Error
|
||||
Wrong Document Error
|
||||
Wrong Document Error
|
||||
<?xml version="1.0"?>
|
||||
<other/>
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child><testelement/></child>
|
||||
<child/>
|
||||
</container>
|
||||
Wrong Document Error
|
||||
<?xml version="1.0"?>
|
||||
<other/>
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child/>
|
||||
</container>
|
||||
Wrong Document Error
|
||||
<?xml version="1.0"?>
|
||||
<other/>
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child/>
|
||||
</container>
|
||||
Wrong Document Error
|
||||
<?xml version="1.0"?>
|
||||
<other/>
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child/>
|
||||
</container>
|
||||
Wrong Document Error
|
||||
<?xml version="1.0"?>
|
||||
<other/>
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child/>
|
||||
</container>
|
||||
|
|
|
@ -4,6 +4,7 @@ GH-11830 (ParentNode methods should perform their checks upfront) - hierarchy va
|
|||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
function test($method) {
|
||||
$doc = new DOMDocument;
|
||||
$doc->loadXML(<<<XML
|
||||
<?xml version="1.0"?>
|
||||
|
@ -18,45 +19,28 @@ $alone = $container->firstElementChild;
|
|||
$testElement = $alone->nextElementSibling->firstElementChild;
|
||||
|
||||
try {
|
||||
$testElement->prepend($alone, $container);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$testElement->append($alone, $container);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$testElement->before($alone, $container);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$testElement->after($alone, $container);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$testElement->replaceWith($alone, $container);
|
||||
$testElement->$method($alone, $container);
|
||||
} catch (\DOMException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
echo $doc->saveXML();
|
||||
}
|
||||
|
||||
test("prepend");
|
||||
test("append");
|
||||
test("before");
|
||||
test("after");
|
||||
test("replaceWith");
|
||||
?>
|
||||
--EXPECT--
|
||||
Hierarchy Request Error
|
||||
Hierarchy Request Error
|
||||
Hierarchy Request Error
|
||||
Hierarchy Request Error
|
||||
<?xml version="1.0"?>
|
||||
Hierarchy Request Error
|
||||
<?xml version="1.0"?>
|
||||
Hierarchy Request Error
|
||||
<?xml version="1.0"?>
|
||||
Hierarchy Request Error
|
||||
<?xml version="1.0"?>
|
||||
Hierarchy Request Error
|
||||
<?xml version="1.0"?>
|
||||
<container>
|
||||
<alone/>
|
||||
<child><testelement/></child>
|
||||
</container>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/gb18030.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent = "é";
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/gb18030_output.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/gb18030_output.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->charset = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/shift_jis.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent .= "é";
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/shift_jis.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/shift_jis.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->charset = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/utf16be_bom.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->characterSet);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent = "é";
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/utf16be_bom_output.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/utf16be_bom_output.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->characterSet = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/utf16le_bom.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->inputEncoding);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent = "é";
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/utf16le_bom_output.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/utf16le_bom_output.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->inputEncoding = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/utf8_bom.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent = "é";
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/utf8_bom_output.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/utf8_bom_output.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->charset = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/windows1251.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->documentElement->firstChild->nextElementSibling->textContent .= "é"; // Note: won't show up in Windows 1251 because it doesn't exist there
|
||||
$output = $dom->saveHTML();
|
||||
echo $output, "\n";
|
||||
|
@ -14,7 +14,7 @@ $dom->saveHTMLFile(__DIR__ . "/windows1251_output.tmp");
|
|||
var_dump(file_get_contents(__DIR__ . "/windows1251_output.tmp") === $output);
|
||||
|
||||
echo "--- After changing encoding to UTF-8 ---\n";
|
||||
$dom->encoding = "UTF-8";
|
||||
$dom->charset = "UTF-8";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
|
|
@ -63,7 +63,7 @@ foreach ($tests as $name => $headers) {
|
|||
['pid' => $pid, 'uri' => $uri] = http_server($responses);
|
||||
for ($i = 0; $i < count($responses); $i++) {
|
||||
$result = DOM\HTMLDocument::createFromFile($uri, LIBXML_NOERROR);
|
||||
echo $result->textContent;
|
||||
echo $result->getElementsByTagName("p")[0]->textContent, "\n";
|
||||
}
|
||||
http_server_kill($pid);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ try {
|
|||
// The override encoding matches with the document encoding attribute
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . '/gb18030_without_charset.html', overrideEncoding: 'GB18030');
|
||||
var_dump($dom->documentElement->lastChild->textContent);
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
|
||||
// The override encoding mismatches with the document encoding attribute
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . '/fallback_encoding.html', overrideEncoding: 'Windows-1252');
|
||||
var_dump($dom->documentElement->lastChild->textContent);
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
|
|
|
@ -14,12 +14,12 @@ try {
|
|||
// The override encoding matches with the document encoding attribute
|
||||
$dom = DOM\HTMLDocument::createFromString(file_get_contents(__DIR__ . '/gb18030_without_charset.html'), overrideEncoding: 'GB18030');
|
||||
var_dump($dom->documentElement->lastChild->textContent);
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
|
||||
// The override encoding mismatches with the document encoding attribute
|
||||
$dom = DOM\HTMLDocument::createFromString(file_get_contents(__DIR__ . '/fallback_encoding.html'), overrideEncoding: 'Windows-1252');
|
||||
var_dump($dom->documentElement->lastChild->textContent);
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
|
|
|
@ -8,9 +8,11 @@ dom
|
|||
// UTF-8 -> UTF-8
|
||||
// Create a UTF-8 string where a UTF-8 byte sequence falls over the boundary of the 4096 byte buffer
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
$dom->append(str_repeat("A", 4096 - 2) . "\xf0\x90\x8d\x88AA");
|
||||
$element = $dom->createElement("container");
|
||||
$dom->append($element);
|
||||
$element->append(str_repeat("A", 4096 - 2 - strlen("<container>")) . "\xf0\x90\x8d\x88AA");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4100) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA𐍈AA"
|
||||
string(4112) "<container>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA𐍈AA</container>"
|
||||
|
|
|
@ -7,9 +7,11 @@ dom
|
|||
|
||||
// UTF-8 -> GB18030
|
||||
$dom = DOM\HTMLDocument::createEmpty("GB18030");
|
||||
$element = $dom->createElement("container");
|
||||
$dom->append($element);
|
||||
// Create a UTF-8 string where a UTF-8 byte sequence falls over the boundary of the 4096 byte buffer
|
||||
// *and* the sequence also falls over the boundary for the result
|
||||
$dom->append(str_repeat("A", 4096 - 2) . "\xf0\x90\x8d\x88AA");
|
||||
$element->append(str_repeat("A", 4096 - 2 - strlen("<container>")) . "\xf0\x90\x8d\x88AA");
|
||||
var_dump($output = $dom->saveHTML());
|
||||
|
||||
// GB18030 encoding of the above UTF-8 symbol
|
||||
|
@ -20,7 +22,7 @@ var_dump($output[4097] == "\x30");
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4100) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA𐍈AA"
|
||||
string(4112) "<container>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA𐍈AA</container>"
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
|
|
|
@ -7,11 +7,13 @@ dom
|
|||
|
||||
// UTF-8 -> GB18030
|
||||
$dom = DOM\HTMLDocument::createEmpty("GB18030");
|
||||
$element = $dom->createElement("container");
|
||||
$dom->append($element);
|
||||
// Create a UTF-8 string where an invalid UTF-8 byte sequence falls over the boundary of the 4096 byte buffer
|
||||
// Note: the strange ?1?7 sequence is the GB18030 encoding for the unicode replacement character
|
||||
$dom->append(str_repeat("A", 4096 - 2) . "\xff\xff\xff");
|
||||
$element->append(str_repeat("A", 4096 - 2 - strlen("<container>")) . "\xff\xff\xff");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4106) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD><EFBFBD><EFBFBD>"
|
||||
string(4118) "<container>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD><EFBFBD><EFBFBD></container>"
|
||||
|
|
|
@ -7,10 +7,12 @@ dom
|
|||
|
||||
// UTF-8 -> UTF-8
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
$element = $dom->createElement("container");
|
||||
$dom->append($element);
|
||||
// Create a UTF-8 string where an invalid UTF-8 byte sequence falls over the boundary of the 4096 byte buffer
|
||||
$dom->append(str_repeat("A", 4096 - 2) . "\xff\xff\xff");
|
||||
$element->append(str_repeat("A", 4096 - 2 - strlen("<container>")) . "\xff\xff\xff");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4103) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD><EFBFBD><EFBFBD>"
|
||||
string(4115) "<container>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD><EFBFBD><EFBFBD></container>"
|
||||
|
|
|
@ -11,8 +11,8 @@ $padding_required_until_4094 = 4094 - strlen($header);
|
|||
$trailer = "\x90\x30\xd5\x30";
|
||||
$dom = DOM\HTMLDocument::createFromString($header . str_repeat("A", $padding_required_until_4094) . $trailer);
|
||||
// GB18030 byte sequence crossing the 4096 boundary
|
||||
var_dump($dom->encoding);
|
||||
$dom->encoding = "UTF-8";
|
||||
var_dump($dom->charset);
|
||||
$dom->charset = "UTF-8";
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
|
|
|
@ -7,10 +7,12 @@ dom
|
|||
|
||||
// UTF-8 -> UTF-8
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
$element = $dom->createElement("container");
|
||||
$dom->append($element);
|
||||
// Create a UTF-8 string where a *broken* UTF-8 byte sequence falls over the boundary of the 4096 byte buffer
|
||||
$dom->append(str_repeat("A", 4096 - 1) . "\xf0\x90");
|
||||
$element->append(str_repeat("A", 4096 - 1 - strlen("<container>")) . "\xf0\x90");
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4101) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD><EFBFBD>"
|
||||
string(4110) "<container>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<EFBFBD></container>"
|
||||
|
|
|
@ -11,8 +11,8 @@ $padding_required_until_4095 = 4095 - strlen($header);
|
|||
$trailer = "\x90\x30";
|
||||
$dom = DOM\HTMLDocument::createFromString($header . str_repeat("A", $padding_required_until_4095) . $trailer);
|
||||
// GB18030 *broken* byte sequence crossing the 4096 boundary
|
||||
var_dump($dom->encoding);
|
||||
$dom->encoding = "UTF-8";
|
||||
var_dump($dom->charset);
|
||||
$dom->charset = "UTF-8";
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
|
|
|
@ -6,23 +6,23 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
var_dump($dom->encoding);
|
||||
$dom->encoding = "CSeuckr";
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->inputEncoding = "CSeuckr";
|
||||
var_dump($dom->characterSet);
|
||||
try {
|
||||
$dom->encoding = "nope";
|
||||
$dom->charset = "nope";
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($dom->encoding);
|
||||
$dom->encoding = "Windows-1251";
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->charset);
|
||||
$dom->inputEncoding = "Windows-1251";
|
||||
var_dump($dom->characterSet);
|
||||
try {
|
||||
$dom->encoding = NULL;
|
||||
$dom->charset = "";
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->inputEncoding);
|
||||
echo $dom->saveHTML();
|
||||
|
||||
try {
|
||||
|
|
|
@ -6,7 +6,7 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/fallback_encoding.html");
|
||||
var_dump($dom->encoding);
|
||||
var_dump($dom->inputEncoding);
|
||||
echo $dom->saveHTML();
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
--TEST--
|
||||
DOM\HTMLDocument adopts a DOMDocument
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML(<<<HTML
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
HTML);
|
||||
|
||||
$dom2 = DOM\HTMLDocument::createEmpty();
|
||||
$dom2->appendChild($dom2->adoptNode($dom->documentElement));
|
||||
echo $dom2->saveHTML();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -18,6 +18,6 @@ var_dump(get_class($element->ownerDocument));
|
|||
?>
|
||||
--EXPECTF--
|
||||
Warning: DOM\HTMLDocument::createFromString(): tree error unexpected-token-in-initial-mode in Entity, line: 1, column: 2 in %s on line %d
|
||||
string(4) "html"
|
||||
string(4) "HTML"
|
||||
string(3) "foo"
|
||||
string(16) "DOM\HTMLDocument"
|
||||
|
|
|
@ -42,6 +42,6 @@ var_dump($dom->documentURI);
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(%d) "file:/%stest%20foo.html"
|
||||
string(%d) "file://%stest%20foo.html"
|
||||
string(12) "php://memory"
|
||||
string(16) "dummy://foo/ bar"
|
||||
|
|
|
@ -67,19 +67,19 @@ var_dump($dom->getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML", "cir
|
|||
?>
|
||||
--EXPECT--
|
||||
--- getElementsByTagName ---
|
||||
string(1) "p"
|
||||
string(1) "P"
|
||||
string(4) "math"
|
||||
string(6) "mtable"
|
||||
string(3) "svg"
|
||||
string(6) "circle"
|
||||
--- getElementsByTagNameNS (*) ---
|
||||
string(1) "p"
|
||||
string(1) "P"
|
||||
string(4) "math"
|
||||
string(6) "mtable"
|
||||
string(3) "svg"
|
||||
string(6) "circle"
|
||||
--- getElementsByTagNameNS (xhtml) ---
|
||||
string(1) "p"
|
||||
string(1) "P"
|
||||
NULL
|
||||
NULL
|
||||
NULL
|
||||
|
|
|
@ -10,8 +10,8 @@ $dom->registerNodeClass("DOM\\HTMLDocument", "DOMDocument");
|
|||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: DOM\Document::registerNodeClass(): Argument #2 ($extendedClass) must be a class name derived from DOM\HTMLDocument or null, DOMDocument given in %s:%d
|
||||
Fatal error: Uncaught TypeError: DOMDocument::registerNodeClass(): Argument #1 ($baseClass) must be a class name derived from DOMNode, DOM\HTMLDocument given in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): DOM\Document->registerNodeClass('DOM\\HTMLDocumen...', 'DOMDocument')
|
||||
#0 %s(%d): DOMDocument->registerNodeClass('DOM\\HTMLDocumen...', 'DOMDocument')
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
||||
|
|
|
@ -10,7 +10,7 @@ class Custom extends DOM\Document {
|
|||
}
|
||||
}
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
try {
|
||||
$dom->registerNodeClass("DOM\\Document", "Custom");
|
||||
} catch (ValueError $e) {
|
||||
|
@ -28,9 +28,9 @@ $element->ownerDocument->foo();
|
|||
?>
|
||||
--EXPECTF--
|
||||
DOM\Document::registerNodeClass(): Argument #1 ($baseClass) must not be an abstract class
|
||||
string(11) "DOMDocument"
|
||||
string(16) "DOM\HTMLDocument"
|
||||
|
||||
Fatal error: Uncaught Error: Call to undefined method DOMDocument::foo() in %s:%d
|
||||
Fatal error: Uncaught Error: Call to undefined method DOM\HTMLDocument::foo() in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
--TEST--
|
||||
DOM\HTMLDocument::registerNodeClass 03
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Custom extends DOM\Element {
|
||||
public int $test = 1;
|
||||
|
||||
public function reverseTagName(): string {
|
||||
var_dump($this->test);
|
||||
return strrev($this->tagName);
|
||||
}
|
||||
}
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("<div>foo</div>", LIBXML_NOERROR);
|
||||
$dom->registerNodeClass("DOM\\Element", "Custom");
|
||||
|
||||
var_dump($dom->getElementsByTagName('div')[0]->reverseTagName());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
string(3) "VID"
|
|
@ -5,45 +5,57 @@ dom
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyElement extends DOM\Element {}
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR);
|
||||
$dom->strictErrorChecking = false;
|
||||
$dom->registerNodeClass("DOM\\Element", "MyElement");
|
||||
|
||||
// Destroy reference to the DOM
|
||||
$child = $dom->documentElement;
|
||||
unset($dom);
|
||||
|
||||
// Regain reference using the ownerDocument property
|
||||
// Should be a DOM\HTML5Document
|
||||
// Should be a DOM\HTMLDocument
|
||||
$dom = $child->ownerDocument;
|
||||
var_dump($dom);
|
||||
// Test if property is preserved (any random doc_props property will do)
|
||||
var_dump($dom->strictErrorChecking);
|
||||
var_dump(get_class($dom->getElementsByTagName("p")->item(0)));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(DOM\HTMLDocument)#1 (26) {
|
||||
["encoding"]=>
|
||||
object(DOM\HTMLDocument)#1 (25) {
|
||||
["implementation"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["URL"]=>
|
||||
string(11) "about:blank"
|
||||
["documentURI"]=>
|
||||
string(11) "about:blank"
|
||||
["characterSet"]=>
|
||||
string(5) "UTF-8"
|
||||
["charset"]=>
|
||||
string(5) "UTF-8"
|
||||
["inputEncoding"]=>
|
||||
string(5) "UTF-8"
|
||||
["doctype"]=>
|
||||
NULL
|
||||
["documentElement"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["strictErrorChecking"]=>
|
||||
bool(false)
|
||||
["documentURI"]=>
|
||||
NULL
|
||||
["firstElementChild"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["lastElementChild"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["childElementCount"]=>
|
||||
int(1)
|
||||
["nodeName"]=>
|
||||
string(9) "#document"
|
||||
["nodeValue"]=>
|
||||
NULL
|
||||
["nodeType"]=>
|
||||
int(13)
|
||||
["nodeName"]=>
|
||||
string(9) "#document"
|
||||
["baseURI"]=>
|
||||
string(11) "about:blank"
|
||||
["isConnected"]=>
|
||||
bool(true)
|
||||
["ownerDocument"]=>
|
||||
NULL
|
||||
["parentNode"]=>
|
||||
NULL
|
||||
["parentElement"]=>
|
||||
|
@ -58,21 +70,9 @@ object(DOM\HTMLDocument)#1 (26) {
|
|||
NULL
|
||||
["nextSibling"]=>
|
||||
NULL
|
||||
["attributes"]=>
|
||||
NULL
|
||||
["isConnected"]=>
|
||||
bool(true)
|
||||
["ownerDocument"]=>
|
||||
NULL
|
||||
["namespaceURI"]=>
|
||||
NULL
|
||||
["prefix"]=>
|
||||
string(0) ""
|
||||
["localName"]=>
|
||||
NULL
|
||||
["baseURI"]=>
|
||||
["nodeValue"]=>
|
||||
NULL
|
||||
["textContent"]=>
|
||||
string(3) "foo"
|
||||
NULL
|
||||
}
|
||||
bool(false)
|
||||
string(9) "MyElement"
|
||||
|
|
|
@ -5,9 +5,11 @@ dom
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
class MyElement extends DOM\Element {}
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR);
|
||||
$dom->strictErrorChecking = false;
|
||||
$child = $dom->appendChild($dom->createElement('html'));
|
||||
$dom->registerNodeClass("DOM\\Element", "MyElement");
|
||||
$child = $dom->documentElement->appendChild($dom->createElement('html'));
|
||||
|
||||
// Destroy reference to the DOM
|
||||
unset($dom);
|
||||
|
@ -17,33 +19,43 @@ unset($dom);
|
|||
$dom = $child->ownerDocument;
|
||||
var_dump($dom);
|
||||
// Test if property is preserved (any random doc_props property will do)
|
||||
var_dump($dom->strictErrorChecking);
|
||||
var_dump(get_class($dom->getElementsByTagName("p")->item(0)));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(DOM\HTMLDocument)#1 (26) {
|
||||
["encoding"]=>
|
||||
object(DOM\HTMLDocument)#1 (25) {
|
||||
["implementation"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["URL"]=>
|
||||
string(11) "about:blank"
|
||||
["documentURI"]=>
|
||||
string(11) "about:blank"
|
||||
["characterSet"]=>
|
||||
string(5) "UTF-8"
|
||||
["charset"]=>
|
||||
string(5) "UTF-8"
|
||||
["inputEncoding"]=>
|
||||
string(5) "UTF-8"
|
||||
["doctype"]=>
|
||||
NULL
|
||||
["documentElement"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["strictErrorChecking"]=>
|
||||
bool(false)
|
||||
["documentURI"]=>
|
||||
NULL
|
||||
["firstElementChild"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["lastElementChild"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["childElementCount"]=>
|
||||
int(2)
|
||||
["nodeName"]=>
|
||||
string(9) "#document"
|
||||
["nodeValue"]=>
|
||||
NULL
|
||||
int(1)
|
||||
["nodeType"]=>
|
||||
int(13)
|
||||
["nodeName"]=>
|
||||
string(9) "#document"
|
||||
["baseURI"]=>
|
||||
string(11) "about:blank"
|
||||
["isConnected"]=>
|
||||
bool(true)
|
||||
["ownerDocument"]=>
|
||||
NULL
|
||||
["parentNode"]=>
|
||||
NULL
|
||||
["parentElement"]=>
|
||||
|
@ -58,21 +70,9 @@ object(DOM\HTMLDocument)#1 (26) {
|
|||
NULL
|
||||
["nextSibling"]=>
|
||||
NULL
|
||||
["attributes"]=>
|
||||
NULL
|
||||
["isConnected"]=>
|
||||
bool(true)
|
||||
["ownerDocument"]=>
|
||||
NULL
|
||||
["namespaceURI"]=>
|
||||
NULL
|
||||
["prefix"]=>
|
||||
string(0) ""
|
||||
["localName"]=>
|
||||
NULL
|
||||
["baseURI"]=>
|
||||
["nodeValue"]=>
|
||||
NULL
|
||||
["textContent"]=>
|
||||
string(3) "foo"
|
||||
NULL
|
||||
}
|
||||
bool(false)
|
||||
string(9) "MyElement"
|
||||
|
|
|
@ -9,27 +9,29 @@ echo "--- Parsing ---\n";
|
|||
|
||||
$dom = DOM\HTMLDocument::createFromString("<!doctype html><html><body><noscript><p>hi</p></noscript></body></html>", DOM\HTML_NO_DEFAULT_NS);
|
||||
var_dump($dom->documentElement->textContent);
|
||||
var_dump($dom->documentElement->namespaceURI);
|
||||
echo $dom->saveHTML(), "\n";
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
|
||||
echo "--- Modifying the text content: tag ---\n";
|
||||
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
$noscript = $xpath->query("//noscript")[0];
|
||||
$noscript->textContent = "<p>bye</p>";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
|
||||
echo "--- Modifying the text content: trick ---\n";
|
||||
|
||||
$noscript->textContent = "<!-- </noscript> -->";
|
||||
echo $dom->saveHTML(), "\n";
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--- Parsing ---
|
||||
string(2) "hi"
|
||||
NULL
|
||||
<!DOCTYPE html><html><head></head><body><noscript><p>hi</p></noscript></body></html>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE html>
|
||||
|
|
|
@ -10,11 +10,13 @@ $trailer = "</body></html>";
|
|||
$data = $header . str_repeat("a", 4096 - strlen($header) - strlen($trailer)) . $trailer;
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString($header . str_repeat("a", 4096 - strlen($header) - strlen($trailer)) . $trailer);
|
||||
var_dump($dom->textContent);
|
||||
var_dump($dom->documentElement->textContent);
|
||||
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
file_put_contents(__DIR__ . "/BOM_edge.tmp", $data);
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/BOM_edge.tmp");
|
||||
var_dump($dom->textContent);
|
||||
var_dump($dom->documentElement->textContent);
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
|
@ -23,4 +25,5 @@ var_dump($dom->textContent);
|
|||
?>
|
||||
--EXPECT--
|
||||
string(4052) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
<!DOCTYPE html><html><head></head><body>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</body></html>
|
||||
string(4052) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
--TEST--
|
||||
HTMLDocument::createFromString() with namespaced attributes
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString(<<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<svg width="1" xmlns:xlink='http://www.w3.org/1999/xlink'>
|
||||
<use xlink:href='#test' foo="bar"></use>
|
||||
</svg>
|
||||
<math>
|
||||
<mo accent="true"></mo>
|
||||
</math>
|
||||
</html>
|
||||
HTML);
|
||||
|
||||
foreach (['svg', 'use', 'mo'] as $tag) {
|
||||
$el = $dom->getElementsByTagName($tag)[0];
|
||||
foreach ($el->attributes as $attribute) {
|
||||
echo "Attribute: \n";
|
||||
var_dump($attribute->name, $attribute->value, $attribute->namespaceURI);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Attribute:
|
||||
string(5) "width"
|
||||
string(1) "1"
|
||||
NULL
|
||||
Attribute:
|
||||
string(11) "xmlns:xlink"
|
||||
string(28) "http://www.w3.org/1999/xlink"
|
||||
string(29) "http://www.w3.org/2000/xmlns/"
|
||||
Attribute:
|
||||
string(10) "xlink:href"
|
||||
string(5) "#test"
|
||||
string(28) "http://www.w3.org/1999/xlink"
|
||||
Attribute:
|
||||
string(3) "foo"
|
||||
string(3) "bar"
|
||||
NULL
|
||||
Attribute:
|
||||
string(6) "accent"
|
||||
string(4) "true"
|
||||
NULL
|
|
@ -6,32 +6,32 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/paragraph.html", LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
$xpath->registerNamespace("x", "http://www.w3.org/1999/xhtml");
|
||||
var_dump($xpath->query("//p"));
|
||||
var_dump($xpath->query("//x:p"));
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromFile(__DIR__ . "/paragraph.html", LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR | DOM\HTML_NO_DEFAULT_NS);
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
$xpath->registerNamespace("x", "http://www.w3.org/1999/xhtml");
|
||||
var_dump($xpath->query("//p"));
|
||||
var_dump($xpath->query("//x:p"));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(0)
|
||||
}
|
||||
object(DOMNodeList)#4 (1) {
|
||||
object(DOM\NodeList)#4 (1) {
|
||||
["length"]=>
|
||||
int(1)
|
||||
}
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(1)
|
||||
}
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(0)
|
||||
}
|
||||
|
|
|
@ -6,32 +6,32 @@ dom
|
|||
<?php
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString(file_get_contents(__DIR__ . "/paragraph.html"), LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
$xpath->registerNamespace("x", "http://www.w3.org/1999/xhtml");
|
||||
var_dump($xpath->query("//p"));
|
||||
var_dump($xpath->query("//x:p"));
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString(file_get_contents(__DIR__ . "/paragraph.html"), LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR | DOM\HTML_NO_DEFAULT_NS);
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
$xpath->registerNamespace("x", "http://www.w3.org/1999/xhtml");
|
||||
var_dump($xpath->query("//p"));
|
||||
var_dump($xpath->query("//x:p"));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(0)
|
||||
}
|
||||
object(DOMNodeList)#4 (1) {
|
||||
object(DOM\NodeList)#4 (1) {
|
||||
["length"]=>
|
||||
int(1)
|
||||
}
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(1)
|
||||
}
|
||||
object(DOMNodeList)#3 (1) {
|
||||
object(DOM\NodeList)#3 (1) {
|
||||
["length"]=>
|
||||
int(0)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ $dom = DOM\HTMLDocument::createFromString(<<<HTML
|
|||
</html>
|
||||
HTML, LIBXML_COMPACT);
|
||||
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
foreach ($xpath->query("//*[name()='p']") as $p) {
|
||||
echo $p->textContent, "\n";
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@ dom
|
|||
echo "--- No elements ---\n";
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("", LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
|
||||
echo "--- Single element ---\n";
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("<p>foo</p>", LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
var_dump($dom->documentElement->namespaceURI);
|
||||
var_dump($dom->documentElement->prefix);
|
||||
|
||||
echo "--- Multiple elements ---\n";
|
||||
|
||||
$dom = DOM\HTMLDocument::createFromString("<p>foo</p><strong>bar</strong>", LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
var_dump($dom->documentElement->namespaceURI);
|
||||
var_dump($dom->documentElement->prefix);
|
||||
var_dump($dom->documentElement->nextSibling->namespaceURI);
|
||||
|
@ -30,16 +30,16 @@ var_dump($dom->documentElement->nextSibling->prefix);
|
|||
--EXPECT--
|
||||
--- No elements ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
|
||||
--- Single element ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<p xmlns="http://www.w3.org/1999/xhtml">foo</p>
|
||||
string(28) "http://www.w3.org/1999/xhtml"
|
||||
string(0) ""
|
||||
NULL
|
||||
--- Multiple elements ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<p xmlns="http://www.w3.org/1999/xhtml">foo</p>
|
||||
<strong xmlns="http://www.w3.org/1999/xhtml">bar</strong>
|
||||
<p xmlns="http://www.w3.org/1999/xhtml">foo</p><strong xmlns="http://www.w3.org/1999/xhtml">bar</strong>
|
||||
string(28) "http://www.w3.org/1999/xhtml"
|
||||
string(0) ""
|
||||
NULL
|
||||
string(28) "http://www.w3.org/1999/xhtml"
|
||||
string(0) ""
|
||||
NULL
|
||||
|
|
|
@ -22,7 +22,7 @@ $dom = DOM\HTMLDocument::createFromString(<<<HTML
|
|||
</html>
|
||||
HTML);
|
||||
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
|
||||
foreach ($xpath->query("//*") as $element) {
|
||||
echo "Element: '", $element->tagName, "', ", $element->getLineNo(), "\n";
|
||||
|
@ -44,13 +44,13 @@ foreach ($xpath->query("//comment()") as $comment) {
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
Element: 'html', 1
|
||||
Element: 'head', 2
|
||||
Element: 'title', 3
|
||||
Element: 'body', 5
|
||||
Element: 'div', 6
|
||||
Element: 'p', 7
|
||||
Element: 'strong', 8
|
||||
Element: 'HTML', 1
|
||||
Element: 'HEAD', 2
|
||||
Element: 'TITLE', 3
|
||||
Element: 'BODY', 5
|
||||
Element: 'DIV', 6
|
||||
Element: 'P', 7
|
||||
Element: 'STRONG', 8
|
||||
Text: 'This is my paragraph', 8
|
||||
Attribute: 'id', 6
|
||||
Attribute: 'x', 6
|
||||
|
|
|
@ -28,7 +28,7 @@ $dom = DOM\HTMLDocument::createFromString(<<<HTML
|
|||
HTML);
|
||||
|
||||
echo "--- Namespaces ---\n";
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
foreach ($xpath->query("//*[name()='body']//*") as $node) {
|
||||
echo $node->nodeName, " ", $node->namespaceURI ?? "(NONE)", "\n";
|
||||
foreach ($node->attributes as $attribute) {
|
||||
|
@ -54,8 +54,8 @@ rect http://www.w3.org/2000/svg
|
|||
Attribute: y (NONE)
|
||||
Attribute: width (NONE)
|
||||
Attribute: height (NONE)
|
||||
div http://www.w3.org/1999/xhtml
|
||||
p http://www.w3.org/1999/xhtml
|
||||
DIV http://www.w3.org/1999/xhtml
|
||||
P http://www.w3.org/1999/xhtml
|
||||
math http://www.w3.org/1998/Math/MathML
|
||||
mtable http://www.w3.org/1998/Math/MathML
|
||||
Attribute: id (NONE)
|
||||
|
|
|
@ -18,7 +18,7 @@ $dom = DOM\HTMLDocument::createFromString(<<<HTML
|
|||
HTML);
|
||||
|
||||
echo "--- Namespaces ---\n";
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath = new DOM\XPath($dom);
|
||||
foreach ($xpath->query("//*[name()='body']//*") as $node) {
|
||||
echo $node->nodeName, " ", $node->namespaceURI ?? "(NONE)", "\n";
|
||||
echo "prefix: \"", $node->prefix, "\"\n";
|
||||
|
@ -35,7 +35,7 @@ echo $dom->saveXML();
|
|||
?>
|
||||
--EXPECT--
|
||||
--- Namespaces ---
|
||||
foo:bar http://www.w3.org/1999/xhtml
|
||||
FOO:BAR http://www.w3.org/1999/xhtml
|
||||
prefix: ""
|
||||
--- HTML serialization ---
|
||||
<!DOCTYPE html><html><head>
|
||||
|
@ -52,6 +52,6 @@ prefix: ""
|
|||
<title>Test</title>
|
||||
</head>
|
||||
<body xmlns:foo="urn:hi">
|
||||
<foo:bar/>
|
||||
<foo:bar></foo:bar>
|
||||
|
||||
</body></html>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
--TEST--
|
||||
Serialize entity reference
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom1 = new DOMDocument();
|
||||
$root = $dom1->appendChild($dom1->createElement('root'));
|
||||
$root->appendChild($dom1->createEntityReference('nbsp'));
|
||||
|
||||
$dom2 = DOM\HTMLDocument::createEmpty();
|
||||
$dom2->appendChild($dom2->importLegacyNode($root, true));
|
||||
|
||||
echo $dom2->saveXML(), "\n";
|
||||
echo $dom2->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<root> </root>
|
||||
<root> </root>
|
|
@ -9,8 +9,7 @@ $dom = DOM\HTMLDocument::createEmpty();
|
|||
$root = $dom->appendChild($dom->createElement("root"));
|
||||
$root->setAttributeNodeNS($dom->createAttributeNS("http://php.net", "x:foo"));
|
||||
$root->setAttributeNodeNS($dom->createAttributeNS("http://www.w3.org/XML/1998/namespace", "y:id"));
|
||||
// Can't test the following because its behaviour is broken in combination with the live spec
|
||||
//$root->setAttributeNodeNS($dom->createAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns"));
|
||||
$root->setAttributeNodeNS($dom->createAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns"));
|
||||
$root->setAttributeNodeNS($dom->createAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:f"));
|
||||
$root->setAttributeNodeNS($dom->createAttributeNS("http://www.w3.org/1999/xlink", "z:f"));
|
||||
|
||||
|
@ -19,4 +18,4 @@ echo $dom->saveHTML();
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
<root x:foo="" xml:id="" xmlns:f="" xlink:f=""></root>
|
||||
<root x:foo="" xml:id="" xmlns="" xmlns:f="" xlink:f=""></root>
|
||||
|
|
|
@ -5,10 +5,15 @@ dom
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
// Note: can't create CData in an HTML document.
|
||||
$dom = DOM\XMLDocument::createEmpty();
|
||||
$cdata = $dom->createCDATASection("foobaré\"<>-&");
|
||||
|
||||
$dom = DOM\HTMLDocument::createEmpty();
|
||||
$dom->appendChild($dom->createCDATASection("foobaré\"<>-&"));
|
||||
$container = $dom->appendChild($dom->createElement("container"));
|
||||
$container->appendChild($dom->importNode($cdata));
|
||||
echo $dom->saveHTML();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
foobaré"<>-&
|
||||
<container>foobaré"<>-&</container>
|
||||
|
|
|
@ -16,10 +16,10 @@ $dom = DOM\HTMLDocument::createFromString(<<<HTML
|
|||
HTML, LIBXML_NOERROR);
|
||||
|
||||
echo "--- XML encoding ---\n";
|
||||
echo $dom->saveXML();
|
||||
echo $dom->saveXML(), "\n";
|
||||
echo "--- HTML encoding ---\n";
|
||||
// We don't expect to see the public ID and the system ID because the serialization algorithm doesn't serialize those
|
||||
echo $dom->saveHTML();
|
||||
echo $dom->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
|
|
|
@ -8,7 +8,7 @@ dom
|
|||
$xml = DOM\XMLDocument::createFromString('<?xml version="1.0"?><container xmlns="some:ns" xmlns:bar="another:ns"/>');
|
||||
$xml->documentElement->setAttributeNS("http://foo/", "foo:bar", "value");
|
||||
$xml->documentElement->appendChild($xml->createElementNS('some:ns2', 'child'));
|
||||
echo $xml->saveXML();
|
||||
echo $xml->saveXML(), "\n";
|
||||
|
||||
echo "--- After import into HTML ---\n";
|
||||
|
||||
|
@ -17,7 +17,7 @@ $html = DOM\HTMLDocument::createFromString('<p>foo</p>', LIBXML_NOERROR);
|
|||
$p = $html->documentElement->firstChild->nextSibling->firstChild;
|
||||
$p->appendChild($html->importNode($xml->documentElement, true));
|
||||
|
||||
echo $html->saveXML();
|
||||
echo $html->saveXML(), "\n";
|
||||
echo $html->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
@ -26,5 +26,5 @@ echo $html->saveHTML(), "\n";
|
|||
<container xmlns="some:ns" xmlns:bar="another:ns" xmlns:foo="http://foo/" foo:bar="value"><child xmlns="some:ns2"/></container>
|
||||
--- After import into HTML ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head/><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns" xmlns:foo="http://foo/" foo:bar="value"><child xmlns="some:ns2"/></container></p></body></html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns" xmlns:foo="http://foo/" foo:bar="value"><child xmlns="some:ns2"/></container></p></body></html>
|
||||
<html><head></head><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns" foo:bar="value"><child></child></container></p></body></html>
|
||||
|
|
|
@ -7,7 +7,7 @@ dom
|
|||
|
||||
$xml = DOM\XMLDocument::createFromFile(__DIR__.'/sample.xml');
|
||||
$xml->documentElement->appendChild($xml->createElementNS('some:ns2', 'child'));
|
||||
echo $xml->saveXML();
|
||||
echo $xml->saveXML(), "\n";
|
||||
|
||||
echo "--- After import into HTML ---\n";
|
||||
|
||||
|
@ -16,7 +16,7 @@ $html = DOM\HTMLDocument::createFromString('<p>foo</p>', LIBXML_NOERROR);
|
|||
$p = $html->documentElement->firstChild->nextSibling->firstChild;
|
||||
$p->appendChild($html->importNode($xml->documentElement, true));
|
||||
|
||||
echo $html->saveXML();
|
||||
echo $html->saveXML(), "\n";
|
||||
echo $html->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
@ -35,7 +35,7 @@ echo $html->saveHTML(), "\n";
|
|||
<child xmlns="some:ns2"/></container>
|
||||
--- After import into HTML ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head/><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns">
|
||||
<x>
|
||||
<subcontainer>
|
||||
<test xmlns="x:y"/>
|
||||
|
|
|
@ -7,7 +7,7 @@ dom
|
|||
|
||||
$xml = DOM\XMLDocument::createFromFile(__DIR__.'/sample.xml');
|
||||
$xml->documentElement->appendChild($xml->createElementNS('some:ns2', 'child'));
|
||||
echo $xml->saveXML();
|
||||
echo $xml->saveXML(), "\n";
|
||||
|
||||
echo "--- After import into HTML ---\n";
|
||||
|
||||
|
@ -16,7 +16,7 @@ $html = DOM\HTMLDocument::createFromString('<p>foo</p>', LIBXML_NOERROR);
|
|||
$p = $html->documentElement->firstChild->nextSibling->firstChild;
|
||||
$p->appendChild($html->importNode($xml->documentElement, false));
|
||||
|
||||
echo $html->saveXML();
|
||||
echo $html->saveXML(), "\n";
|
||||
echo $html->saveHTML(), "\n";
|
||||
|
||||
?>
|
||||
|
@ -35,5 +35,5 @@ echo $html->saveHTML(), "\n";
|
|||
<child xmlns="some:ns2"/></container>
|
||||
--- After import into HTML ---
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head/><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns"/></p></body></html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns"/></p></body></html>
|
||||
<html><head></head><body><p>foo<container xmlns="some:ns" xmlns:bar="another:ns"></container></p></body></html>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue