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 086ea4c

Browse files
committed
Add simplexml_load_stream()
1 parent 6091820 commit 086ea4c

7 files changed

+219
-36
lines changed

‎ext/simplexml/simplexml.c

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,17 +2183,37 @@ sxe_object_new(zend_class_entry *ce)
21832183
}
21842184
/* }}} */
21852185

2186+
static void sxe_create_obj_from_doc(zval *return_value, xmlDocPtr docp, zend_class_entry *ce, zend_string *ns, bool isprefix)
2187+
{
2188+
if (!docp) {
2189+
RETURN_FALSE;
2190+
}
2191+
2192+
zend_function *fptr_count;
2193+
if (!ce) {
2194+
ce = ce_SimpleXMLElement;
2195+
fptr_count = NULL;
2196+
} else {
2197+
fptr_count = php_sxe_find_fptr_count(ce);
2198+
}
2199+
php_sxe_object *sxe = php_sxe_object_new(ce, fptr_count);
2200+
sxe->iter.nsprefix = ZSTR_LEN(ns) ? zend_string_copy(ns) : NULL;
2201+
sxe->iter.isprefix = isprefix;
2202+
php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2203+
php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
2204+
2205+
RETURN_OBJ(&sxe->zo);
2206+
}
2207+
21862208
/* {{{ Load a filename and return a simplexml_element object to allow for processing */
21872209
PHP_FUNCTION(simplexml_load_file)
21882210
{
2189-
php_sxe_object *sxe;
21902211
char *filename;
21912212
size_t filename_len;
21922213
xmlDocPtr docp;
21932214
zend_string *ns = zend_empty_string;
21942215
zend_long options = 0;
21952216
zend_class_entry *ce= ce_SimpleXMLElement;
2196-
zend_function *fptr_count;
21972217
bool isprefix = 0;
21982218

21992219
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|C!lSb", &filename, &filename_len, &ce, &options, &ns, &isprefix) == FAILURE) {
@@ -2209,37 +2229,70 @@ PHP_FUNCTION(simplexml_load_file)
22092229
docp = xmlReadFile(filename, NULL, (int)options);
22102230
PHP_LIBXML_RESTORE_GLOBALS(read_file);
22112231

2212-
if (!docp) {
2213-
RETURN_FALSE;
2232+
sxe_create_obj_from_doc(return_value, docp, ce, ns, isprefix);
2233+
}
2234+
/* }}} */
2235+
2236+
static int sxe_stream_read(void *context, char *buffer, int len)
2237+
{
2238+
zend_resource *resource = context;
2239+
if (EXPECTED(resource->ptr)) {
2240+
php_stream *stream = resource->ptr;
2241+
return php_stream_read(stream, buffer, len);
22142242
}
2243+
return -1;
2244+
}
22152245

2216-
if (!ce) {
2217-
ce = ce_SimpleXMLElement;
2218-
fptr_count = NULL;
2219-
} else {
2220-
fptr_count = php_sxe_find_fptr_count(ce);
2246+
PHP_FUNCTION(simplexml_load_stream)
2247+
{
2248+
zval *stream_zv;
2249+
php_stream *stream;
2250+
xmlDocPtr docp;
2251+
zend_string *ns = zend_empty_string;
2252+
zend_long options = 0;
2253+
zend_class_entry *ce = ce_SimpleXMLElement;
2254+
bool isprefix = 0;
2255+
const char *encoding = NULL;
2256+
const char *document_uri = NULL;
2257+
size_t encoding_len, document_uri_len;
2258+
2259+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|p!p!C!lSb",
2260+
&stream_zv, &encoding, &encoding_len, &document_uri, &document_uri_len, &ce, &options, &ns, &isprefix) == FAILURE) {
2261+
RETURN_THROWS();
22212262
}
2222-
sxe = php_sxe_object_new(ce, fptr_count);
2223-
sxe->iter.nsprefix = ZSTR_LEN(ns) ? zend_string_copy(ns) : NULL;
2224-
sxe->iter.isprefix = isprefix;
2225-
php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2226-
php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
22272263

2228-
RETURN_OBJ(&sxe->zo);
2264+
php_stream_from_res(stream, Z_RES_P(stream_zv));
2265+
2266+
if (!php_libxml_is_valid_encoding(encoding)) {
2267+
zend_argument_value_error(2, "must be a valid character encoding");
2268+
RETURN_THROWS();
2269+
}
2270+
2271+
if (ZEND_LONG_EXCEEDS_INT(options)) {
2272+
zend_argument_value_error(5, "is too large");
2273+
RETURN_THROWS();
2274+
}
2275+
2276+
if (encoding) {
2277+
options |= XML_PARSE_IGNORE_ENC;
2278+
}
2279+
2280+
PHP_LIBXML_SANITIZE_GLOBALS(read_file);
2281+
docp = xmlReadIO(sxe_stream_read, NULL, stream->res, document_uri, encoding, (int) options);
2282+
PHP_LIBXML_RESTORE_GLOBALS(read_file);
2283+
2284+
sxe_create_obj_from_doc(return_value, docp, ce, ns, isprefix);
22292285
}
2230-
/* }}} */
22312286

