From: Colin O'Dell Date: Mon, 21 Oct 2019 18:49:08 +0000 (-0400) Subject: Accept null lengths for substr functions() X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e6d3146bdc943ead15209c4070a51a35abc99167;p=php Accept null lengths for substr functions() If a null $length is passed to any of these functions, behave as if no parameter was passed: - substr() - substr_count() - substr_compare() - iconv_substr() --- diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index 9fab00a746..9e4c52d252 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -2028,13 +2028,14 @@ PHP_FUNCTION(iconv_substr) size_t charset_len = 0; zend_string *str; zend_long offset, length = 0; + zend_bool len_is_null = 1; php_iconv_err_t err; smart_str retval = {0}; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|ls", - &str, &offset, &length, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l!s", + &str, &offset, &length, &len_is_null, &charset, &charset_len) == FAILURE) { return; } @@ -2044,7 +2045,7 @@ PHP_FUNCTION(iconv_substr) RETURN_FALSE; } - if (ZEND_NUM_ARGS() < 3) { + if (len_is_null) { length = ZSTR_LEN(str); } diff --git a/ext/iconv/iconv.stub.php b/ext/iconv/iconv.stub.php index dfa2593f0c..965c4a7e96 100644 --- a/ext/iconv/iconv.stub.php +++ b/ext/iconv/iconv.stub.php @@ -4,7 +4,7 @@ function iconv_strlen(string $str, string $charset = UNKNOWN) {} /** @return string|false */ -function iconv_substr(string $str, int $offset, int $length = UNKNOWN, string $charset = UNKNOWN) {} +function iconv_substr(string $str, int $offset, ?int $length = null, string $charset = UNKNOWN) {} /** @return int|false */ function iconv_strpos(string $haystack, string $needle, int $offset = 0, string $charset = UNKNOWN) {} diff --git a/ext/iconv/iconv_arginfo.h b/ext/iconv/iconv_arginfo.h index 1587b0fadb..462b1cfbe4 100644 --- a/ext/iconv/iconv_arginfo.h +++ b/ext/iconv/iconv_arginfo.h @@ -8,7 +8,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_ARG_TYPE_INFO(0, charset, IS_STRING, 0) ZEND_END_ARG_INFO() diff --git a/ext/iconv/tests/iconv_substr.phpt b/ext/iconv/tests/iconv_substr.phpt index 6ca545b2ea..2a514e6f61 100644 --- a/ext/iconv/tests/iconv_substr.phpt +++ b/ext/iconv/tests/iconv_substr.phpt @@ -34,6 +34,7 @@ foo(" bar("This is a test", 100000); bar("This is a test", 0, 100000); bar("This is a test", -3); +bar("This is a test", -3, null); bar("This is a test", 0, -9); bar("This is a test", 0, -100000); bar("This is a test", -9, -100000); @@ -50,6 +51,8 @@ string(14) "This is a test" string(14) "This is a test" string(3) "est" string(3) "est" +string(3) "est" +string(3) "est" string(5) "This " string(5) "This " bool(false) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index c85547f7a9..78bc728d2a 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -474,7 +474,7 @@ function strrchr(string $haystack, string $needle) {} function chunk_split(string $str, int $chunklen = 76, string $ending = "\r\n"): string {} /** @return string|false */ -function substr(string $str, int $start, int $length = UNKNOWN) {} +function substr(string $str, int $start, ?int $length = null) {} /** * @param mixed $str @@ -566,7 +566,7 @@ function localeconv(): array {} function strnatcasecmp(string $s1, string $s2): int {} /** @return int|false */ -function substr_count(string $haystack, string $needle, int $offset = 0, int $length = UNKNOWN) {} +function substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null) {} function str_pad(string $input, int $pad_length, string $pad_string = " ", int $pad_type = STR_PAD_RIGHT): string {} @@ -591,7 +591,7 @@ function str_split(string $str, int $split_length = 1): array {} function strpbrk(string $haystack, string $char_list) {} /** @return int|false */ -function substr_compare(string $main_str, string $str, int $offset, int $length = UNKNOWN, bool $case_insensitivity = false) {} +function substr_compare(string $main_str, string $str, int $offset, ?int $length = null, bool $case_insensitivity = false) {} function utf8_encode(string $data): string {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 8abd27b8a8..56b0f116c4 100755 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -630,7 +630,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_substr, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_substr_replace, 0, 0, 3) @@ -751,7 +751,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_substr_count, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, haystack, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_str_pad, 0, 2, IS_STRING, 0) @@ -798,7 +798,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_substr_compare, 0, 0, 3) ZEND_ARG_TYPE_INFO(0, main_str, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1) ZEND_ARG_TYPE_INFO(0, case_insensitivity, _IS_BOOL, 0) ZEND_END_ARG_INFO() diff --git a/ext/standard/string.c b/ext/standard/string.c index b2be54e2cd..639e443c06 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -2184,13 +2184,13 @@ PHP_FUNCTION(substr) { zend_string *str; zend_long l = 0, f; - int argc = ZEND_NUM_ARGS(); + zend_bool len_is_null = 1; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(str) Z_PARAM_LONG(f) Z_PARAM_OPTIONAL - Z_PARAM_LONG(l) + Z_PARAM_LONG_OR_NULL(l, len_is_null) ZEND_PARSE_PARAMETERS_END(); if (f > (zend_long)ZSTR_LEN(str)) { @@ -2204,7 +2204,7 @@ PHP_FUNCTION(substr) } else { f = (zend_long)ZSTR_LEN(str) + f; } - if (argc > 2) { + if (!len_is_null) { if (l < 0) { /* if "length" position is negative, set it to the length * needed to stop that many chars from the end of the string @@ -2224,7 +2224,7 @@ PHP_FUNCTION(substr) } else { goto truncate_len; } - } else if (argc > 2) { + } else if (!len_is_null) { if (l < 0) { /* if "length" position is negative, set it to the length * needed to stop that many chars from the end of the string @@ -5553,7 +5553,7 @@ PHP_FUNCTION(substr_count) { char *haystack, *needle; zend_long offset = 0, length = 0; - int ac = ZEND_NUM_ARGS(); + zend_bool length_is_null = 1; zend_long count = 0; size_t haystack_len, needle_len; const char *p, *endp; @@ -5564,7 +5564,7 @@ PHP_FUNCTION(substr_count) Z_PARAM_STRING(needle, needle_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(offset) - Z_PARAM_LONG(length) + Z_PARAM_LONG_OR_NULL(length, length_is_null) ZEND_PARSE_PARAMETERS_END(); if (needle_len == 0) { @@ -5584,7 +5584,7 @@ PHP_FUNCTION(substr_count) } p += offset; - if (ac == 4) { + if (!length_is_null) { if (length < 0) { length += (haystack_len - offset); diff --git a/ext/standard/tests/strings/substr.phpt b/ext/standard/tests/strings/substr.phpt index 18e7cd1781..fe687ed1ae 100644 Binary files a/ext/standard/tests/strings/substr.phpt and b/ext/standard/tests/strings/substr.phpt differ diff --git a/ext/standard/tests/strings/substr_compare.phpt b/ext/standard/tests/strings/substr_compare.phpt index b0a8a5b0eb..6a0bca4336 100644 --- a/ext/standard/tests/strings/substr_compare.phpt +++ b/ext/standard/tests/strings/substr_compare.phpt @@ -4,6 +4,7 @@ substr_compare() --EXPECTF-- bool(true) +bool(true) int(0) int(0) int(0) diff --git a/ext/standard/tests/strings/substr_count_basic.phpt b/ext/standard/tests/strings/substr_count_basic.phpt index 385689e697..a6d715ed67 100644 --- a/ext/standard/tests/strings/substr_count_basic.phpt +++ b/ext/standard/tests/strings/substr_count_basic.phpt @@ -24,8 +24,10 @@ var_dump(substr_count($a, "bca")); $a = str_repeat("abcacbabca", 100); var_dump(substr_count($a, "bca")); var_dump(substr_count($a, "bca", 200)); +var_dump(substr_count($a, "bca", 200, null)); var_dump(substr_count($a, "bca", 200, 50)); var_dump(substr_count($a, "bca", -200)); +var_dump(substr_count($a, "bca", -200, null)); var_dump(substr_count($a, "bca", -200, 50)); var_dump(substr_count($a, "bca", -200, -50)); @@ -42,8 +44,10 @@ int(0) int(100) int(200) int(160) +int(160) int(10) int(40) +int(40) int(10) int(30) Done