diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 15d792360f827..fc2bf43716765 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2360,11 +2360,13 @@ PHP_METHOD(SplFileObject, fputcsv) size_t d_len = 0, e_len = 0, esc_len = 0; zend_long ret; zval *fields = NULL; + zend_string *eol = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sss", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sssS", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len, &eol) == SUCCESS) { switch(ZEND_NUM_ARGS()) { + case 5: case 4: switch (esc_len) { case 0: @@ -2396,7 +2398,8 @@ PHP_METHOD(SplFileObject, fputcsv) case 0: break; } - ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape); + + ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape, eol); if (ret < 0) { RETURN_FALSE; } diff --git a/ext/spl/spl_directory.stub.php b/ext/spl/spl_directory.stub.php index 80b708a3f462a..ad8ebfdd4ccbd 100644 --- a/ext/spl/spl_directory.stub.php +++ b/ext/spl/spl_directory.stub.php @@ -209,7 +209,7 @@ public function fread(int $length) {} public function fgetcsv(string $separator = ",", string $enclosure = "\"", string $escape = "\\") {} /** @return int|false */ - public function fputcsv(array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\") {} + public function fputcsv(array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n") {} /** @return bool|null */ public function setCsvControl(string $separator = ",", string $enclosure = "\"", string $escape = "\\") {} diff --git a/ext/spl/spl_directory_arginfo.h b/ext/spl/spl_directory_arginfo.h index 252a82fb74553..4db38be0f4808 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 the .stub.php file instead. - * Stub hash: de510a0512057bfaecbac8228107600ed14e2ba5 */ + * Stub hash: 00139cce188b3950e5a7606c70c5848c6280851d */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFileInfo___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -181,6 +181,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFileObject_fputcsv, 0, 0, 1) 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, eol, IS_STRING, 0, "\"\\n\"") ZEND_END_ARG_INFO() #define arginfo_class_SplFileObject_setCsvControl arginfo_class_SplFileObject_fgetcsv diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation16.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation16.phpt new file mode 100644 index 0000000000000..d2bca8572f5b0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation16.phpt @@ -0,0 +1,32 @@ +--TEST-- +SplFileObject::fputcsv() with user provided eol +--FILE-- +fputcsv($record, ',', '"', '', $eol_char); + } + + $file->rewind(); + foreach ($file as $line) { + echo $line; + } + + echo "\n"; +} +?> +--EXPECT-- +aaa,bbb,ccc,dddd||123,456,789||"""aaa""","""bbb"""|| +aaa,bbb,ccc,dddd|123,456,789|"""aaa""","""bbb"""| +aaa,bbb,ccc,dddd\n123,456,789\n"""aaa""","""bbb"""\n +aaa,bbb,ccc,dddd +123,456,789 +"""aaa""","""bbb""" diff --git a/ext/spl/tests/bug68479.phpt b/ext/spl/tests/bug68479.phpt index e749d01120a9e..85a573a3987ce 100644 --- a/ext/spl/tests/bug68479.phpt +++ b/ext/spl/tests/bug68479.phpt @@ -9,7 +9,7 @@ var_dump($params); ?> --EXPECT-- -array(4) { +array(5) { [0]=> object(ReflectionParameter)#2 (1) { ["name"]=> @@ -30,4 +30,9 @@ array(4) { ["name"]=> string(6) "escape" } + [4]=> + object(ReflectionParameter)#6 (1) { + ["name"]=> + string(3) "eol" + } } diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 83000d5b099b7..76525762a2af9 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -867,7 +867,7 @@ function unlink(string $filename, $context = null): bool {} function file_put_contents(string $filename, mixed $data, int $flags = 0, $context = null): int|false {} /** @param resource $stream */ -function fputcsv($stream, array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): int|false {} +function fputcsv($stream, array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n"): int|false {} /** @param resource $stream */ function fgetcsv($stream, ?int $length = null, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): array|false {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index f44a32226736b..a61d6b1b82642 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 97edf8c87780c892984099e52ad1c6c745b919f8 */ + * Stub hash: 23c263defa042155631bec5fcb5282e4cd1e88a7 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -1335,6 +1335,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_fputcsv, 0, 2, MAY_BE_LONG|MAY_B 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, eol, IS_STRING, 0, "\"\\n\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_fgetcsv, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) diff --git a/ext/standard/file.c b/ext/standard/file.c index ff29bf1b1c0a0..5c7830f199c13 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1795,14 +1795,16 @@ PHP_FUNCTION(fputcsv) ssize_t ret; char *delimiter_str = NULL, *enclosure_str = NULL, *escape_str = NULL; size_t delimiter_str_len = 0, enclosure_str_len = 0, escape_str_len = 0; + zend_string *eol_str = NULL; - ZEND_PARSE_PARAMETERS_START(2, 5) + ZEND_PARSE_PARAMETERS_START(2, 6) Z_PARAM_RESOURCE(fp) Z_PARAM_ARRAY(fields) Z_PARAM_OPTIONAL Z_PARAM_STRING(delimiter_str, delimiter_str_len) Z_PARAM_STRING(enclosure_str, enclosure_str_len) Z_PARAM_STRING(escape_str, escape_str_len) + Z_PARAM_STR_OR_NULL(eol_str) ZEND_PARSE_PARAMETERS_END(); if (delimiter_str != NULL) { @@ -1840,7 +1842,7 @@ PHP_FUNCTION(fputcsv) PHP_STREAM_TO_ZVAL(stream, fp); - ret = php_fputcsv(stream, fields, delimiter, enclosure, escape_char); + ret = php_fputcsv(stream, fields, delimiter, enclosure, escape_char, eol_str); if (ret < 0) { RETURN_FALSE; } @@ -1848,8 +1850,8 @@ PHP_FUNCTION(fputcsv) } /* }}} */ -/* {{{ PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char) */ -PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char) +/* {{{ PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char, zend_string *eol_str) */ +PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char, zend_string *eol_str) { int count, i = 0; size_t ret; @@ -1897,8 +1899,12 @@ PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, cha } zend_tmp_string_release(tmp_field_str); } ZEND_HASH_FOREACH_END(); - - smart_str_appendc(&csvline, '\n'); + + if (eol_str) { + smart_str_append(&csvline, eol_str); + } else { + smart_str_appendc(&csvline, '\n'); + } smart_str_0(&csvline); ret = php_stream_write(stream, ZSTR_VAL(csvline.s), ZSTR_LEN(csvline.s)); diff --git a/ext/standard/file.h b/ext/standard/file.h index f9d153a52a5d2..582a061569f1a 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -49,7 +49,7 @@ PHPAPI void php_flock_common(php_stream *stream, zend_long operation, uint32_t o #define PHP_CSV_NO_ESCAPE EOF PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, int escape_char, size_t buf_len, char *buf, zval *return_value); -PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char); +PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char, zend_string *eol_str); #define META_DEF_BUFSIZE 8192 diff --git a/ext/standard/tests/file/fputcsv_variation17.phpt b/ext/standard/tests/file/fputcsv_variation17.phpt new file mode 100644 index 0000000000000..581bd2cd77ddf Binary files /dev/null and b/ext/standard/tests/file/fputcsv_variation17.phpt differ