Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 584d38c

Browse files
committed
Add XMLDocument::createFromStream()
1 parent d987b6d commit 584d38c

File tree

7 files changed

+206
-59
lines changed

7 files changed

+206
-59
lines changed

‎ext/dom/document.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,17 @@ const char *dom_get_valid_file_path(const char *source, char *resolved_path, int
13451345
}
13461346
/* }}} */
13471347

1348-
xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source, size_t source_len, size_t options, xmlCharEncodingHandlerPtr encoding) /* {{{ */
1348+
static int dom_stream_read(void *context, char *buffer, int len)
1349+
{
1350+
zend_resource *resource = context;
1351+
if (EXPECTED(resource->ptr)) {
1352+
php_stream *stream = resource->ptr;
1353+
return php_stream_read(stream, buffer, len);
1354+
}
1355+
return -1;
1356+
}
1357+
1358+
xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, dom_source_union source, size_t options, xmlCharEncodingHandlerPtr encoding, const char *override_document_uri) /* {{{ */
13491359
{
13501360
xmlDocPtr ret;
13511361
xmlParserCtxtPtr ctxt = NULL;
@@ -1371,16 +1381,18 @@ xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source,
13711381
xmlInitParser();
13721382

13731383
if (mode == DOM_LOAD_FILE) {
1374-
if (CHECK_NULL_PATH(source, source_len)) {
1384+
if (CHECK_NULL_PATH(source.str, source.str_len)) {
13751385
zend_argument_value_error(1, "must not contain any null bytes");
13761386
return NULL;
13771387
}
1378-
const char *file_dest = dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1388+
const char *file_dest = dom_get_valid_file_path(source.str, resolved_path, MAXPATHLEN);
13791389
if (file_dest) {
13801390
ctxt = xmlCreateFileParserCtxt(file_dest);
13811391
}
1392+
} else if (mode == DOM_LOAD_STRING) {
1393+
ctxt = xmlCreateMemoryParserCtxt(source.str, source.str_len);
13821394
} else {
1383-
ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1395+
ctxt = xmlCreateIOParserCtxt(NULL, NULL, dom_stream_read, NULL, source.stream->res, XML_CHAR_ENCODING_NONE);
13841396
}
13851397

13861398
if (ctxt == NULL) {
@@ -1393,7 +1405,7 @@ xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source,
13931405
}
13941406

13951407
/* If loading from memory, we need to set the base directory for the document */
1396-
if (mode !=DOM_LOAD_FILE) {
1408+
if (mode ==DOM_LOAD_STRING) {
13971409
#ifdef HAVE_GETCWD
13981410
directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
13991411
#elif defined(HAVE_GETWD)
@@ -1410,6 +1422,11 @@ xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, const char *source,
14101422
}
14111423
ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
14121424
}
1425+
} else if (override_document_uri) {
1426+
if(ctxt->directory != NULL) {
1427+
xmlFree(ctxt->directory);
1428+
}
1429+
ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) override_document_uri);
14131430
}
14141431

14151432
ctxt->vctxt.error = php_libxml_ctx_error;
@@ -1507,21 +1524,20 @@ static void php_dom_finish_loading_document(zval *this, zval *return_value, xmlD
15071524
RETURN_TRUE;
15081525
}
15091526

1510-
static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode)
1527+
static void dom_legacy_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode)
15111528
{
1512-
char *source;
1513-
size_t source_len;
1529+
dom_source_union source;
15141530
zend_long options = 0;
15151531

1516-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1532+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source.str, &source.str_len, &options) == FAILURE) {
15171533
RETURN_THROWS();
15181534
}
15191535

1520-
if (!source_len) {
1536+
if (!source.str_len) {
15211537
zend_argument_must_not_be_empty_error(1);
15221538
RETURN_THROWS();
15231539
}
1524-
if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1540+
if (ZEND_SIZE_T_INT_OVFL(source.str_len)) {
15251541
php_error_docref(NULL, E_WARNING, "Input string is too long");
15261542
RETURN_FALSE;
15271543
}
@@ -1530,7 +1546,7 @@ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode)
15301546
RETURN_FALSE;
15311547
}
15321548

