Backport libxml2 2.13.2 fixes (#14816)

Backproted from https://github.com/php/php-src/pull/14789
This commit is contained in:
Niels Dossche 2024-07-04 06:29:50 -07:00 committed by GitHub
parent 7b74cadf8c
commit 4fe821311c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 109 additions and 27 deletions

View file

@ -1292,11 +1292,13 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) { if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
options |= XML_PARSE_NOBLANKS; options |= XML_PARSE_NOBLANKS;
} }
if (recover) {
options |= XML_PARSE_RECOVER;
}
php_libxml_sanitize_parse_ctxt_options(ctxt); php_libxml_sanitize_parse_ctxt_options(ctxt);
xmlCtxtUseOptions(ctxt, options); xmlCtxtUseOptions(ctxt, options);
ctxt->recovery = recover;
if (recover) { if (recover) {
old_error_reporting = EG(error_reporting); old_error_reporting = EG(error_reporting);
EG(error_reporting) = old_error_reporting | E_WARNING; EG(error_reporting) = old_error_reporting | E_WARNING;
@ -1306,7 +1308,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
if (ctxt->wellFormed || recover) { if (ctxt->wellFormed || recover) {
ret = ctxt->myDoc; ret = ctxt->myDoc;
if (ctxt->recovery) { if (recover) {
EG(error_reporting) = old_error_reporting; EG(error_reporting) = old_error_reporting;
} }
/* If loading from memory, set the base reference uri for the document */ /* If loading from memory, set the base reference uri for the document */

View file

@ -15,4 +15,4 @@ $result = $doc->loadHTMLFile(__DIR__ . "/ffff/test.html");
assert($result === false); assert($result === false);
?> ?>
--EXPECTF-- --EXPECTF--
%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O warning : failed to load external entity %s %r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O %s

View file

@ -23,7 +23,7 @@ domdocumentloadxml_test_method.inc
--EXPECTF-- --EXPECTF--
Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d
Warning: DOMDocument::loadXML(): internal error: xmlParseStartTag: problem parsing attributes in Entity, line: 4 in %s on line %d Warning: DOMDocument::loadXML():%sattributes%s
Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d

View file

@ -23,7 +23,7 @@ domdocumentload_test_method.inc
--EXPECTF-- --EXPECTF--
Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d
Warning: DOMDocument::load(): internal error: xmlParseStartTag: problem parsing attributes in %s on line %d Warning: DOMDocument::load():%sattributes%s
Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d

View file

@ -20,7 +20,7 @@ $result = $doc->relaxNGValidate($rng);
var_dump($result); var_dump($result);
?> ?>
--EXPECTF-- --EXPECTF--
Warning: DOMDocument::relaxNGValidate(): I/O warning : failed to load external entity "%s/foo.rng" in %s on line %d Warning: DOMDocument::relaxNGValidate(): I/O %s : failed to load %s
Warning: DOMDocument::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

View file

@ -5,6 +5,10 @@ Knut Urdalen <knut@php.net>
#PHPTestFest2009 Norway 2009-06-09 \o/ #PHPTestFest2009 Norway 2009-06-09 \o/
--EXTENSIONS-- --EXTENSIONS--
dom dom
--SKIPIF--
<?php
if (LIBXML_VERSION >= 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
?>
--FILE-- --FILE--
<?php <?php
$filename = __DIR__."/DOMDocument_saveHTMLFile_basic.html"; $filename = __DIR__."/DOMDocument_saveHTMLFile_basic.html";

View file

@ -5,6 +5,10 @@ Knut Urdalen <knut@php.net>
#PHPTestFest2009 Norway 2009-06-09 \o/ #PHPTestFest2009 Norway 2009-06-09 \o/
--EXTENSIONS-- --EXTENSIONS--
dom dom
--SKIPIF--
<?php
if (LIBXML_VERSION >= 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
?>
--FILE-- --FILE--
<?php <?php
$filename = __DIR__."/DOMDocument_saveHTMLFile_formatOutput.html"; $filename = __DIR__."/DOMDocument_saveHTMLFile_formatOutput.html";

View file

@ -0,0 +1,32 @@
--TEST--
DOMDocument::saveHTMLFile() should format output on demand
--CREDITS--
Knut Urdalen <knut@php.net>
#PHPTestFest2009 Norway 2009-06-09 \o/
--EXTENSIONS--
dom
--SKIPIF--
<?php
if (LIBXML_VERSION < 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
?>
--FILE--
<?php
$filename = __DIR__."/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.html";
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$root = $doc->createElement('html');
$root = $doc->appendChild($root);
$head = $doc->createElement('head');
$head = $root->appendChild($head);
$title = $doc->createElement('title');
$title = $head->appendChild($title);
$text = $doc->createTextNode('This is the title');
$text = $title->appendChild($text);
$bytes = $doc->saveHTMLFile($filename);
var_dump($bytes);
echo file_get_contents($filename);
unlink($filename);
?>
--EXPECT--
int(59)
<html><head><title>This is the title</title></head></html>

View file

@ -0,0 +1,31 @@
--TEST--
DOMDocument::saveHTMLFile() should dump the internal document into a file using HTML formatting
--CREDITS--
Knut Urdalen <knut@php.net>
#PHPTestFest2009 Norway 2009-06-09 \o/
--EXTENSIONS--
dom
--SKIPIF--
<?php
if (LIBXML_VERSION < 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
?>
--FILE--
<?php
$filename = __DIR__."/DOMDocument_saveHTMLFile_basic_gte_2_13.html";
$doc = new DOMDocument('1.0');
$root = $doc->createElement('html');
$root = $doc->appendChild($root);
$head = $doc->createElement('head');
$head = $root->appendChild($head);
$title = $doc->createElement('title');
$title = $head->appendChild($title);
$text = $doc->createTextNode('This is the title');
$text = $title->appendChild($text);
$bytes = $doc->saveHTMLFile($filename);
var_dump($bytes);
echo file_get_contents($filename);
unlink($filename);
?>
--EXPECT--
int(59)
<html><head><title>This is the title</title></head></html>

View file

@ -17,7 +17,7 @@ var_dump($result);
?> ?>
--EXPECTF-- --EXPECTF--
Warning: DOMDocument::schemaValidate(): I/O warning : failed to load external entity "%snon-existent-file" in %s.php on line %d Warning: DOMDocument::schemaValidate(): I/O %s : failed to load %s
Warning: DOMDocument::schemaValidate(): Failed to locate the main schema resource at '%s/non-existent-file'. in %s.php on line %d Warning: DOMDocument::schemaValidate(): Failed to locate the main schema resource at '%s/non-existent-file'. in %s.php on line %d

View file

@ -251,14 +251,10 @@ try {
print $e->getMessage() . "\n"; print $e->getMessage() . "\n";
} }
/* This isn't because the xml namespace isn't there and we can't create it */ /* There used to be a 29 here that tested DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace').
print "29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace')\n"; * In libxml2 version 2.12 or prior this didn't work because the xml namespace isn't there and you can't create it without
try { * a document. Starting from libxml2 version 2.13 it does actually work because the XML namespace is statically defined.
$element = new DomElement('xml:valid', '', 'http://www.w3.org/XML/1998/namespace'); * The behaviour from version 2.13 is actually the desired behaviour anyway. */
print "valid\n";
} catch (Exception $e) {
print $e->getMessage() . "\n";
}
/* the qualifiedName or its prefix is "xmlns" and the namespaceURI is /* the qualifiedName or its prefix is "xmlns" and the namespaceURI is
@ -378,8 +374,6 @@ Namespace Error
Namespace Error Namespace Error
28 DOMDocument::createElementNS('http://www.w3.org/XML/1998/namespace', 'xml:valid') 28 DOMDocument::createElementNS('http://www.w3.org/XML/1998/namespace', 'xml:valid')
valid valid
29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace')
Namespace Error
30 DOMDocument::createElementNS('http://wrong.namespaceURI.com', 'xmlns:valid') 30 DOMDocument::createElementNS('http://wrong.namespaceURI.com', 'xmlns:valid')
Namespace Error Namespace Error
31 DOMElement::__construct('xmlns:valid', '', 'http://wrong.namespaceURI.com') 31 DOMElement::__construct('xmlns:valid', '', 'http://wrong.namespaceURI.com')

View file

@ -419,8 +419,10 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
static xmlOutputBufferPtr static xmlOutputBufferPtr
php_libxml_output_buffer_create_filename(const char *URI, php_libxml_output_buffer_create_filename(const char *URI,
xmlCharEncodingHandlerPtr encoder, xmlCharEncodingHandlerPtr encoder,
int compression ATTRIBUTE_UNUSED) int compression)
{ {
ZEND_IGNORE_VALUE(compression);
xmlOutputBufferPtr ret; xmlOutputBufferPtr ret;
xmlURIPtr puri; xmlURIPtr puri;
void *context = NULL; void *context = NULL;

View file

@ -167,6 +167,7 @@ ZEND_TSRMLS_CACHE_EXTERN()
* Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */ * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */
static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt) static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt)
{ {
PHP_LIBXML_IGNORE_DEPRECATIONS_START
ctxt->loadsubset = 0; ctxt->loadsubset = 0;
ctxt->validate = 0; ctxt->validate = 0;
ctxt->pedantic = 0; ctxt->pedantic = 0;
@ -174,6 +175,7 @@ static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserC
ctxt->linenumbers = 0; ctxt->linenumbers = 0;
ctxt->keepBlanks = 1; ctxt->keepBlanks = 1;
ctxt->options = 0; ctxt->options = 0;
PHP_LIBXML_IGNORE_DEPRECATIONS_END
} }
#else /* HAVE_LIBXML */ #else /* HAVE_LIBXML */

View file

@ -20,7 +20,7 @@ var_dump($sxe->asXML("$uri.out%00foo"));
--EXPECTF-- --EXPECTF--
Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d
Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%%r00%rfoo" in %s on line %d Warning: simplexml_load_file(): I/O warning : failed to load %s
bool(false) bool(false)
Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d

View file

@ -3374,7 +3374,6 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
} else { } else {
smart_str prefix = {0}; smart_str prefix = {0};
int num = ++SOAP_GLOBAL(cur_uniq_ns); int num = ++SOAP_GLOBAL(cur_uniq_ns);
xmlChar *enc_ns;
while (1) { while (1) {
smart_str_appendl(&prefix, "ns", 2); smart_str_appendl(&prefix, "ns", 2);
@ -3388,9 +3387,15 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
num = ++SOAP_GLOBAL(cur_uniq_ns); num = ++SOAP_GLOBAL(cur_uniq_ns);
} }
enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns)); /* Starting with libxml 2.13, we don't have to do this workaround anymore, otherwise we get double-encoded
* entities. See libxml2 commit f506ec66547ef9bac97a2bf306d368ecea8c0c9e. */
#if LIBXML_VERSION < 21300
xmlChar *enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns));
xmlns = xmlNewNs(node->doc->children, enc_ns, BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : "")); xmlns = xmlNewNs(node->doc->children, enc_ns, BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
xmlFree(enc_ns); xmlFree(enc_ns);
#else
xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
#endif
smart_str_free(&prefix); smart_str_free(&prefix);
} }
} }

