fputcsv

Formats an array as a CSV line and writes it to an open file handle.

Signature
fputcsv(resource $stream, array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n"): int|false
  • Added in PHP 5.1.0

Parameters

ParameterTypeDescription
$streamresourceAn open file pointer from fopen(), opened for writing.
$fieldsarrayA one-dimensional array of values to write as one CSV row.
$separatoroptionalstring= ","The field delimiter. Must be a single byte character.
$enclosureoptionalstring= "\""The field enclosure character. Must be a single byte character.
$escapeoptionalstring= "\\"The escape character, or an empty string to disable PHP's proprietary escaping. Relying on the default is deprecated as of PHP 8.4.
$eoloptionalstring= "\n"The end-of-line sequence appended after the row.

Return value

int|falseThe length of the written string in bytes, or false on failure.

Errors

Throws a ValueError if separator, enclosure or escape is not a single byte character (escape may also be an empty string); emits an E_WARNING if the stream is not writable.

Changelog

  • PHP 8.4.0Relying on the default value of escape is deprecated; it must now be passed explicitly, positionally or by named argument.
  • PHP 8.1.0The optional eol parameter was added.
  • PHP 7.4.0The escape parameter accepts an empty string to disable the proprietary escape mechanism.

fputcsv takes a flat array and writes it as one properly quoted CSV row. It handles the fiddly parts for you: a field is only wrapped in quotes when it actually needs to be, and an embedded quote is doubled.

When to reach for it

  • Exporting query results to a downloadable CSV.
  • Writing a report file that Excel or Google Sheets will open.
  • Building CSV in memory with php://memory before sending it as a response.

What trips people up

The $escape parameter is the big one. PHP's default backslash escaping is not part of the CSV standard, and it produces output other parsers read wrongly. Since PHP 8.4 relying on the default also emits a deprecation notice. Always pass it explicitly, and pass '' for RFC 4180-compliant output:

fputcsv($fh, $row, ',', '"', '');

The other surprise is line endings. The default is \n, but many Windows tools expect \r\n. Since PHP 8.1 you can pass that as the sixth argument rather than post-processing the file.

Finally, $fields must be one-dimensional. Nested arrays are converted to the string "Array" with a notice. Objects need __toString(), and null becomes an empty field.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Stream a database export to the browser row by row without buffering the whole result set.
  • Write a nightly report file that Excel opens cleanly, using \r\n line endings.
  • Serialize a config array to CSV for a downstream import job.

Frequently asked questions

Why do I get a deprecation notice from fputcsv in PHP 8.4?

Because relying on the default `$escape` value is deprecated. Pass it explicitly — `fputcsv($fh, $row, ',', '"', '')` — where the empty string also gives you standards-compliant CSV.

How do I write a CSV with \r\n line endings?

Pass `"\r\n"` as the sixth argument, `$eol`, which was added in PHP 8.1. On older versions you have to write to a buffer and replace the endings yourself.

Why does fputcsv not quote all my fields?

By design — it only encloses a field that contains the separator, the enclosure, the escape character, a newline, a carriage return, a tab or a space. This is valid CSV; if you need every field quoted you must build the line yourself.

More examples

Round-tripping with fgetcsv

The comma inside `Ada, L.` survives the round trip as a single field because `fputcsv` quoted it and `fgetcsv` unquoted it. Passing the same escape value to both calls is what keeps the two sides in agreement.

Example · php
<?php
$out = fopen('people.csv', 'w');
fputcsv($out, ['name', 'city'], ',', '"', '');
fputcsv($out, ['Ada, L.', 'London'], ',', '"', '');
fclose($out);

$in = fopen('people.csv', 'r');
while (($row = fgetcsv($in, 0, ',', '"', '')) !== false) {
    print_r($row);
}
fclose($in);
unlink('people.csv');

Windows-friendly line endings

The visible markers show `<CR><LF>` after each row, and the byte count is 16 rather than the 14 you would get with plain `\n`. The sixth parameter, added in PHP 8.1, removes the need to rewrite the file afterwards.

Example · php
<?php
$fh = fopen('php://memory', 'r+');
fputcsv($fh, ['a', 'b'], ',', '"', '', "\r\n");
fputcsv($fh, ['c', 'd'], ',', '"', '', "\r\n");

rewind($fh);
$csv = stream_get_contents($fh);
fclose($fh);

echo str_replace(["\r", "\n"], ['<CR>', "<LF>\n"], $csv);
echo 'bytes: ', strlen($csv), "\n";

A semicolon-separated export

Only `Widget; large` gets quoted, because it is the one value containing the separator. Semicolons are the norm for European locales where the comma is the decimal mark, and the values here show why.

Example · php
<?php
$fh = fopen('php://memory', 'r+');

fputcsv($fh, ['product', 'price'], ';', '"', '');
fputcsv($fh, ['Widget; large', '9,99'], ';', '"', '');
fputcsv($fh, ['Plain widget', '4,50'], ';', '"', '');

rewind($fh);
echo stream_get_contents($fh);
fclose($fh);

Discussion

  • Be the first to comment on this lesson.