Skip to content

Fix #42357: fputcsv() has an optional parameter for line endings #6403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions ext/spl/spl_directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/spl/spl_directory.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "\\") {}
Expand Down
3 changes: 2 additions & 1 deletion ext/spl/spl_directory_arginfo.h
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions ext/spl/tests/SplFileObject_fputcsv_variation16.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
SplFileObject::fputcsv() with user provided eol
--FILE--
<?php
$data = [
['aaa', 'bbb', 'ccc', 'dddd'],
['123', '456', '789'],
['"aaa"', '"bbb"'],
];

$eol_chars = ['||', '|', '\n', "\n"];
foreach ($eol_chars as $eol_char) {
$file = new SplTempFileObject;
foreach ($data as $record) {
$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"""
7 changes: 6 additions & 1 deletion ext/spl/tests/bug68479.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ var_dump($params);

?>
--EXPECT--
array(4) {
array(5) {
[0]=>
object(ReflectionParameter)#2 (1) {
["name"]=>
Expand All @@ -30,4 +30,9 @@ array(4) {
["name"]=>
string(6) "escape"
}
[4]=>
object(ReflectionParameter)#6 (1) {
["name"]=>
string(3) "eol"
}
}
2 changes: 1 addition & 1 deletion ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
3 changes: 2 additions & 1 deletion ext/standard/basic_functions_arginfo.h
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 12 additions & 6 deletions ext/standard/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -1840,16 +1842,16 @@ 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;
}
RETURN_LONG(ret);
}
/* }}} */

/* {{{ 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;
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Binary file added ext/standard/tests/file/fputcsv_variation17.phpt
Binary file not shown.