Skip to content

Commit 81e59c6

Browse files
committed
Improve handling of XML options
Mark boolean options as such Warn on invalid types Stubs info Closes phpGH-10675
1 parent 524391b commit 81e59c6

10 files changed

+138
-50
lines changed

Diff for: Zend/Optimizer/zend_func_infos.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ static const func_info_t func_infos[] = {
688688
F1("var_export", MAY_BE_STRING|MAY_BE_NULL),
689689
F1("serialize", MAY_BE_STRING),
690690
F1("xml_error_string", MAY_BE_STRING|MAY_BE_NULL),
691-
F1("xml_parser_get_option", MAY_BE_STRING|MAY_BE_LONG),
691+
F1("xml_parser_get_option", MAY_BE_STRING|MAY_BE_LONG|MAY_BE_BOOL),
692692
FN("zip_open", MAY_BE_RESOURCE|MAY_BE_LONG|MAY_BE_FALSE),
693693
FN("zip_read", MAY_BE_RESOURCE|MAY_BE_FALSE),
694694
F1("ob_gzhandler", MAY_BE_STRING|MAY_BE_FALSE),

Diff for: ext/xml/tests/bug72714.phpt

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
Bug #72714 (_xml_startElementHandler() segmentation fault)
33
--EXTENSIONS--
44
xml
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE < 8) die('skip this test is for 64bit builds only');
8+
?>
59
--FILE--
610
<?php
711
function startElement($parser, $name, $attribs) {
@@ -26,6 +30,6 @@ parse(3015809298423721);
2630
parse(20);
2731
?>
2832
--EXPECTF--
29-
Warning: xml_parser_set_option(): tagstart ignored, because it is out of range in %s on line %d
33+
Warning: xml_parser_set_option(): Argument #3 ($value) must be between 0 and 2147483647 for option XML_OPTION_SKIP_TAGSTART in %s on line %d
3034
string(9) "NS1:TOTAL"
3135
string(0) ""

Diff for: ext/xml/tests/xml_parser_get_option_variation3.phpt

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,26 @@ $parser = xml_parser_create();
88
echo "defaults:\n";
99
var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_TAGSTART));
1010
var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_WHITE));
11+
var_dump(xml_parser_get_option($parser, XML_OPTION_CASE_FOLDING));
1112
echo "setting:\n";
1213
var_dump(xml_parser_set_option($parser, XML_OPTION_SKIP_TAGSTART, 7));
1314
var_dump(xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1));
15+
var_dump(xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false));
1416
echo "getting:\n";
1517
var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_TAGSTART));
1618
var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_WHITE));
19+
var_dump(xml_parser_get_option($parser, XML_OPTION_CASE_FOLDING));
1720
?>
1821
--EXPECT--
1922
defaults:
2023
int(0)
21-
int(0)
24+
bool(false)
25+
bool(true)
2226
setting:
2327
bool(true)
2428
bool(true)
29+
bool(true)
2530
getting:
2631
int(7)
27-
int(1)
32+
bool(true)
33+
bool(false)

Diff for: ext/xml/tests/xml_parser_set_option_basic.phpt

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ echo "Done\n";
3232
?>
3333
--EXPECT--
3434
Simple testcase for xml_parser_get_option() function
35-
int(1)
35+
bool(true)
3636
string(5) "UTF-8"
3737
bool(true)
3838
bool(true)
39-
int(1)
39+
bool(true)
4040
string(10) "ISO-8859-1"
4141
bool(true)
4242
bool(true)
43-
int(0)
43+
bool(false)
4444
string(5) "UTF-8"
4545
bool(true)
4646
string(8) "US-ASCII"

