diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 95fc5e25be4b..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(); } 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 new file mode 100644 index 000000000000..e23ace69a984 --- /dev/null +++ b/ext/spl/tests/gh22156.phpt @@ -0,0 +1,112 @@ +--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); +} + +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()); + +?> +--EXPECTF-- +Test 1: +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [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" +}