]> granicus.if.org Git - php/commitdiff
Allow all scalar types in ini_set()
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 11 Feb 2021 09:42:55 +0000 (10:42 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 11 Feb 2021 14:01:16 +0000 (15:01 +0100)
This changes ini_set() to accept all scalar types
(string|int|float|bool|null) for the new value. The idea here is
that while the INI system ultimately works with strings, its value
interpretation is designed to be consistent with PHP's casting rules,
e.g. "1" and "" are interpreted as boolean true and false respectively.

I personally believe that writing ini_set('precision', 10) makes more
sense than ini_set('precision', '10'), and find strict_types to be
unnecessarily pedantic here.

Closes GH-6680.

ext/standard/basic_functions.c
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/tests/general_functions/ini_set_types.phpt [new file with mode: 0644]

index 54c318877152da46006b1060dfe3ef814fd484ea..4084f5d85311093d22015b045e53a7e1634029ef 100755 (executable)
@@ -2086,14 +2086,19 @@ static int php_ini_check_path(char *option_name, size_t option_len, char *new_op
 PHP_FUNCTION(ini_set)
 {
        zend_string *varname;
-       zend_string *new_value;
+       zval *new_value;
        zend_string *val;
 
        ZEND_PARSE_PARAMETERS_START(2, 2)
                Z_PARAM_STR(varname)
-               Z_PARAM_STR(new_value)
+               Z_PARAM_ZVAL(new_value)
        ZEND_PARSE_PARAMETERS_END();
 
+       if (Z_TYPE_P(new_value) > IS_STRING) {
+               zend_argument_type_error(2, "must be of type string|int|float|bool|null");
+               RETURN_THROWS();
+       }
+
        val = zend_ini_get_value(varname);
 
        if (val) {
@@ -2102,6 +2107,9 @@ PHP_FUNCTION(ini_set)
                RETVAL_FALSE;
        }
 
+       zend_string *new_value_tmp_str;
+       zend_string *new_value_str = zval_get_tmp_string(new_value, &new_value_tmp_str);
+
 #define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
        /* open basedir check */
        if (PG(open_basedir)) {
@@ -2111,18 +2119,20 @@ PHP_FUNCTION(ini_set)
                        _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "mail.log") ||
                        _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.library.path") ||
                        _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "vpopmail.directory")) {
-                       if (php_check_open_basedir(ZSTR_VAL(new_value))) {
+                       if (php_check_open_basedir(ZSTR_VAL(new_value_str))) {
                                zval_ptr_dtor_str(return_value);
+                               zend_tmp_string_release(new_value_tmp_str);
                                RETURN_FALSE;
                        }
                }
        }
 #undef _CHECK_PATH
 
-       if (zend_alter_ini_entry_ex(varname, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
+       if (zend_alter_ini_entry_ex(varname, new_value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
                zval_ptr_dtor_str(return_value);
-               RETURN_FALSE;
+               RETVAL_FALSE;
        }
+       zend_tmp_string_release(new_value_tmp_str);
 }
 /* }}} */
 
index 197af9e3e1ca4e21dcb50b955dd717d6dfe5f326..3a7e0de1743f1f235269021e4a959ab21bee2b71 100755 (executable)
@@ -318,7 +318,7 @@ function ini_get(string $option): string|false {}
 
 function ini_get_all(?string $extension = null, bool $details = true): array|false {}
 
-function ini_set(string $option, string $value): string|false {}
+function ini_set(string $option, string|int|float|bool|null $value): string|false {}
 
 /** @alias ini_set */
 function ini_alter(string $option, string $value): string|false {}
index 514a0338d574504132e0c311a60b9e20aead4338..1c7f6b00ecaae4d0520625eccc6464f1989ebbbc 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 4f4ed195a688735d48aeb3b7cd390d8463a07c26 */
+ * Stub hash: e9f39cbc595f0f2cdd84e58d4857f9fdb03ff7b7 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
        ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
@@ -491,10 +491,13 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_ini_set, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
        ZEND_ARG_TYPE_INFO(0, option, IS_STRING, 0)
-       ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
+       ZEND_ARG_TYPE_MASK(0, value, MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_BOOL|MAY_BE_NULL, NULL)
 ZEND_END_ARG_INFO()
 
-#define arginfo_ini_alter arginfo_ini_set
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_ini_alter, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
+       ZEND_ARG_TYPE_INFO(0, option, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
+ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ini_restore, 0, 1, IS_VOID, 0)
        ZEND_ARG_TYPE_INFO(0, option, IS_STRING, 0)
diff --git a/ext/standard/tests/general_functions/ini_set_types.phpt b/ext/standard/tests/general_functions/ini_set_types.phpt
new file mode 100644 (file)
index 0000000..16def38
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+ini_set() accepts non-strings under strict_types
+--FILE--
+<?php
+declare(strict_types=1);
+
+ini_set('docref_root', null);
+var_dump(ini_get('docref_root'));
+ini_set('html_errors', true);
+var_dump(ini_get('html_errors'));
+ini_set('html_errors', false);
+var_dump(ini_get('html_errors'));
+ini_set('precision', 6);
+var_dump(ini_get('precision'));
+
+// There are no float options in always enabled extensions.
+// Just use a random string property, even though it doesn't make sense.
+ini_set('user_agent', 3.14);
+var_dump(ini_get('user_agent'));
+
+try {
+    ini_set('foo', []);
+} catch (TypeError $e) {
+    echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+string(0) ""
+string(1) "1"
+string(0) ""
+string(1) "6"
+string(4) "3.14"
+ini_set(): Argument #2 ($value) must be of type string|int|float|bool|null