Improve ini number handling with INI_SCANNER_TYPED

Fixes GH-11010
Closes GH-11014
This commit is contained in:
Ilija Tovilo 2023-04-04 16:14:24 +02:00
parent 471dcf6e40
commit 86ffde3c38
No known key found for this signature in database
GPG Key ID: A4F5D403F118200A
7 changed files with 65 additions and 34 deletions

3
NEWS
View File

@ -170,6 +170,9 @@ PHP NEWS
. Fix GH-10239 (proc_close after proc_get_status always returns -1). (nielsdos)
. Improve the warning message for unpack() in case not enough values were
provided. (nielsdos)
. Fix GH-11010 (parse_ini_string() now preserves formatting of unquoted
strings starting with numbers when the INI_SCANNER_TYPED flag is
specified). (ilutov)
- Streams:
. Fixed bug #51056: blocking fread() will block even if data is available.

View File

@ -43,6 +43,7 @@ int ini_parse(void);
#endif
#define ZEND_SYSTEM_INI CG(ini_parser_unbuffered_errors)
#define INI_ZVAL_IS_NUMBER 1
static int get_int_val(zval *op) {
switch (Z_TYPE_P(op)) {
@ -92,8 +93,12 @@ static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
break;
}
str_len = sprintf(str_result, "%d", i_result);
ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI));
if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) {
str_len = sprintf(str_result, "%d", i_result);
ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI));
} else {
ZVAL_LONG(result, i_result);
}
}
/* }}} */
@ -276,6 +281,41 @@ static void zval_ini_dtor(zval *zv)
}
/* }}} */
static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len)
{
uint8_t type;
int overflow;
zend_long lval;
double dval;
if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) {
if (type == IS_LONG) {
ZVAL_LONG(retval, lval);
return SUCCESS;
} else if (type == IS_DOUBLE && !overflow) {
ZVAL_DOUBLE(retval, dval);
return SUCCESS;
}
}
return FAILURE;
}
static void normalize_value(zval *zv)
{
if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) {
return;
}
if (Z_EXTRA_P(zv) == INI_ZVAL_IS_NUMBER && Z_TYPE_P(zv) == IS_STRING) {
zval number_rv;
if (convert_to_number(&number_rv, Z_STRVAL_P(zv), Z_STRLEN_P(zv)) == SUCCESS) {
zval_ptr_dtor(zv);
ZVAL_COPY_VALUE(zv, &number_rv);
}
}
}
%}
%expect 0
@ -351,7 +391,7 @@ section_string_or_value:
;
string_or_value:
expr { $$ = $1; }
expr { $$ = $1; normalize_value(&$$); }
| BOOL_TRUE { $$ = $1; }
| BOOL_FALSE { $$ = $1; }
| NULL_NULL { $$ = $1; }
@ -412,7 +452,11 @@ constant_literal:
constant_string:
TC_CONSTANT { zend_ini_get_constant(&$$, &$1); }
| TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
| TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
| TC_NUMBER {
$$ = $1;
Z_EXTRA($$) = INI_ZVAL_IS_NUMBER;
/*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/
}
| TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
| TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
;

View File

@ -151,26 +151,6 @@ ZEND_API zend_ini_scanner_globals ini_scanner_globals;
return type; \
}
static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len)
{
uint8_t type;
int overflow;
zend_long lval;
double dval;
if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) {
if (type == IS_LONG) {
ZVAL_LONG(retval, lval);
return SUCCESS;
} else if (type == IS_DOUBLE && !overflow) {
ZVAL_DOUBLE(retval, dval);
return SUCCESS;
}
}
return FAILURE;
}
static void zend_ini_copy_typed_value(zval *retval, const int type, const char *str, int len)
{
switch (type) {
@ -183,11 +163,6 @@ static void zend_ini_copy_typed_value(zval *retval, const int type, const char *
ZVAL_NULL(retval);
break;
case TC_NUMBER:
if (convert_to_number(retval, str, len) == SUCCESS) {
break;
}
ZEND_FALLTHROUGH;
default:
zend_ini_copy_value(retval, str, len);
}

View File

@ -21,7 +21,7 @@ array(%d) {
["foo"]=>
array(%d) {
[123]=>
string(%d) "24575"
int(24575)
[456]=>
int(123)
}

View File

@ -13,7 +13,7 @@ var_dump(parse_ini_string($ini, true, INI_SCANNER_TYPED));
--EXPECT--
array(2) {
["val1"]=>
string(1) "2"
int(2)
["val2"]=>
string(1) "2"
int(2)
}

View File

@ -21,7 +21,7 @@ array(1) {
["foo"]=>
array(1) {
["bar"]=>
string(1) "1"
int(1)
}
}
array(1) {
@ -42,6 +42,6 @@ array(1) {
["foo"]=>
array(1) {
["bar"]=>
string(2) "42"
int(42)
}
}

View File

@ -0,0 +1,9 @@
--TEST--
GH-11010: Preserve ini formatting of concatenated numbers
--FILE--
<?php
$result = parse_ini_string('variable = -00 20 30', false, INI_SCANNER_TYPED);
var_dump($result['variable']);
?>
--EXPECT--
string(9) "-00 20 30"