1533-
xmlDocPtr newdoc = dom_document_parser(ZEND_THIS, mode, source, source_len, options, NULL);
1549+
xmlDocPtr newdoc = dom_document_parser(ZEND_THIS, mode, source, options, NULL, NULL);
15341550
if (newdoc == DOM_DOCUMENT_MALFORMED) {
15351551
newdoc = NULL;
15361552
}
@@ -1542,7 +1558,7 @@ Since: DOM Level 3
15421558
*/
15431559
PHP_METHOD(DOMDocument, load)
15441560
{
1545-
dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1561+
dom_legacy_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
15461562
}
15471563
/* }}} end dom_document_load */
15481564

@@ -1551,7 +1567,7 @@ Since: DOM Level 3
15511567
*/
15521568
PHP_METHOD(DOMDocument, loadXML)
15531569
{
1554-
dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1570+
dom_legacy_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
15551571
}
15561572
/* }}} end dom_document_loadxml */
15571573

‎ext/dom/php_dom.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,22 @@ void dom_set_document_ref_pointers(xmlNodePtr node, php_libxml_ref_obj *document
179179
void dom_set_document_ref_pointers_attr(xmlAttrPtr attr, php_libxml_ref_obj *document);
180180

181181
typedef enum {
182-
DOM_LOAD_STRING = 0,
183-
DOM_LOAD_FILE = 1,
182+
DOM_LOAD_STRING,
183+
DOM_LOAD_FILE,
184+
DOM_LOAD_STREAM,
184185
} dom_load_mode;
185186

187+
typedef union {
188+
struct {
189+
const char *str;
190+
size_t str_len;
191+
};
192+
php_stream *stream;
193+
} dom_source_union;
194+
186195
#define DOM_DOCUMENT_MALFORMED ((xmlDocPtr) -1)
187196

188-
xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, constchar*source, size_t source_len, size_toptions, xmlCharEncodingHandlerPtr encoding);
197+
xmlDocPtr dom_document_parser(zval *id, dom_load_mode mode, dom_source_unionsource, size_t options, xmlCharEncodingHandlerPtr encoding, constchar*override_document_uri);
189198

190199
/* parentnode */
191200
void dom_parent_node_prepend(dom_object *context, zval *nodes, uint32_t nodesc);

‎ext/dom/php_dom.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,9 @@ public static function createEmpty(string $version = "1.0", string $encoding = "
20682068

20692069
public static function createFromFile(string $path, int $options = 0, ?string $overrideEncoding = null): XMLDocument {}
20702070

2071+
/** @param resource $stream */
2072+
public static function createFromStream($stream, ?string $documentURI = null, int $options = 0, ?string $overrideEncoding = null): XMLDocument {}
2073+
20712074
public static function createFromString(string $source, int $options = 0, ?string $overrideEncoding = null): XMLDocument {}
20722075

20732076
/**

‎ext/dom/php_dom_arginfo.h

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Dom\XMLDocument::createFromStream() - from memory
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
$tmp = fopen("php://memory", "r+");
9+
fwrite($tmp, "<root/>");
10+
rewind($tmp);
11+
$dom1 = Dom\XMLDocument::createFromStream($tmp);
12+
rewind($tmp);
13+
$dom2 = Dom\XMLDocument::createFromStream($tmp, "http://example.com");
14+
fclose($tmp);
15+
16+
var_dump($dom1->documentURI);
17+
var_dump($dom2->documentURI);
18+
19+
echo $dom1->saveXml(), "\n";
20+
echo $dom2->saveXml(), "\n";
21+
22+
?>
23+
--EXPECT--
24+
string(11) "about:blank"
25+
string(18) "http://example.com"
26+
<?xml version="1.0" encoding="UTF-8"?>
27+
<root/>
28+
<?xml version="1.0" encoding="UTF-8"?>
29+
<root/>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
Dom\HTMLDocument::createFromStream() - broken stream
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
class MyStream {
9+
public $context;
10+
private bool $first = true;
11+
12+
public function stream_read(int $count): string|false {
13+
if ($this->first) {
14+
$this->first = false;
15+
return "<root><child>";
16+
}
17+
throw new Error("broken");
18+
}
19+
20+
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path) {
21+
return true;
22+
}
23+
24+
public function stream_close(): void {
25+
}
26+
27+
public function stream_eof(): bool {
28+
return !$this->first;
29+
}
30+
}
31+
32+
stream_wrapper_register("foo", MyStream::class);
33+
34+
$tmp = fopen("foo://", "r+");
35+
try {
36+
$dom = Dom\XMLDocument::createFromStream($tmp);
37+
} catch (Error $e) {
38+
echo $e->getMessage(), "\n";
39+
}
40+
fclose($tmp);
41+
42+
?>
43+
--EXPECT--
44+
broken

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /