Skip to content

Commit

Permalink
Fix GH-11792: LIBXML_NOXMLDECL is not implemented or broken
Browse files Browse the repository at this point in the history
Fixes GH-11792.
Closes GH-11794.
  • Loading branch information
nielsdos committed Jul 26, 2023
1 parent 8ac0dcc commit 4bee574
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 24 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ PHP NEWS
- Core:
. Fixed oss-fuzz #60741 (Leak in open_basedir). (ilutov)

- DOM:
. Fixed bug GH-11792 (LIBXML_NOXMLDECL is not implemented or broken).
(nielsdos)

- FFI:
. Fix leaking definitions when using FFI::cdef()->new(...). (ilutov)

Expand Down
66 changes: 42 additions & 24 deletions ext/dom/document.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include <libxml/SAX.h>
#include <libxml/xmlsave.h>
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
Expand Down Expand Up @@ -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, old_xml_save_no_empty_tags;
zend_long options = 0;

id = ZEND_THIS;
Expand All @@ -1484,42 +1485,59 @@ 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;
}
/* 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 (options & LIBXML_SAVE_NOEMPTYTAG) {
xmlSaveNoEmptyTags = saveempty;
}
mem = (xmlChar*) xmlBufferContent(buf);
if (!mem) {
xmlBufferFree(buf);
xmlSaveNoEmptyTags = old_xml_save_no_empty_tags;
} 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;
}
/* 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 */
xmlDocDumpFormatMemory(docp, &mem, &size, format);
if (options & LIBXML_SAVE_NOEMPTYTAG) {
xmlSaveNoEmptyTags = saveempty;
xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(buf, (const char *) docp->encoding, converted_options);
xmlSaveNoEmptyTags = old_xml_save_no_empty_tags;
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 */

Expand Down
24 changes: 24 additions & 0 deletions ext/dom/tests/DOMDocument_saveXML_XML_SAVE_NO_DECL.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
DOMDocument::saveXML(): XML_SAVE_NO_DECL
--EXTENSIONS--
dom
--FILE--
<?php
$doc = new DOMDocument();
$doc->loadXML('<root>é</root>');

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--
<?xml version="1.0"?>
<root>&#xE9;</root>
<root>&#xE9;</root>
<root>&#233;</root>
string(0) ""

0 comments on commit 4bee574

Please sign in to comment.