Skip to content

Commit c24b8fe

Browse files
committed
[RFC] Implement XMLWriter::toUri() and XMLWriter::toMemory()
1 parent acf2762 commit c24b8fe

8 files changed

+148
-11
lines changed

NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ PHP NEWS
327327
. Add XMLReader::fromStream(). (nielsdos)
328328

329329
- XMLWriter:
330-
. Add XMLWriter::toStream(). (nielsdos)
330+
. Add XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory(). (nielsdos)
331331

332332
- XSL:
333333
. Implement request #64137 (XSLTProcessor::setParameter() should allow both

UPGRADING

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ PHP 8.4 UPGRADE NOTES
633633
RFC: https://wiki.php.net/rfc/xmlreader_writer_streams
634634

635635
- XMLWriter:
636-
. Added XMLWriter::toStream().
636+
. Added XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory().
637637
RFC: https://wiki.php.net/rfc/xmlreader_writer_streams
638638

639639
- XSL:

ext/xmlwriter/php_xmlwriter.c

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@ static char *_xmlwriter_get_valid_file_path(char *source, char *resolved_path, i
179179
}
180180
/* }}} */
181181

182+
static void xml_writer_create_static(INTERNAL_FUNCTION_PARAMETERS, xmlTextWriterPtr writer, xmlBufferPtr output)
183+
{
184+
if (object_init_with_constructor(return_value, Z_CE_P(ZEND_THIS), 0, NULL, NULL) == SUCCESS) {
185+
ze_xmlwriter_object *intern = Z_XMLWRITER_P(return_value);
186+
intern->ptr = writer;
187+
intern->output = output;
188+
} else {
189+
xmlBufferFree(output);
190+
xmlFreeTextWriter(writer);
191+
}
192+
}
193+
182194
static const zend_module_dep xmlwriter_deps[] = {
183195
ZEND_MOD_REQUIRED("libxml")
184196
ZEND_MOD_END
@@ -836,6 +848,36 @@ PHP_FUNCTION(xmlwriter_open_uri)
836848
}
837849
/* }}} */
838850

851+
PHP_METHOD(XMLWriter, toUri)
852+
{
853+
char *source;
854+
size_t source_len;
855+
char resolved_path[MAXPATHLEN + 1];
856+
857+
ZEND_PARSE_PARAMETERS_START(1, 1)
858+
Z_PARAM_PATH(source, source_len)
859+
ZEND_PARSE_PARAMETERS_END();
860+
861+
if (source_len == 0) {
862+
zend_argument_value_error(1, "cannot be empty");
863+
RETURN_THROWS();
864+
}
865+
866+
const char *valid_file = _xmlwriter_get_valid_file_path(source, resolved_path, MAXPATHLEN);
867+
if (!valid_file) {
868+
zend_argument_value_error(1, "must resolve to a valid file path");
869+
RETURN_THROWS();
870+
}
871+
872+
xmlTextWriterPtr writer = xmlNewTextWriterFilename(valid_file, 0);
873+
if (!writer) {
874+
zend_throw_error(NULL, "Could not construct libxml writer");
875+
RETURN_THROWS();
876+
}
877+
878+
xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, NULL);
879+
}
880+
839881
/* {{{ Create new xmlwriter using memory for string output */
840882
PHP_FUNCTION(xmlwriter_open_memory)
841883
{
@@ -881,6 +923,23 @@ PHP_FUNCTION(xmlwriter_open_memory)
881923
}
882924
/* }}} */
883925

926+
PHP_METHOD(XMLWriter, toMemory)
927+
{
928+
ZEND_PARSE_PARAMETERS_NONE();
929+
930+
xmlBufferPtr buffer = xmlBufferCreate();
931+
xmlTextWriterPtr writer = xmlNewTextWriterMemory(buffer, 0);
932+
933+
/* No need for an explicit buffer check as this will fail on a NULL buffer. */
934+
if (!writer) {
935+
xmlBufferFree(buffer);
936+
zend_throw_error(NULL, "Could not construct libxml writer");
937+
RETURN_THROWS();
938+
}
939+
940+
xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, buffer);
941+
}
942+
884943
static int xml_writer_stream_write(void *context, const char *buffer, int len)
885944
{
886945
zend_resource *resource = context;
@@ -927,14 +986,8 @@ PHP_METHOD(XMLWriter, toStream)
927986
RETURN_THROWS();
928987
}
929988

930-
if (object_init_with_constructor(return_value, Z_CE_P(ZEND_THIS), 0, NULL, NULL) == SUCCESS) {
931-
ze_xmlwriter_object *intern = Z_XMLWRITER_P(return_value);
932-
intern->ptr = writer;
933-
/* output_buffer is owned by writer, and so writer will clean that up for us. */
934-
intern->output = NULL;
935-
} else {
936-
xmlFreeTextWriter(writer);
937-
}
989+
/* output_buffer is owned by writer, and so writer will clean that up for us. */
990+
xml_writer_create_static(INTERNAL_FUNCTION_PARAM_PASSTHRU, writer, NULL);
938991
}
939992

940993
/* {{{ php_xmlwriter_flush */

ext/xmlwriter/php_xmlwriter.stub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,17 @@ class XMLWriter
9595
*/
9696
public function openUri(string $uri): bool {}
9797

98+
public static function toUri(string $uri): static {}
99+
98100
/**
99101
* @tentative-return-type
100102
* @alias xmlwriter_open_memory
101103
* @no-verify Behaviour differs from the aliased function
102104
*/
103105
public function openMemory(): bool {}
104106

107+
public static function toMemory(): static {}
108+
105109
/** @param resource $stream */
106110
public static function toStream($stream): static {}
107111

ext/xmlwriter/php_xmlwriter_arginfo.h

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
XMLWriter::toMemory() - custom constructor
3+
--EXTENSIONS--
4+
xmlwriter
5+
--FILE--
6+
<?php
7+
8+
class CustomXMLWriter extends XMLWriter {
9+
public int $myField;
10+
11+
public function __construct() {
12+
$this->myField = 1234;
13+
echo "hello world\n";
14+
}
15+
}
16+
17+
$writer = CustomXMLWriter::toMemory();
18+
var_dump($writer);
19+
$writer->startElement("root");
20+
$writer->endElement();
21+
echo $writer->outputMemory();
22+
23+
?>
24+
--EXPECTF--
25+
hello world
26+
object(CustomXMLWriter)#%d (1) {
27+
["myField"]=>
28+
int(1234)
29+
}
30+
<root/>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
XMLWriter::toMemory() - custom constructor error
3+
--EXTENSIONS--
4+
xmlwriter
5+
--FILE--
6+
<?php
7+
8+
class CustomXMLWriter extends XMLWriter {
9+
public function __construct() {
10+
throw new Error('nope');
11+
}
12+
}
13+
14+
try {
15+
CustomXMLWriter::toMemory();
16+
} catch (Throwable $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
20+
?>
21+
--EXPECT--
22+
nope
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
XMLWriter::toMemory() - normal usage
3+
--EXTENSIONS--
4+
xmlwriter
5+
--FILE--
6+
<?php
7+
8+
$writer = XMLWriter::toMemory();
9+
$writer->startElement("root");
10+
$writer->writeAttribute("align", "left");
11+
$writer->writeComment("hello");
12+
$writer->endElement();
13+
echo $writer->outputMemory();
14+
15+
?>
16+
--EXPECT--
17+
<root align="left"><!--hello--></root>

0 commit comments

Comments
 (0)