Diff for: ext/xml/tests/xml_parser_set_option_errors.phpt

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
--TEST--
2+
xml_parser_set_option(): Setting options to invalid values
3+
--EXTENSIONS--
4+
xml
5+
--FILE--
6+
<?php
7+
8+
$xmlParser = xml_parser_create();
9+
10+
echo "Case folding\n";
11+
try {
12+
xml_parser_set_option($xmlParser, XML_OPTION_CASE_FOLDING, []);
13+
} catch (ValueError $exception) {
14+
echo $exception->getMessage() . "\n";
15+
}
16+
try {
17+
xml_parser_set_option($xmlParser, XML_OPTION_CASE_FOLDING, new stdClass());
18+
} catch (TypeError $exception) {
19+
echo $exception->getMessage() . "\n";
20+
}
21+
22+
echo "Skip Whitespace\n";
23+
try {
24+
xml_parser_set_option($xmlParser, XML_OPTION_SKIP_WHITE, []);
25+
} catch (ValueError $exception) {
26+
echo $exception->getMessage() . "\n";
27+
}
28+
try {
29+
xml_parser_set_option($xmlParser, XML_OPTION_SKIP_WHITE, new stdClass());
30+
} catch (TypeError $exception) {
31+
echo $exception->getMessage() . "\n";
32+
}
33+
34+
echo "Tag Start\n";
35+
xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, -5);
36+
37+
xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, []);
38+
39+
xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, new stdClass());
40+
41+
echo "Encodings\n";
42+
try {
43+
xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, 'Invalid Encoding');
44+
} catch (ValueError $exception) {
45+
echo $exception->getMessage() . "\n";
46+
}
47+
try {
48+
xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, []);
49+
} catch (ValueError $exception) {
50+
echo $exception->getMessage() . "\n";
51+
}
52+
try {
53+
xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, new stdClass());
54+
} catch (Error $exception) {
55+
echo $exception::class, ': ', $exception->getMessage() . "\n";
56+
}
57+
58+
?>
59+
--EXPECTF--
60+
Case folding
61+
62+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d
63+
64+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d
65+
Skip Whitespace
66+
67+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d
68+
69+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d
70+
Tag Start
71+
72+
Warning: xml_parser_set_option(): Argument #3 ($value) must be between 0 and 2147483647 for option XML_OPTION_SKIP_TAGSTART in %s on line %d
73+
74+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d
75+
76+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d
77+
78+
Warning: Object of class stdClass could not be converted to int in %s on line %d
79+
Encodings
80+
xml_parser_set_option(): Argument #3 ($value) is not a supported target encoding
81+
82+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d
83+
84+
Warning: Array to string conversion in %s on line %d
85+
xml_parser_set_option(): Argument #3 ($value) is not a supported target encoding
86+
87+
Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d
88+
Error: Object of class stdClass could not be converted to string

Diff for: ext/xml/tests/xml_parser_set_option_variation5.phpt renamed to ext/xml/tests/xml_parser_set_option_nonexistent_option.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
xml_parser_set_option() - Test invalid parameter
2+
xml_parser_set_option(): Non-existent option
33
--EXTENSIONS--
44
xml
55
--FILE--

Diff for: ext/xml/tests/xml_parser_set_option_variation4.phpt

-24
This file was deleted.

Diff for: ext/xml/xml.c

+28-14
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ ZEND_GET_MODULE(xml)
132132

133133
#define XML_MAXLEVEL 255 /* XXX this should be dynamic */
134134

135-
#define SKIP_TAGSTART(str) ((str) + (parser->toffset > (int)strlen(str) ? strlen(str) : parser->toffset))
135+
#define SKIP_TAGSTART(str) ((str) + (parser->toffset > strlen(str) ? strlen(str) : parser->toffset))
136136

137137
static zend_class_entry *xml_parser_ce;
138138
static zend_object_handlers xml_parser_object_handlers;
@@ -1392,37 +1392,51 @@ PHP_FUNCTION(xml_parser_free)
13921392
PHP_FUNCTION(xml_parser_set_option)
13931393
{
13941394
xml_parser *parser;
1395-
zval *pind, *val;
1395+
zval *pind;
13961396
zend_long opt;
1397+
zval *value;
13971398

1398-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &pind, xml_parser_ce, &opt, &val) == FAILURE) {
1399+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &pind, xml_parser_ce, &opt, &value) == FAILURE) {
13991400
RETURN_THROWS();
14001401
}
14011402

