diff --git a/NEWS b/NEWS index 37fe3f07666..d98b69766f1 100644 --- a/NEWS +++ b/NEWS @@ -327,7 +327,7 @@ PHP NEWS . Add XMLReader::fromStream(). (nielsdos) - XMLWriter: - . Add XMLWriter::toStream(). (nielsdos) + . Add XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory(). (nielsdos) - XSL: . Implement request #64137 (XSLTProcessor::setParameter() should allow both diff --git a/UPGRADING b/UPGRADING index 9223dba06bd..00bdd36c7e1 100644 --- a/UPGRADING +++ b/UPGRADING @@ -633,7 +633,7 @@ PHP 8.4 UPGRADE NOTES RFC: https://wiki.php.net/rfc/xmlreader_writer_streams - XMLWriter: - . Added XMLWriter::toStream(). + . Added XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory(). RFC: https://wiki.php.net/rfc/xmlreader_writer_streams - XSL: diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c index 45ba59f32de..9a2e2d8003b 100644 --- a/ext/xmlwriter/php_xmlwriter.c +++ b/ext/xmlwriter/php_xmlwriter.c @@ -179,6 +179,18 @@ static char *_xmlwriter_get_valid_file_path(char *source, char *resolved_path, i } /* }}} */ +static void xml_writer_create_static(INTERNAL_FUNCTION_PARAMETERS, xmlTextWriterPtr writer, xmlBufferPtr output) +{ + if (object_init_with_constructor(return_value, Z_CE_P(ZEND_THIS), 0, NULL, NULL) == SUCCESS) { + ze_xmlwriter_object *intern = Z_XMLWRITER_P(return_value); + intern->ptr = writer; + intern->output = output; + } else { + xmlBufferFree(output); + xmlFreeTextWriter(writer); + } +} + static const zend_module_dep xmlwriter_deps[] = { ZEND_MOD_REQUIRED("libxml") ZEND_MOD_END @@ -836,6 +848,36 @@ PHP_FUNCTION(xmlwriter_open_uri) } /* }}} */ +PHP_METHOD(XMLWriter, toUri) +{ + char *source; + size_t source_len; + char resolved_path[MAXPATHLEN + 1]; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH(source, source_len) + ZEND_PARSE_PARAMETERS_END(); + + if (source_len == 0) { + zend_argument_value_error(1, "cannot be empty"); + RETURN_THROWS(); + } + + const char *valid_file = _xmlwriter_get_valid_file_path(source, resolved_path, MAXPATHLEN); + if (!valid_file) { + zend_argument_value_error(1, "must resolve to a valid file path"); + RETURN_THROWS(); + } + + xmlTextWriterPtr writer = xmlNewTextWriterFilename(valid_file, 0); + if (!writer) { + zend_throw_error(NULL, "Could not construct libxml writer"); + RETURN_THROWS(); + } + + xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, NULL); +} + /* {{{ Create new xmlwriter using memory for string output */ PHP_FUNCTION(xmlwriter_open_memory) { @@ -881,6 +923,23 @@ PHP_FUNCTION(xmlwriter_open_memory) } /* }}} */ +PHP_METHOD(XMLWriter, toMemory) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + xmlBufferPtr buffer = xmlBufferCreate(); + xmlTextWriterPtr writer = xmlNewTextWriterMemory(buffer, 0); + + /* No need for an explicit buffer check as this will fail on a NULL buffer. */ + if (!writer) { + xmlBufferFree(buffer); + zend_throw_error(NULL, "Could not construct libxml writer"); + RETURN_THROWS(); + } + + xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, buffer); +} + static int xml_writer_stream_write(void *context, const char *buffer, int len) { zend_resource *resource = context; @@ -927,14 +986,8 @@ PHP_METHOD(XMLWriter, toStream) RETURN_THROWS(); } - if (object_init_with_constructor(return_value, Z_CE_P(ZEND_THIS), 0, NULL, NULL) == SUCCESS) { - ze_xmlwriter_object *intern = Z_XMLWRITER_P(return_value); - intern->ptr = writer; - /* output_buffer is owned by writer, and so writer will clean that up for us. */ - intern->output = NULL; - } else { - xmlFreeTextWriter(writer); - } + /* output_buffer is owned by writer, and so writer will clean that up for us. */ + xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, NULL); } /* {{{ php_xmlwriter_flush */ diff --git a/ext/xmlwriter/php_xmlwriter.stub.php b/ext/xmlwriter/php_xmlwriter.stub.php index 753478d586a..44b509aa1dd 100644 --- a/ext/xmlwriter/php_xmlwriter.stub.php +++ b/ext/xmlwriter/php_xmlwriter.stub.php @@ -95,6 +95,8 @@ class XMLWriter */ public function openUri(string $uri): bool {} + public static function toUri(string $uri): static {} + /** * @tentative-return-type * @alias xmlwriter_open_memory @@ -102,6 +104,8 @@ class XMLWriter */ public function openMemory(): bool {} + public static function toMemory(): static {} + /** @param resource $stream */ public static function toStream($stream): static {} diff --git a/ext/xmlwriter/php_xmlwriter_arginfo.h b/ext/xmlwriter/php_xmlwriter_arginfo.h index bafd8fbdd04..fda02c49f6f 100644 --- a/ext/xmlwriter/php_xmlwriter_arginfo.h +++ b/ext/xmlwriter/php_xmlwriter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c65d664c3c84742dfda4cb3e2682036ec4fe893a */ + * Stub hash: fcc388de55bd6d21530d16f6a9ab5f0eb307c1ff */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_xmlwriter_open_uri, 0, 1, XMLWriter, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) @@ -179,9 +179,16 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_XMLWriter_openUr ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLWriter_toUri, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_XMLWriter_openMemory, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLWriter_toMemory, 0, 0, IS_STATIC, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLWriter_toStream, 0, 1, IS_STATIC, 0) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO() @@ -373,6 +380,8 @@ ZEND_FUNCTION(xmlwriter_end_dtd_entity); ZEND_FUNCTION(xmlwriter_write_dtd_entity); ZEND_FUNCTION(xmlwriter_output_memory); ZEND_FUNCTION(xmlwriter_flush); +ZEND_METHOD(XMLWriter, toUri); +ZEND_METHOD(XMLWriter, toMemory); ZEND_METHOD(XMLWriter, toStream); static const zend_function_entry ext_functions[] = { @@ -423,7 +432,9 @@ static const zend_function_entry ext_functions[] = { static const zend_function_entry class_XMLWriter_methods[] = { ZEND_RAW_FENTRY("openUri", zif_xmlwriter_open_uri, arginfo_class_XMLWriter_openUri, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(XMLWriter, toUri, arginfo_class_XMLWriter_toUri, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_RAW_FENTRY("openMemory", zif_xmlwriter_open_memory, arginfo_class_XMLWriter_openMemory, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(XMLWriter, toMemory, arginfo_class_XMLWriter_toMemory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(XMLWriter, toStream, arginfo_class_XMLWriter_toStream, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_RAW_FENTRY("setIndent", zif_xmlwriter_set_indent, arginfo_class_XMLWriter_setIndent, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("setIndentString", zif_xmlwriter_set_indent_string, arginfo_class_XMLWriter_setIndentString, ZEND_ACC_PUBLIC, NULL, NULL) diff --git a/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor.phpt b/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor.phpt new file mode 100644 index 00000000000..5088168af8f --- /dev/null +++ b/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor.phpt @@ -0,0 +1,30 @@ +--TEST-- +XMLWriter::toMemory() - custom constructor +--EXTENSIONS-- +xmlwriter +--FILE-- +myField = 1234; + echo "hello world\n"; + } +} + +$writer = CustomXMLWriter::toMemory(); +var_dump($writer); +$writer->startElement("root"); +$writer->endElement(); +echo $writer->outputMemory(); + +?> +--EXPECTF-- +hello world +object(CustomXMLWriter)#%d (1) { + ["myField"]=> + int(1234) +} + diff --git a/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor_error.phpt b/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor_error.phpt new file mode 100644 index 00000000000..3a87d963c9d --- /dev/null +++ b/ext/xmlwriter/tests/xmlwriter_toMemory_custom_constructor_error.phpt @@ -0,0 +1,22 @@ +--TEST-- +XMLWriter::toMemory() - custom constructor error +--EXTENSIONS-- +xmlwriter +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +nope diff --git a/ext/xmlwriter/tests/xmlwriter_toMemory_normal_usage.phpt b/ext/xmlwriter/tests/xmlwriter_toMemory_normal_usage.phpt new file mode 100644 index 00000000000..ef3f4127020 --- /dev/null +++ b/ext/xmlwriter/tests/xmlwriter_toMemory_normal_usage.phpt @@ -0,0 +1,17 @@ +--TEST-- +XMLWriter::toMemory() - normal usage +--EXTENSIONS-- +xmlwriter +--FILE-- +startElement("root"); +$writer->writeAttribute("align", "left"); +$writer->writeComment("hello"); +$writer->endElement(); +echo $writer->outputMemory(); + +?> +--EXPECT-- +