CSV (comma-separated values) is a plain text format for tables. Spreadsheets import and export it. Do not parse it with explode(","), because values can contain commas inside quotes.
Write a CSV: fputcsv()
<?php
$rows = [
["name", "city", "note"],
["Ana", "Pune", "likes tea, coffee"],
["Ben", "Delhi", 'says "hi" loudly'],
];
$handle = fopen("people.csv", "w");
foreach ($rows as $row) {
fputcsv($handle, $row, ",", '"', "\\");
}
fclose($handle);
echo file_get_contents("people.csv");
name,city,note
Ana,Pune,"likes tea, coffee"
Ben,Delhi,"says ""hi"" loudly"
fputcsv() adds quotes where needed and doubles quote marks inside values. The extra arguments (",", '"', "\\") are the separator, enclosure and escape character. Newer PHP versions warn when the escape argument is left out, so we pass it explicitly.
Read a CSV: fgetcsv()
<?php
file_put_contents("people.csv", "name,city\nAna,Pune\nBen,Delhi\n");
$handle = fopen("people.csv", "r");
$header = fgetcsv($handle, 0, ",", '"', "\\");
while (($row = fgetcsv($handle, 0, ",", '"', "\\")) !== false) {
$person = array_combine($header, $row);
echo $person["name"] . " lives in " . $person["city"] . "\n";
}
fclose($handle);
Ana lives in Pune
Ben lives in Delhi
The first row is the header. array_combine() turns each row into an associative array keyed by header names.
Parse a CSV string: str_getcsv()
<?php
print_r(str_getcsv('a,"b,c",d', ",", '"', "\\"));
Array
(
[0] => a
[1] => b,c
[2] => d
)
A safe import loop
Imported files are untrusted input. Check every row.
<?php
file_put_contents("import.csv", "name,age\nAna,30\nBen,abc\nCy\n");
$handle = fopen("import.csv", "r");
fgetcsv($handle, 0, ",", '"', "\\"); // skip the header
$good = 0;
$bad = 0;
while (($row = fgetcsv($handle, 0, ",", '"', "\\")) !== false) {
if (count($row) !== 2 || filter_var($row[1], FILTER_VALIDATE_INT) === false) {
$bad++;
continue;
}
$good++;
}
fclose($handle);
echo "$good good, $bad rejected";
1 good, 2 rejected
Export a CSV download
<?php
header("Content-Type: text/csv; charset=utf-8");
header('Content-Disposition: attachment; filename="people.csv"');
$out = fopen("php://output", "w");
fputcsv($out, ["name", "city"], ",", '"', "\\");
fputcsv($out, ["Ana", "Pune"], ",", '"', "\\");
fclose($out);
php://output writes straight to the browser, with no temporary file.
CSV injection
If a cell starts with =, +, - or @, Excel may run it as a formula. When you export text that came from users, prefix such cells with a single quote or a space so spreadsheets treat them as text.
<?php
function csvSafe(string $value): string
{
return preg_match('/^[=+\-@]/', $value) === 1 ? "'" . $value : $value;
}
echo csvSafe("=HYPERLINK(\"http://evil\")") . "\n";
echo csvSafe("Normal text");
'=HYPERLINK("http://evil")
Normal text
Encoding
"\xEF\xBB\xBF"). Add it when your users open the export in Excel.