From 402fca265344c86e63fac657bc6a51d50f22a9a7 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 7 Mar 2017 19:02:34 +0200 Subject: [PATCH] Add optional allow_objects param to is_string() When set to true, will allow objects implementing __toString() to pass is_string() validation --- ext/standard/basic_functions.c | 3 +- .../tests/general_functions/is_string.phpt | 39 +++++++++++++++++-- ext/standard/type.c | 22 ++++++++++- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 2079afa38a3fe..17b2cde9780d4 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2547,8 +2547,9 @@ ZEND_BEGIN_ARG_INFO(arginfo_is_float, 0) ZEND_ARG_INFO(0, var) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_is_string, 0) +ZEND_BEGIN_ARG_INFO_EX(arginfo_is_string, 0, 0, 1) ZEND_ARG_INFO(0, var) + ZEND_ARG_INFO(0, allow_objects) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_is_array, 0) diff --git a/ext/standard/tests/general_functions/is_string.phpt b/ext/standard/tests/general_functions/is_string.phpt index b8c82b187bd71..c3c7dcf659ecd 100644 --- a/ext/standard/tests/general_functions/is_string.phpt +++ b/ext/standard/tests/general_functions/is_string.phpt @@ -140,12 +140,31 @@ foreach ($not_strings as $type ) { var_dump( is_string($type) ); } +echo "\n*** Testing is_string() second parameter ***\n"; + +echo "-- objects not allowed; string input --\n"; +var_dump(is_string("string", false)); +echo "-- objects allowed; string input --\n"; +var_dump(is_string("string", true)); + +echo "-- objects not allowed; non-__toString() object input --\n"; +var_dump(is_string(new stdClass(), false)); +echo "-- objects allowed; non-__toString() object input --\n"; +var_dump(is_string(new stdClass(), true)); + +$toStringObject = new class() { public function __toString() { return ''; } }; +echo "-- objects not allowed; __toString() object input --\n"; +var_dump(is_string($toStringObject, false)); +echo "-- objects allowed; __toString() object input --\n"; +var_dump(is_string($toStringObject, true)); + + echo "\n*** Testing error conditions ***\n"; //Zero argument var_dump( is_string() ); //arguments more than expected -var_dump( is_string("string", "test") ); +var_dump( is_string("string", false, "test") ); echo "Done\n"; @@ -293,11 +312,25 @@ bool(false) -- Iteration 45 -- bool(false) +*** Testing is_string() second parameter *** +-- objects not allowed; string input -- +bool(true) +-- objects allowed; string input -- +bool(true) +-- objects not allowed; non-__toString() object input -- +bool(false) +-- objects allowed; non-__toString() object input -- +bool(false) +-- objects not allowed; __toString() object input -- +bool(false) +-- objects allowed; __toString() object input -- +bool(true) + *** Testing error conditions *** -Warning: is_string() expects exactly 1 parameter, 0 given in %s on line %d +Warning: is_string() expects at least 1 parameter, 0 given in %s on line %d bool(false) -Warning: is_string() expects exactly 1 parameter, 2 given in %s on line %d +Warning: is_string() expects at most 2 parameters, 3 given in %s on line %d bool(false) Done diff --git a/ext/standard/type.c b/ext/standard/type.c index a8000504628f2..5b1c0b5f4ad66 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -301,12 +301,30 @@ PHP_FUNCTION(is_float) } /* }}} */ -/* {{{ proto bool is_string(mixed var) +/* {{{ proto bool is_string(mixed var [, bool allow_objects]) Returns true if variable is a string Warning: This function is special-cased by zend_compile.c and so is usually bypassed */ PHP_FUNCTION(is_string) { - php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_STRING); + zval *var; + zend_bool allow_objects = 0; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(var) + Z_PARAM_OPTIONAL Z_PARAM_BOOL(allow_objects) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + switch (Z_TYPE_P(var)) { + case IS_STRING: + RETURN_TRUE; + break; + case IS_OBJECT: + RETURN_BOOL(allow_objects == 1 && Z_OBJCE_P(var)->__tostring); + break; + default: + RETURN_FALSE; + break; + } } /* }}} */