From ea00ab9f792f66b86aa04fb41de0611e6de195a4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 25 Jul 2023 22:22:01 +0200 Subject: [PATCH 1/2] Implement LIBXML_NOXMLDECL Fixes GH-11792. --- ext/dom/document.c | 64 ++++++++++++------- .../DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt | 24 +++++++ 2 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 ext/dom/tests/DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt diff --git a/ext/dom/document.c b/ext/dom/document.c index aabccd072085c..16351bd32b6de 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -23,6 +23,7 @@ #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" #include +#include #ifdef LIBXML_SCHEMAS_ENABLED #include #include @@ -1462,9 +1463,9 @@ PHP_METHOD(DOMDocument, saveXML) xmlDoc *docp; xmlNode *node; xmlBufferPtr buf; - xmlChar *mem; + const xmlChar *mem; dom_object *intern, *nodeobj; - int size, format, saveempty = 0; + int size, format, saveempty; zend_long options = 0; id = ZEND_THIS; @@ -1484,42 +1485,57 @@ PHP_METHOD(DOMDocument, saveXML) php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document)); RETURN_FALSE; } + buf = xmlBufferCreate(); if (!buf) { php_error_docref(NULL, E_WARNING, "Could not fetch buffer"); RETURN_FALSE; } - if (options & LIBXML_SAVE_NOEMPTYTAG) { - saveempty = xmlSaveNoEmptyTags; - xmlSaveNoEmptyTags = 1; - } + saveempty = xmlSaveNoEmptyTags; + xmlSaveNoEmptyTags = !!(options & LIBXML_SAVE_NOEMPTYTAG); xmlNodeDump(buf, docp, node, 0, format); - if (options & LIBXML_SAVE_NOEMPTYTAG) { - xmlSaveNoEmptyTags = saveempty; - } - mem = (xmlChar*) xmlBufferContent(buf); - if (!mem) { - xmlBufferFree(buf); + xmlSaveNoEmptyTags = saveempty; + } else { + buf = xmlBufferCreate(); + if (!buf) { + php_error_docref(NULL, E_WARNING, "Could not fetch buffer"); RETURN_FALSE; } - RETVAL_STRING((char *) mem); - xmlBufferFree(buf); - } else { - if (options & LIBXML_SAVE_NOEMPTYTAG) { - saveempty = xmlSaveNoEmptyTags; - xmlSaveNoEmptyTags = 1; + + int converted_options = XML_SAVE_AS_XML; + if (options & XML_SAVE_NO_DECL) { + converted_options |= XML_SAVE_NO_DECL; + } + if (format) { + converted_options |= XML_SAVE_FORMAT; } /* Encoding is handled from the encoding property set on the document */ - xmlDocDumpFormatMemory(docp, &mem, &size, format); - if (options & LIBXML_SAVE_NOEMPTYTAG) { - xmlSaveNoEmptyTags = saveempty; + saveempty = xmlSaveNoEmptyTags; + xmlSaveNoEmptyTags = !!(options & LIBXML_SAVE_NOEMPTYTAG); + xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(buf, (const char *) docp->encoding, converted_options); + xmlSaveNoEmptyTags = saveempty; + if (UNEXPECTED(!ctxt)) { + xmlBufferFree(buf); + php_error_docref(NULL, E_WARNING, "Could not create save context"); + RETURN_FALSE; } - if (!size || !mem) { + if (UNEXPECTED(xmlSaveDoc(ctxt, docp) < 0)) { + (void) xmlSaveClose(ctxt); + xmlBufferFree(buf); + php_error_docref(NULL, E_WARNING, "Could not save document"); RETURN_FALSE; } - RETVAL_STRINGL((char *) mem, size); - xmlFree(mem); + (void) xmlSaveFlush(ctxt); + (void) xmlSaveClose(ctxt); + } + mem = xmlBufferContent(buf); + if (!mem) { + xmlBufferFree(buf); + RETURN_FALSE; } + size = xmlBufferLength(buf); + RETVAL_STRINGL((const char *) mem, size); + xmlBufferFree(buf); } /* }}} end dom_document_savexml */ diff --git a/ext/dom/tests/DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt b/ext/dom/tests/DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt new file mode 100644 index 0000000000000..240e5d498482d --- /dev/null +++ b/ext/dom/tests/DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt @@ -0,0 +1,24 @@ +--TEST-- +DOMDocument::saveXML(): XML_SAVE_NO_DECL +--EXTENSIONS-- +dom +--FILE-- +loadXML('é'); + +echo $doc->saveXML(options: 0); +echo $doc->saveXML(options: LIBXML_NOXMLDECL); +$doc->encoding = "BIG5"; +echo $doc->saveXML(options: LIBXML_NOXMLDECL); + +// Edge case +$doc = new DOMDocument(); +var_dump($doc->saveXML(options: LIBXML_NOXMLDECL)); +?> +--EXPECT-- + +é +é +é +string(0) "" From c17229201be1e44dd663ad05267015eb16d4f8c5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:12:18 +0200 Subject: [PATCH 2/2] Address review comments --- ext/dom/document.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ext/dom/document.c b/ext/dom/document.c index 16351bd32b6de..a836be09306bd 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1465,7 +1465,7 @@ PHP_METHOD(DOMDocument, saveXML) xmlBufferPtr buf; const xmlChar *mem; dom_object *intern, *nodeobj; - int size, format, saveempty; + int size, format, old_xml_save_no_empty_tags; zend_long options = 0; id = ZEND_THIS; @@ -1491,10 +1491,11 @@ PHP_METHOD(DOMDocument, saveXML) php_error_docref(NULL, E_WARNING, "Could not fetch buffer"); RETURN_FALSE; } - saveempty = xmlSaveNoEmptyTags; - xmlSaveNoEmptyTags = !!(options & LIBXML_SAVE_NOEMPTYTAG); + /* 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); - xmlSaveNoEmptyTags = saveempty; + xmlSaveNoEmptyTags = old_xml_save_no_empty_tags; } else { buf = xmlBufferCreate(); if (!buf) { @@ -1509,11 +1510,12 @@ PHP_METHOD(DOMDocument, saveXML) if (format) { converted_options |= XML_SAVE_FORMAT; } + /* Save libxml2 global, override its vaule, and restore after saving. */ + old_xml_save_no_empty_tags = xmlSaveNoEmptyTags; + xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0; /* Encoding is handled from the encoding property set on the document */ - saveempty = xmlSaveNoEmptyTags; - xmlSaveNoEmptyTags = !!(options & LIBXML_SAVE_NOEMPTYTAG); xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(buf, (const char *) docp->encoding, converted_options); - xmlSaveNoEmptyTags = saveempty; + xmlSaveNoEmptyTags = old_xml_save_no_empty_tags; if (UNEXPECTED(!ctxt)) { xmlBufferFree(buf); php_error_docref(NULL, E_WARNING, "Could not create save context");