]> granicus.if.org Git - php/commitdiff
Accept null lengths for substr functions()
authorColin O'Dell <colinodell@gmail.com>
Mon, 21 Oct 2019 18:49:08 +0000 (14:49 -0400)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 22 Oct 2019 10:09:04 +0000 (12:09 +0200)
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()

ext/iconv/iconv.c
ext/iconv/iconv.stub.php
ext/iconv/iconv_arginfo.h
ext/iconv/tests/iconv_substr.phpt
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/string.c
ext/standard/tests/strings/substr.phpt
ext/standard/tests/strings/substr_compare.phpt
ext/standard/tests/strings/substr_count_basic.phpt

index 9fab00a7464f8c236b7818686692e0472013bb42..9e4c52d25208e8a0d2c2d0c62d644b1acd982f41 100644 (file)
@@ -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);
        }
 
index dfa2593f0c1a29c28b86ce9b4edc26aeb063600c..965c4a7e9615522511094d80c56ae1f08a19f20b 100644 (file)
@@ -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) {}
index 1587b0fadb35cb5e87c3f6c87d46dd8cf90abdd6..462b1cfbe4891782d632b7eb9c1667a9218057a3 100644 (file)
@@ -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()
 
index 6ca545b2ea19cd1bcce9db2aecfb002002d17d11..2a514e6f61ce7571b2d0536306e68584a9834410 100644 (file)
@@ -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)
index c85547f7a9aee25ec1289de46f51bd2ad86c90e6..78bc728d2af9b350f90b9244dac40c315c5593bf 100755 (executable)
@@ -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 {}
 
index 8abd27b8a8c794b8e42bc13c9dc0743b238a8743..56b0f116c494c010351a93b9243491ff3f2c805a 100755 (executable)
@@ -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()
 
index b2be54e2cd3eac0ec7244de8bd846e11011044a3..639e443c066ce7b21e88dea265114c15432f5f5d 100644 (file)
@@ -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);
index 18e7cd17812091d5599a726af903ccd065fa448d..fe687ed1aefd77cdeb64da58baf93a0c70e77850 100644 (file)
Binary files a/ext/standard/tests/strings/substr.phpt and b/ext/standard/tests/strings/substr.phpt differ
index b0a8a5b0eb509ece493087d9d52e68a3e7db8ee7..6a0bca43369ddc9e570582df3f1df0a4937d54f1 100644 (file)
@@ -4,6 +4,7 @@ substr_compare()
 <?php
 
 var_dump(substr_compare("abcde", "df", -2) < 0);
+var_dump(substr_compare("abcde", "df", -2, null) < 0);
 var_dump(substr_compare("abcde", "bc", 1, 2));
 var_dump(substr_compare("abcde", "bcg", 1, 2));
 var_dump(substr_compare("abcde", "BC", 1, 2, true));
@@ -25,6 +26,7 @@ echo "Done\n";
 ?>
 --EXPECTF--
 bool(true)
+bool(true)
 int(0)
 int(0)
 int(0)
index 385689e69705081191c670213f213139cf1a4957..a6d715ed6739498326f4916260a00320b1490db1 100644 (file)
@@ -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