From d7b37c01b2d1a53810d1efe3941c04ce28784bfe Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Wed, 27 May 2026 17:14:54 +0530 Subject: [PATCH 1/3] ext/spl: Fix default argument handling for named parameters in SplFileObject::fgetcsv() --- ext/spl/spl_directory.c | 4 +++- ext/spl/tests/gh22156.phpt | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 ext/spl/tests/gh22156.phpt diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 95fc5e25be4b..f8c417fad73c 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2268,7 +2268,9 @@ PHP_METHOD(SplFileObject, fgetcsv) zend_argument_value_error(1, "must be a single character"); RETURN_THROWS(); } - delimiter = delim[0]; + if(delim[0] != ',') { + delimiter = delim[0]; + } } if (enclo) { if (e_len != 1) { diff --git a/ext/spl/tests/gh22156.phpt b/ext/spl/tests/gh22156.phpt new file mode 100644 index 000000000000..a1a5e9762be1 --- /dev/null +++ b/ext/spl/tests/gh22156.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug GH-22156 SplFileObject::fgetcsv() with named escape parameter +--FILE-- +fwrite("foo;bar;baz"); +$file->seek(0); + +$file->setCsvControl(';', "\n", "\\"); + +while (!$file->eof()) { + $line = $file->fgetcsv(escape: '\\'); + var_dump($line); +} + +?> +--EXPECT-- +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [2]=> + string(3) "baz" +} + From 2952d887c0f0e08ddd9ff54d9b0cf74dad693c5f Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Wed, 27 May 2026 18:28:50 +0530 Subject: [PATCH 2/3] ext/spl: Fix default argument handling for named parameters in SplFileObject::fgetcsv() --- ext/spl/spl_directory.c | 6 +-- ext/spl/spl_directory.stub.php | 2 +- ext/spl/spl_directory_arginfo.h | 8 +-- ext/spl/tests/gh22156.phpt | 86 ++++++++++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index f8c417fad73c..a4769c2188be 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2257,7 +2257,7 @@ PHP_METHOD(SplFileObject, fgetcsv) size_t d_len = 0, e_len = 0; zend_string *escape_str = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ssS", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!S!", &delim, &d_len, &enclo, &e_len, &escape_str) == FAILURE) { RETURN_THROWS(); } @@ -2268,9 +2268,7 @@ PHP_METHOD(SplFileObject, fgetcsv) zend_argument_value_error(1, "must be a single character"); RETURN_THROWS(); } - if(delim[0] != ',') { - delimiter = delim[0]; - } + delimiter = delim[0]; } if (enclo) { if (e_len != 1) { diff --git a/ext/spl/spl_directory.stub.php b/ext/spl/spl_directory.stub.php index 6194a8617b43..d3eca11eb5c1 100644 --- a/ext/spl/spl_directory.stub.php +++ b/ext/spl/spl_directory.stub.php @@ -245,7 +245,7 @@ public function fgets(): string {} public function fread(int $length): string|false {} /** @tentative-return-type */ - public function fgetcsv(string $separator = ",", string $enclosure = "\"", string $escape = "\\"): array|false {} + public function fgetcsv(?string $separator = null, ?string $enclosure = null, ?string $escape = null): array|false {} /** @tentative-return-type */ public function fputcsv(array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n"): int|false {} diff --git a/ext/spl/spl_directory_arginfo.h b/ext/spl/spl_directory_arginfo.h index 16860be558d7..be7ec5b7fbfe 100644 --- a/ext/spl/spl_directory_arginfo.h +++ b/ext/spl/spl_directory_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit spl_directory.stub.php instead. - * Stub hash: 802429d736404c2d66601f640942c827b6e6e94b */ + * Stub hash: b6fe5a5f28ca0a93739d41cfe630abfefa960d26 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFileInfo___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -178,9 +178,9 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SplFileObject_fr ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SplFileObject_fgetcsv, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, separator, IS_STRING, 0, "\",\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enclosure, IS_STRING, 0, "\"\\\"\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, escape, IS_STRING, 0, "\"\\\\\"") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, separator, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enclosure, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, escape, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SplFileObject_fputcsv, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) diff --git a/ext/spl/tests/gh22156.phpt b/ext/spl/tests/gh22156.phpt index a1a5e9762be1..95c16efec1d2 100644 --- a/ext/spl/tests/gh22156.phpt +++ b/ext/spl/tests/gh22156.phpt @@ -3,6 +3,7 @@ Bug GH-22156 SplFileObject::fgetcsv() with named escape parameter --FILE-- fwrite("foo;bar;baz"); @@ -15,8 +16,48 @@ while (!$file->eof()) { var_dump($line); } +echo "Test 2:\n"; +$f = new SplFileObject('php://memory', 'rw+'); +$f->setCsvControl(';', "\n", "\\"); +$f->fwrite("a,b;c\n"); +$f->seek(0); +var_dump($f->fgetcsv(',', '"', '\\')); + +echo "Test 3:\n"; +$f = new SplFileObject('php://memory', 'rw+'); +$f->setCsvControl(',', "'", "\\"); +$f->fwrite("a,'b,c'\n"); +$f->seek(0); +var_dump($f->fgetcsv(escape: '\\')); + +echo "Test 4:\n"; +$f = new SplFileObject('php://memory', 'rw+'); +$f->setCsvControl(',', "'"); +$f->fwrite("a,'b\\'c'\n"); +$f->seek(0); +var_dump($f->fgetcsv(escape: '\\')); + +echo "Test 5:\n"; + +$rm = new ReflectionMethod(SplFileObject::class, 'fgetcsv'); +foreach ($rm->getParameters() as $p) { + var_dump( + $p->getName(), + $p->allowsNull(), + $p->getDefaultValue() + ); +} + +echo "Test 6:\n"; +$f = new SplFileObject('php://memory', 'rw+'); +$f->setCsvControl(',', '"'); +$f->fwrite("a,b\n"); +$f->seek(0); +var_dump($f->fgetcsv()); + ?> ---EXPECT-- +--EXPECTF-- +Test 1: array(3) { [0]=> string(3) "foo" @@ -25,4 +66,47 @@ array(3) { [2]=> string(3) "baz" } +Test 2: +array(2) { + [0]=> + string(1) "a" + [1]=> + string(3) "b;c" +} +Test 3: +array(2) { + [0]=> + string(1) "a" + [1]=> + string(3) "b,c" +} +Test 4: + +Deprecated: SplFileObject::setCsvControl(): the $escape parameter must be provided as its default value will change in %s on line %d +array(2) { + [0]=> + string(1) "a" + [1]=> + string(4) "b\'c" +} +Test 5: +string(9) "separator" +bool(true) +NULL +string(9) "enclosure" +bool(true) +NULL +string(6) "escape" +bool(true) +NULL +Test 6: + +Deprecated: SplFileObject::setCsvControl(): the $escape parameter must be provided as its default value will change in %s on line %d +Deprecated: SplFileObject::fgetcsv(): the $escape parameter must be provided, as its default value will change, either explicitly or via SplFileObject::setCsvControl() in %s on line %d +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" +} \ No newline at end of file From 2d305061cc8546deb1db825ee8a743aa03d71d42 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Wed, 27 May 2026 19:13:33 +0530 Subject: [PATCH 3/3] ext/spl: Fix default argument handling for named parameters in SplFileObject::fgetcsv() --- ext/spl/tests/gh22156.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/spl/tests/gh22156.phpt b/ext/spl/tests/gh22156.phpt index 95c16efec1d2..e23ace69a984 100644 --- a/ext/spl/tests/gh22156.phpt +++ b/ext/spl/tests/gh22156.phpt @@ -109,4 +109,4 @@ array(2) { string(1) "a" [1]=> string(1) "b" -} \ No newline at end of file +}