1403+
if (Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE &&
1404+
Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING) {
1405+
php_error_docref(NULL, E_WARNING,
1406+
"Argument #3 ($value) must be of type string|int|bool, %s given", zend_zval_type_name(value));
1407+
}
1408+
14021409
parser = Z_XMLPARSER_P(pind);
14031410
switch (opt) {
1411+
/* Boolean option */
14041412
case PHP_XML_OPTION_CASE_FOLDING:
1405-
parser->case_folding = zval_get_long(val);
1413+
parser->case_folding = zend_is_true(value);
1414+
break;
1415+
/* Boolean option */
1416+
case PHP_XML_OPTION_SKIP_WHITE:
1417+
parser->skipwhite = zend_is_true(value);
14061418
break;
1419+
/* Integer option */
14071420
case PHP_XML_OPTION_SKIP_TAGSTART:
1408-
parser->toffset = zval_get_long(val);
1421+
/* The tag start offset is stored in an int */
1422+
/* TODO Improve handling of values? */
1423+
parser->toffset = zval_get_long(value);
14091424
if (parser->toffset < 0) {
1410-
php_error_docref(NULL, E_WARNING, "tagstart ignored, because it is out of range");
1411-
parser->toffset = 0;
14121425
/* TODO Promote to ValueError in PHP 9.0 */
1426+
php_error_docref(NULL, E_WARNING, "Argument #3 ($value) must be between 0 and %d"
1427+
" for option XML_OPTION_SKIP_TAGSTART", INT_MAX);
1428+
parser->toffset = 0;
14131429
RETURN_FALSE;
14141430
}
14151431
break;
1416-
case PHP_XML_OPTION_SKIP_WHITE:
1417-
parser->skipwhite = zval_get_long(val);
1418-
break;
1432+
/* String option */
14191433
case PHP_XML_OPTION_TARGET_ENCODING: {
14201434
const xml_encoding *enc;
1421-
if (!try_convert_to_string(val)) {
1435+
if (!try_convert_to_string(value)) {
14221436
RETURN_THROWS();
14231437
}
14241438

1425-
enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(val));
1439+
enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(value));
14261440
if (enc == NULL) {
14271441
zend_argument_value_error(3, "is not a supported target encoding");
14281442
RETURN_THROWS();
@@ -1455,13 +1469,13 @@ PHP_FUNCTION(xml_parser_get_option)
14551469
parser = Z_XMLPARSER_P(pind);
14561470
switch (opt) {
14571471
case PHP_XML_OPTION_CASE_FOLDING:
1458-
RETURN_LONG(parser->case_folding);
1472+
RETURN_BOOL(parser->case_folding);
14591473
break;
14601474
case PHP_XML_OPTION_SKIP_TAGSTART:
14611475
RETURN_LONG(parser->toffset);
14621476
break;
14631477
case PHP_XML_OPTION_SKIP_WHITE:
1464-
RETURN_LONG(parser->skipwhite);
1478+
RETURN_BOOL(parser->skipwhite);
14651479
break;
14661480
case PHP_XML_OPTION_TARGET_ENCODING:
14671481
RETURN_STRING((char *)parser->target_encoding);

Diff for: ext/xml/xml.stub.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,11 @@ function xml_get_current_byte_index(XMLParser $parser): int {}
197197

198198
function xml_parser_free(XMLParser $parser): bool {}
199199

200-
/** @param string|int $value */
200+
/** @param string|int|bool $value */
201201
function xml_parser_set_option(XMLParser $parser, int $option, $value): bool {}
202202

203203
/** @refcount 1 */
204-
function xml_parser_get_option(XMLParser $parser, int $option): string|int {}
204+
function xml_parser_get_option(XMLParser $parser, int $option): string|int|bool {}
205205

206206
/**
207207
* @strict-properties

Diff for: ext/xml/xml_arginfo.h

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)