Skip to content

Commit e6d3146

Browse files
colinodellnikic
authored andcommitted
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()
1 parent 8ccd58b commit e6d3146

10 files changed

+28
-18
lines changed

ext/iconv/iconv.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -2028,13 +2028,14 @@ PHP_FUNCTION(iconv_substr)
20282028
size_t charset_len = 0;
20292029
zend_string *str;
20302030
zend_long offset, length = 0;
2031+
zend_bool len_is_null = 1;
20312032

20322033
php_iconv_err_t err;
20332034

20342035
smart_str retval = {0};
20352036

2036-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|ls",
2037-
&str, &offset, &length,
2037+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l!s",
2038+
&str, &offset, &length, &len_is_null,
20382039
&charset, &charset_len) == FAILURE) {
20392040
return;
20402041
}
@@ -2044,7 +2045,7 @@ PHP_FUNCTION(iconv_substr)
20442045
RETURN_FALSE;
20452046
}
20462047

2047-
if (ZEND_NUM_ARGS() < 3) {
2048+
if (len_is_null) {
20482049
length = ZSTR_LEN(str);
20492050
}
20502051

ext/iconv/iconv.stub.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
function iconv_strlen(string $str, string $charset = UNKNOWN) {}
55

66
/** @return string|false */
7-
function iconv_substr(string $str, int $offset, int $length = UNKNOWN, string $charset = UNKNOWN) {}
7+
function iconv_substr(string $str, int $offset, ?int $length = null, string $charset = UNKNOWN) {}
88

99
/** @return int|false */
1010
function iconv_strpos(string $haystack, string $needle, int $offset = 0, string $charset = UNKNOWN) {}

ext/iconv/iconv_arginfo.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ZEND_END_ARG_INFO()
88
ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2)
99
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
1010
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
11-
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
11+
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1)
1212
ZEND_ARG_TYPE_INFO(0, charset, IS_STRING, 0)
1313
ZEND_END_ARG_INFO()
1414

ext/iconv/tests/iconv_substr.phpt

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ foo("
3434
bar("This is a test", 100000);
3535
bar("This is a test", 0, 100000);
3636
bar("This is a test", -3);
37+
bar("This is a test", -3, null);
3738
bar("This is a test", 0, -9);
3839
bar("This is a test", 0, -100000);
3940
bar("This is a test", -9, -100000);
@@ -50,6 +51,8 @@ string(14) "This is a test"
5051
string(14) "This is a test"
5152
string(3) "est"
5253
string(3) "est"
54+
string(3) "est"
55+
string(3) "est"
5356
string(5) "This "
5457
string(5) "This "
5558
bool(false)

ext/standard/basic_functions.stub.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ function strrchr(string $haystack, string $needle) {}
474474
function chunk_split(string $str, int $chunklen = 76, string $ending = "\r\n"): string {}
475475

476476
/** @return string|false */
477-
function substr(string $str, int $start, int $length = UNKNOWN) {}
477+
function substr(string $str, int $start, ?int $length = null) {}
478478

479479
/**
480480
* @param mixed $str
@@ -566,7 +566,7 @@ function localeconv(): array {}
566566
function strnatcasecmp(string $s1, string $s2): int {}
567567

568568
/** @return int|false */
569-
function substr_count(string $haystack, string $needle, int $offset = 0, int $length = UNKNOWN) {}
569+
function substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null) {}
570570

571571
function str_pad(string $input, int $pad_length, string $pad_string = " ", int $pad_type = STR_PAD_RIGHT): string {}
572572

@@ -591,7 +591,7 @@ function str_split(string $str, int $split_length = 1): array {}
591591
function strpbrk(string $haystack, string $char_list) {}
592592

593593
/** @return int|false */
594-
function substr_compare(string $main_str, string $str, int $offset, int $length = UNKNOWN, bool $case_insensitivity = false) {}
594+
function substr_compare(string $main_str, string $str, int $offset, ?int $length = null, bool $case_insensitivity = false) {}
595595

596596
function utf8_encode(string $data): string {}
597597

ext/standard/basic_functions_arginfo.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ ZEND_END_ARG_INFO()
630630
ZEND_BEGIN_ARG_INFO_EX(arginfo_substr, 0, 0, 2)
631631
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
632632
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
633-
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
633+
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1)
634634
ZEND_END_ARG_INFO()
635635

636636
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)
751751
ZEND_ARG_TYPE_INFO(0, haystack, IS_STRING, 0)
752752
ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0)
753753
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
754-
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
754+
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1)
755755
ZEND_END_ARG_INFO()
756756