View file

@ -92,13 +92,16 @@ xmlDocPtr soap_xmlParseFile(const char *filename)
bool old; bool old;
php_libxml_sanitize_parse_ctxt_options(ctxt); php_libxml_sanitize_parse_ctxt_options(ctxt);
/* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */
PHP_LIBXML_IGNORE_DEPRECATIONS_START
ctxt->keepBlanks = 0; ctxt->keepBlanks = 0;
ctxt->options |= XML_PARSE_HUGE;
PHP_LIBXML_IGNORE_DEPRECATIONS_END
ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
ctxt->sax->comment = soap_Comment; ctxt->sax->comment = soap_Comment;
ctxt->sax->warning = NULL; ctxt->sax->warning = NULL;
ctxt->sax->error = NULL; ctxt->sax->error = NULL;
/*ctxt->sax->fatalError = NULL;*/ /*ctxt->sax->fatalError = NULL;*/
ctxt->options |= XML_PARSE_HUGE;
old = php_libxml_disable_entity_loader(1); old = php_libxml_disable_entity_loader(1);
xmlParseDocument(ctxt); xmlParseDocument(ctxt);
php_libxml_disable_entity_loader(old); php_libxml_disable_entity_loader(old);
@ -146,7 +149,10 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
ctxt->sax->warning = NULL; ctxt->sax->warning = NULL;
ctxt->sax->error = NULL; ctxt->sax->error = NULL;
/*ctxt->sax->fatalError = NULL;*/ /*ctxt->sax->fatalError = NULL;*/
/* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */
PHP_LIBXML_IGNORE_DEPRECATIONS_START
ctxt->options |= XML_PARSE_HUGE; ctxt->options |= XML_PARSE_HUGE;
PHP_LIBXML_IGNORE_DEPRECATIONS_END
old = php_libxml_disable_entity_loader(1); old = php_libxml_disable_entity_loader(1);
xmlParseDocument(ctxt); xmlParseDocument(ctxt);
php_libxml_disable_entity_loader(old); php_libxml_disable_entity_loader(old);

