Skip to content

Commit 2d21eb7

Browse files
committed
Fixes
1 parent 2e6f51d commit 2d21eb7

File tree

7 files changed

+88
-16
lines changed

7 files changed

+88
-16
lines changed

ext/dom/document.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,9 +1104,47 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
11041104
}
11051105
}
11061106

1107+
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */
1108+
#if LIBXML_VERSION < 21000
1109+
static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_dict, xmlChar *str)
1110+
{
1111+
if (str == NULL) {
1112+
return NULL;
1113+
}
1114+
if (xmlDictOwns(src_dict, str) == 1) {
1115+
if (dst_dict == NULL) {
1116+
return xmlStrdup(str);
1117+
}
1118+
return BAD_CAST xmlDictLookup(dst_dict, str, -1);
1119+
}
1120+
return str;
1121+
}
1122+
1123+
static void libxml_fixup_name_and_content(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
1124+
{
1125+
if (src_doc != NULL && dst_doc != src_doc && src_doc->dict != NULL) {
1126+
node->name = libxml_copy_dicted_string(src_doc->dict, dst_doc->dict, BAD_CAST node->name);
1127+
node->content = libxml_copy_dicted_string(src_doc->dict, NULL, node->content);
1128+
}
1129+
}
1130+
1131+
static void libxml_fixup_name_and_content_element(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
1132+
{
1133+
libxml_fixup_name_and_content(src_doc, dst_doc, node);
1134+
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
1135+
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
1136+
}
1137+
1138+
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
1139+
libxml_fixup_name_and_content_element(src_doc, dst_doc, child);
1140+
}
1141+
}
1142+
#endif
1143+
11071144
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document)
11081145
{
1109-
php_libxml_invalidate_node_list_cache_from_doc(nodep->doc);
1146+
xmlDocPtr original_document = nodep->doc;
1147+
php_libxml_invalidate_node_list_cache_from_doc(original_document);
11101148
if (nodep->doc != new_document) {
11111149
php_libxml_invalidate_node_list_cache(dom_object_new_document->document);
11121150

@@ -1116,8 +1154,12 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
11161154
xmlUnlinkNode(nodep);
11171155
xmlSetTreeDoc(nodep, new_document);
11181156
dom_libxml_reconcile_modern(nodep);
1157+
1158+
#if LIBXML_VERSION < 21000
1159+
libxml_fixup_name_and_content_element(original_document, new_document, nodep);
1160+
#endif
11191161
} else {
1120-
int ret = xmlDOMWrapAdoptNode(NULL, nodep->doc, nodep, new_document, NULL, /* options, unused */ 0);
1162+
int ret = xmlDOMWrapAdoptNode(NULL, original_document, nodep, new_document, NULL, /* options, unused */ 0);
11211163
if (UNEXPECTED(ret != 0)) {
11221164
return false;
11231165
}

ext/dom/html_document.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,9 @@ PHP_METHOD(DOM_HTMLDocument, createFromFile)
10811081
xmlFree(converted);
10821082
lxml_doc->URL = new_buffer;
10831083
} else {
1084+
#if PHP_WIN32
1085+
converted = php_dom_libxml_fix_file_path(converted);
1086+
#endif
10841087
lxml_doc->URL = converted;
10851088
}
10861089
} else {

ext/dom/php_dom.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,4 +2218,22 @@ xmlAttrPtr php_dom_get_attribute_node(xmlNodePtr elem, const xmlChar *name, size
22182218
return ret;
22192219
}
22202220

2221+
/* Workaround for a libxml2 bug on Windows: https://gitlab.gnome.org/GNOME/libxml2/-/issues/611. */
2222+
xmlChar *php_dom_libxml_fix_file_path(xmlChar *path)
2223+
{
2224+
if (strncmp((char *) path, "file:/", sizeof("file:/") - 1) == 0) {
2225+
if (path[6] != '/' && path[6] != '\0' && path[7] != '/' && path[7] != '\0') {
2226+
/* The path is file:/xx... where xx != "//", which is broken */
2227+
xmlChar *new_path = xmlStrdup(BAD_CAST "file:///");
2228+
if (UNEXPECTED(new_path == NULL)) {
2229+
return path;
2230+
}
2231+
new_path = xmlStrcat(new_path, path + 6);
2232+
xmlFree(path);
2233+
return new_path;
2234+
}
2235+
}
2236+
return path;
2237+
}
2238+
22212239
#endif /* HAVE_DOM */

ext/dom/php_dom.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ bool php_dom_has_child_of_type(xmlNodePtr node, xmlElementType type);
164164
void php_dom_update_document_after_clone(dom_object *original, xmlNodePtr original_node, dom_object *clone, xmlNodePtr cloned_node);
165165
void php_dom_document_constructor(INTERNAL_FUNCTION_PARAMETERS);
166166
xmlAttrPtr php_dom_get_attribute_node(xmlNodePtr elem, const xmlChar *name, size_t name_len);
167+
xmlChar *php_dom_libxml_fix_file_path(xmlChar *path);
167168

168169
dom_object *php_dom_instantiate_object_helper(zval *return_value, zend_class_entry *ce, xmlNodePtr obj, dom_object *parent);
169170

ext/dom/tests/modern/html/encoding/HTMLDocument_createFromFile_http_header.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ foreach ($tests as $name => $headers) {
6363
['pid' => $pid, 'uri' => $uri] = http_server($responses);
6464
for ($i = 0; $i < count($responses); $i++) {
6565
$result = DOM\HTMLDocument::createFromFile($uri, LIBXML_NOERROR);
66-
echo $result->textContent;
66+
echo $result->getElementsByTagName("p")[0]->textContent, "\n";
6767
}
6868
http_server_kill($pid);
6969
}

ext/dom/tests/modern/spec/clone_document.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ dom
88
$dom = DOM\XMLDocument::createFromString(<<<XML
99
<?xml version="1.0" encoding="UTF-8"?>
1010
<!DOCTYPE root [
11-
<!ELEMENT root (child, child2)>
1211
<!ELEMENT child (#PCDATA)>
1312
<!ELEMENT child2 (#PCDATA)>
1413
<!ENTITY foo "bar">
@@ -50,7 +49,6 @@ string(3) "foo"
5049
---
5150
<?xml version="1.0" encoding="UTF-8"?>
5251
<!DOCTYPE root [
53-
<!ELEMENT root (child , child2)>
5452
<!ELEMENT child (#PCDATA)>
5553
<!ELEMENT child2 (#PCDATA)>
5654
<!ENTITY foo "bar">

ext/dom/xml_document.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,18 +194,28 @@ static void load_from_helper(INTERNAL_FUNCTION_PARAMETERS, int mode)
194194
lxml_doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
195195
}
196196
}
197-
if (mode == DOM_LOAD_FILE && lxml_doc->URL != NULL && !php_is_stream_path((char *) lxml_doc->URL)) {
198-
/* Check for "file:/" instead of "file://" because of libxml2 quirk */
199-
if (strncmp((const char *) lxml_doc->URL, "file:/", sizeof("file:/") - 1) != 0) {
200-
xmlChar *buffer = xmlStrdup((const xmlChar *) "file://");
201-
if (buffer != NULL) {
202-
xmlChar *new_buffer = xmlStrcat(buffer, lxml_doc->URL);
203-
if (new_buffer != NULL) {
204-
xmlFree(BAD_CAST lxml_doc->URL);
205-
lxml_doc->URL = new_buffer;
206-
} else {
207-
xmlFree(buffer);
197+
if (mode == DOM_LOAD_FILE && lxml_doc->URL != NULL) {
198+
if (!php_is_stream_path((char *) lxml_doc->URL)) {
199+
/* Check for "file:/" instead of "file://" because of libxml2 quirk */
200+
if (strncmp((const char *) lxml_doc->URL, "file:/", sizeof("file:/") - 1) != 0) {
201+
#if PHP_WIN32
202+
xmlChar *buffer = xmlStrdup((const xmlChar *) "file:///");
203+
#else
204+
xmlChar *buffer = xmlStrdup((const xmlChar *) "file://");
205+
#endif
206+
if (buffer != NULL) {
207+
xmlChar *new_buffer = xmlStrcat(buffer, lxml_doc->URL);
208+
if (new_buffer != NULL) {
209+
xmlFree(BAD_CAST lxml_doc->URL);
210+
lxml_doc->URL = new_buffer;
211+
} else {
212+
xmlFree(buffer);
213+
}
208214
}
215+
} else {
216+
#if PHP_WIN32
217+
lxml_doc->URL = php_dom_libxml_fix_file_path(BAD_CAST lxml_doc->URL);
218+
#endif
209219
}
210220
}
211221
}

0 commit comments

Comments
 (0)