757757
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)
798798
ZEND_ARG_TYPE_INFO(0, main_str, IS_STRING, 0)
799799
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
800800
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
801-
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
801+
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 1)
802802
ZEND_ARG_TYPE_INFO(0, case_insensitivity, _IS_BOOL, 0)
803803
ZEND_END_ARG_INFO()
804804

ext/standard/string.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -2184,13 +2184,13 @@ PHP_FUNCTION(substr)
21842184
{
21852185
zend_string *str;
21862186
zend_long l = 0, f;
2187-
int argc = ZEND_NUM_ARGS();
2187+
zend_bool len_is_null = 1;
21882188

21892189
ZEND_PARSE_PARAMETERS_START(2, 3)
21902190
Z_PARAM_STR(str)
21912191
Z_PARAM_LONG(f)
21922192
Z_PARAM_OPTIONAL
2193-
Z_PARAM_LONG(l)
2193+
Z_PARAM_LONG_OR_NULL(l, len_is_null)
21942194
ZEND_PARSE_PARAMETERS_END();
21952195

21962196
if (f > (zend_long)ZSTR_LEN(str)) {
@@ -2204,7 +2204,7 @@ PHP_FUNCTION(substr)
22042204
} else {
22052205
f = (zend_long)ZSTR_LEN(str) + f;
22062206
}
2207-
if (argc > 2) {
2207+
if (!len_is_null) {
22082208
if (l < 0) {
22092209
/* if "length" position is negative, set it to the length
22102210
* needed to stop that many chars from the end of the string
@@ -2224,7 +2224,7 @@ PHP_FUNCTION(substr)
22242224
} else {
22252225
goto truncate_len;
22262226
}
2227-
} else if (argc > 2) {
2227+
} else if (!len_is_null) {
22282228
if (l < 0) {
22292229
/* if "length" position is negative, set it to the length
22302230
* needed to stop that many chars from the end of the string
@@ -5553,7 +5553,7 @@ PHP_FUNCTION(substr_count)
55535553
{
55545554
char *haystack, *needle;
55555555
zend_long offset = 0, length = 0;
5556-
int ac = ZEND_NUM_ARGS();
5556+
zend_bool length_is_null = 1;
55575557
zend_long count = 0;
55585558
size_t haystack_len, needle_len;
55595559
const char *p, *endp;
@@ -5564,7 +5564,7 @@ PHP_FUNCTION(substr_count)
55645564
Z_PARAM_STRING(needle, needle_len)
55655565
Z_PARAM_OPTIONAL
55665566
Z_PARAM_LONG(offset)
5567-
Z_PARAM_LONG(length)
5567+
Z_PARAM_LONG_OR_NULL(length, length_is_null)
55685568
ZEND_PARSE_PARAMETERS_END();
55695569

55705570
if (needle_len == 0) {
@@ -5584,7 +5584,7 @@ PHP_FUNCTION(substr_count)
55845584
}
55855585
p += offset;
55865586

5587-
if (ac == 4) {
5587+
if (!length_is_null) {
55885588

55895589
if (length < 0) {
55905590
length += (haystack_len - offset);
260 Bytes
Binary file not shown.

ext/standard/tests/strings/substr_compare.phpt

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ substr_compare()
44
<?php
55

66
var_dump(substr_compare("abcde", "df", -2) < 0);
7+
var_dump(substr_compare("abcde", "df", -2, null) < 0);
78
var_dump(substr_compare("abcde", "bc", 1, 2));
89
var_dump(substr_compare("abcde", "bcg", 1, 2));
910
var_dump(substr_compare("abcde", "BC", 1, 2, true));
@@ -25,6 +26,7 @@ echo "Done\n";
2526
?>
2627
--EXPECTF--
2728
bool(true)
29+
bool(true)
2830
int(0)
2931
int(0)
3032
int(0)

ext/standard/tests/strings/substr_count_basic.phpt

+4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ var_dump(substr_count($a, "bca"));
2424
$a = str_repeat("abcacbabca", 100);
2525
var_dump(substr_count($a, "bca"));
2626
var_dump(substr_count($a, "bca", 200));
27+
var_dump(substr_count($a, "bca", 200, null));
2728
var_dump(substr_count($a, "bca", 200, 50));
2829
var_dump(substr_count($a, "bca", -200));
30+
var_dump(substr_count($a, "bca", -200, null));
2931
var_dump(substr_count($a, "bca", -200, 50));
3032
var_dump(substr_count($a, "bca", -200, -50));
3133

@@ -42,8 +44,10 @@ int(0)
4244
int(100)
4345
int(200)
4446
int(160)
47+
int(160)
4548
int(10)
4649
int(40)
50+
int(40)
4751
int(10)
4852
int(30)
4953
Done

0 commit comments

Comments
 (0)