View file

@ -25,8 +25,8 @@ try {
} }
echo "ok\n"; echo "ok\n";
?> ?>
--EXPECT-- --EXPECTF--
SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load external entity "httpx://" SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load %s
ok ok
I don't get executed either. I don't get executed either.

View file

@ -714,8 +714,7 @@ XML_GetCurrentByteCount(XML_Parser parser)
{ {
/* WARNING: this is identical to ByteIndex; it should probably /* WARNING: this is identical to ByteIndex; it should probably
* be different */ * be different */
return parser->parser->input->consumed + return XML_GetCurrentByteIndex(parser);
(parser->parser->input->cur - parser->parser->input->base);
} }
PHP_XML_API const XML_Char *XML_ExpatVersion(void) PHP_XML_API const XML_Char *XML_ExpatVersion(void)

View file

@ -1004,7 +1004,8 @@ static void php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS, int force_string)
} }
output_bytes = xmlTextWriterFlush(ptr); output_bytes = xmlTextWriterFlush(ptr);
if (buffer) { if (buffer) {
RETVAL_STRING((char *) buffer->content); const xmlChar *content = xmlBufferContent(buffer);
RETVAL_STRING((const char *) content);
if (empty) { if (empty) {
xmlBufferEmpty(buffer); xmlBufferEmpty(buffer);
} }