22322287
/* {{{ Load a string and return a simplexml_element object to allow for processing */
22332288
PHP_FUNCTION(simplexml_load_string)
22342289
{
2235-
php_sxe_object *sxe;
22362290
char *data;
22372291
size_t data_len;
22382292
xmlDocPtr docp;
22392293
zend_string *ns = zend_empty_string;
22402294
zend_long options = 0;
22412295
zend_class_entry *ce= ce_SimpleXMLElement;
2242-
zend_function *fptr_count;
22432296
bool isprefix = 0;
22442297

22452298
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!lSb", &data, &data_len, &ce, &options, &ns, &isprefix) == FAILURE) {
@@ -2263,23 +2316,7 @@ PHP_FUNCTION(simplexml_load_string)
22632316
docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
22642317
PHP_LIBXML_RESTORE_GLOBALS(read_memory);
22652318

2266-
if (!docp) {
2267-
RETURN_FALSE;
2268-
}
2269-
2270-
if (!ce) {
2271-
ce = ce_SimpleXMLElement;
2272-
fptr_count = NULL;
2273-
} else {
2274-
fptr_count = php_sxe_find_fptr_count(ce);
2275-
}
2276-
sxe = php_sxe_object_new(ce, fptr_count);
2277-
sxe->iter.nsprefix = ZSTR_LEN(ns) ? zend_string_copy(ns) : NULL;
2278-
sxe->iter.isprefix = isprefix;
2279-
php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp);
2280-
php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL);
2281-
2282-
RETURN_OBJ(&sxe->zo);
2319+
sxe_create_obj_from_doc(return_value, docp, ce, ns, isprefix);
22832320
}
22842321
/* }}} */
22852322

‎ext/simplexml/simplexml.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
function simplexml_load_file(string $filename, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false): SimpleXMLElement|false {}
66

7+
/** @param resource $stream */
8+
function simplexml_load_stream($stream, ?string $encoding = null, ?string $document_uri = null, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false): SimpleXMLElement|false {}
9+
710
function simplexml_load_string(string $data, ?string $class_name = SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false): SimpleXMLElement|false {}
811

912
function simplexml_import_dom(object $node, ?string $class_name = SimpleXMLElement::class): ?SimpleXMLElement {}

‎ext/simplexml/simplexml_arginfo.h

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
simplexml_load_stream() - from broken stream
3+
--EXTENSIONS--
4+
simplexml
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+
var_dump($count);
14+
if ($this->first) {
15+
$this->first = false;
16+
return "<root><child/>";
17+
}
18+
return false;
19+
}
20+
21+
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path) {
22+
return true;
23+
}
24+
25+
public function stream_close(): void {
26+
}
27+
28+
public function stream_eof(): bool {
29+
return !$this->first;
30+
}
31+
}
32+
33+
stream_wrapper_register("foo", MyStream::class);
34+
35+
$tmp = fopen("foo://", "r");
36+
$sxe = simplexml_load_stream($tmp);
37+
fclose($tmp);
38+
39+
var_dump($sxe);
40+
41+
?>
42+
--EXPECTF--
43+
int(8192)
44+
int(8192)
45+
%A
46+
Warning: simplexml_load_stream(): Entity: line 1: parser error : Premature end of data in tag root line 1 in %s on line %d
47+
48+
Warning: simplexml_load_stream(): <root><child/> in %s on line %d
49+
50+
Warning: simplexml_load_stream(): ^ in %s on line %d
51+
bool(false)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
simplexml_load_stream() - errors
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
8+
$tmp = fopen("php://memory", "w+");
9+
try {
10+
simplexml_load_stream($tmp, "doesnotexist");
11+
} catch (ValueError $e) {
12+
echo $e->getMessage(), "\n";
13+
}
14+
fclose($tmp);
15+
16+
?>
17+
--EXPECT--
18+
simplexml_load_stream(): Argument #2 ($encoding) must be a valid character encoding
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
simplexml_load_stream() - from memory stream
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
8+
$tmp = fopen("php://memory", "w+");
9+
fwrite($tmp, "<root><child1/><child2/></root>");
10+
rewind($tmp);
11+
$sxe1 = simplexml_load_stream($tmp);
12+
rewind($tmp);
13+
$sxe2 = simplexml_load_stream($tmp, document_uri: 'http://example.com');
14+
fclose($tmp);
15+
16+
var_dump($sxe1, $sxe2);
17+
18+
?>
19+
--EXPECTF--
20+
object(SimpleXMLElement)#%d (2) {
21+
["child1"]=>
22+
object(SimpleXMLElement)#%d (0) {
23+
}
24+
["child2"]=>
25+
object(SimpleXMLElement)#%d (0) {
26+
}
27+
}
28+
object(SimpleXMLElement)#%d (2) {
29+
["child1"]=>
30+
object(SimpleXMLElement)#%d (0) {
31+
}
32+
["child2"]=>
33+
object(SimpleXMLElement)#%d (0) {
34+
}
35+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
simplexml_load_stream() - from memory stream with encoding
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
8+
$tmp = fopen("php://memory", "w+");
9+
fwrite($tmp, '<?xml version="1.0" encoding="Shift-JIS"?><root>ééé</root>');
10+
rewind($tmp);
11+
$sxe1 = simplexml_load_stream($tmp, encoding: 'UTF-8');
12+
rewind($tmp);
13+
$sxe2 = simplexml_load_stream($tmp);
14+
fclose($tmp);
15+
16+
var_dump($sxe1, $sxe2);
17+
18+
?>
19+
--EXPECTF--
20+
object(SimpleXMLElement)#%d (1) {
21+
[0]=>
22+
string(6) "ééé"
23+
}
24+
object(SimpleXMLElement)#%d (1) {
25+
[0]=>
26+
string(18) "テゥテゥテゥ"
27+
}

0 commit comments

Comments
(0)

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