mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4: Fix #70962: XML_OPTION_SKIP_WHITE strips embedded whitespace
This commit is contained in:
commit
f55d78e817
3 changed files with 103 additions and 57 deletions
4
NEWS
4
NEWS
|
@ -17,6 +17,10 @@ PHP NEWS
|
||||||
- PCRE:
|
- PCRE:
|
||||||
. Fixed bug #81424 (PCRE2 10.35 JIT performance regression). (cmb)
|
. Fixed bug #81424 (PCRE2 10.35 JIT performance regression). (cmb)
|
||||||
|
|
||||||
|
- XML:
|
||||||
|
. Fixed bug #70962 (XML_OPTION_SKIP_WHITE strips embedded whitespace).
|
||||||
|
(Aliaksandr Bystry, cmb)
|
||||||
|
|
||||||
23 Sep 2021, PHP 8.0.11
|
23 Sep 2021, PHP 8.0.11
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
|
|
37
ext/xml/tests/bug70962.phpt
Normal file
37
ext/xml/tests/bug70962.phpt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
--TEST--
|
||||||
|
Bug #70962 (XML_OPTION_SKIP_WHITE strips embedded whitespace)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('xml')) die('skip xml extension not available');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
function parseAndOutput($xml)
|
||||||
|
{
|
||||||
|
$parser = xml_parser_create();
|
||||||
|
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
|
||||||
|
|
||||||
|
xml_parse_into_struct($parser, $xml, $values);
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = "<a><b><d>\n <e></b><![CDATA[ ]]><c>\n \t</c></a>";
|
||||||
|
|
||||||
|
$parsed = parseAndOutput($xml);
|
||||||
|
|
||||||
|
// Check embedded whitespace is not getting skipped.
|
||||||
|
echo $parsed[1]['value'] . "\n";
|
||||||
|
|
||||||
|
// Check XML_OPTION_SKIP_WHITE ignores values of tags containing whitespace characters only.
|
||||||
|
var_dump(isset($parsed[2]['value']));
|
||||||
|
|
||||||
|
// Check XML_OPTION_SKIP_WHITE ignores empty <![CDATA[ ]]> values.
|
||||||
|
var_dump(count($parsed));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
<d>
|
||||||
|
<e>
|
||||||
|
bool(false)
|
||||||
|
int(4)
|
119
ext/xml/xml.c
119
ext/xml/xml.c
|
@ -781,72 +781,77 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
|
||||||
zend_string *decoded_value;
|
zend_string *decoded_value;
|
||||||
|
|
||||||
decoded_value = xml_utf8_decode(s, len, parser->target_encoding);
|
decoded_value = xml_utf8_decode(s, len, parser->target_encoding);
|
||||||
for (i = 0; i < ZSTR_LEN(decoded_value); i++) {
|
if (parser->skipwhite) {
|
||||||
switch (ZSTR_VAL(decoded_value)[i]) {
|
for (i = 0; i < ZSTR_LEN(decoded_value); i++) {
|
||||||
case ' ':
|
switch (ZSTR_VAL(decoded_value)[i]) {
|
||||||
case '\t':
|
case ' ':
|
||||||
case '\n':
|
case '\t':
|
||||||
continue;
|
case '\n':
|
||||||
default:
|
continue;
|
||||||
doprint = 1;
|
default:
|
||||||
|
doprint = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (doprint) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (doprint) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (doprint || (! parser->skipwhite)) {
|
|
||||||
if (parser->lastwasopen) {
|
|
||||||
zval *myval;
|
|
||||||
|
|
||||||
/* check if the current tag already has a value - if yes append to that! */
|
if (parser->lastwasopen) {
|
||||||
if ((myval = zend_hash_str_find(Z_ARRVAL_P(parser->ctag), "value", sizeof("value") - 1))) {
|
zval *myval;
|
||||||
int newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
|
|
||||||
Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
|
|
||||||
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
|
|
||||||
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
|
|
||||||
zend_string_release_ex(decoded_value, 0);
|
|
||||||
} else {
|
|
||||||
add_assoc_str(parser->ctag, "value", decoded_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* check if the current tag already has a value - if yes append to that! */
|
||||||
|
if ((myval = zend_hash_str_find(Z_ARRVAL_P(parser->ctag), "value", sizeof("value") - 1))) {
|
||||||
|
size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
|
||||||
|
Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
|
||||||
|
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
|
||||||
|
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
|
||||||
|
zend_string_release_ex(decoded_value, 0);
|
||||||
} else {
|
} else {
|
||||||
zval tag;
|
if (doprint || (! parser->skipwhite)) {
|
||||||
zval *curtag, *mytype, *myval;
|
add_assoc_str(parser->ctag, "value", decoded_value);
|
||||||
|
} else {
|
||||||
ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL(parser->data), curtag) {
|
zend_string_release_ex(decoded_value, 0);
|
||||||
if ((mytype = zend_hash_str_find(Z_ARRVAL_P(curtag),"type", sizeof("type") - 1))) {
|
|
||||||
if (!strcmp(Z_STRVAL_P(mytype), "cdata")) {
|
|
||||||
if ((myval = zend_hash_str_find(Z_ARRVAL_P(curtag), "value", sizeof("value") - 1))) {
|
|
||||||
int newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
|
|
||||||
Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
|
|
||||||
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
|
|
||||||
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
|
|
||||||
zend_string_release_ex(decoded_value, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} ZEND_HASH_FOREACH_END();
|
|
||||||
|
|
||||||
if (parser->level <= XML_MAXLEVEL && parser->level > 0) {
|
|
||||||
array_init(&tag);
|
|
||||||
|
|
||||||
_xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1]));
|
|
||||||
|
|
||||||
add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1]));
|
|
||||||
add_assoc_str(&tag, "value", decoded_value);
|
|
||||||
add_assoc_string(&tag, "type", "cdata");
|
|
||||||
add_assoc_long(&tag, "level", parser->level);
|
|
||||||
|
|
||||||
zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag);
|
|
||||||
} else if (parser->level == (XML_MAXLEVEL + 1)) {
|
|
||||||
php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
zend_string_release_ex(decoded_value, 0);
|
zval tag;
|
||||||
|
zval *curtag, *mytype, *myval;
|
||||||
|
|
||||||
|
ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL(parser->data), curtag) {
|
||||||
|
if ((mytype = zend_hash_str_find(Z_ARRVAL_P(curtag),"type", sizeof("type") - 1))) {
|
||||||
|
if (!strcmp(Z_STRVAL_P(mytype), "cdata")) {
|
||||||
|
if ((myval = zend_hash_str_find(Z_ARRVAL_P(curtag), "value", sizeof("value") - 1))) {
|
||||||
|
size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
|
||||||
|
Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
|
||||||
|
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
|
||||||
|
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
|
||||||
|
zend_string_release_ex(decoded_value, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
|
||||||
|
if (parser->level <= XML_MAXLEVEL && parser->level > 0 && (doprint || (! parser->skipwhite))) {
|
||||||
|
array_init(&tag);
|
||||||
|
|
||||||
|
_xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1]));
|
||||||
|
|
||||||
|
add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1]));
|
||||||
|
add_assoc_str(&tag, "value", decoded_value);
|
||||||
|
add_assoc_string(&tag, "type", "cdata");
|
||||||
|
add_assoc_long(&tag, "level", parser->level);
|
||||||
|
|
||||||
|
zend_hash_next_index_insert(Z_ARRVAL(parser->data), &tag);
|
||||||
|
} else if (parser->level == (XML_MAXLEVEL + 1)) {
|
||||||
|
php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated");
|
||||||
|
} else {
|
||||||
|
zend_string_release_ex(decoded_value, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue