Skip to content

PHP Tutorial File Handling

Reading and Writing CSV Files

Lesson 172 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

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()

index.php
PHP
<?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");
Output
OUTPUT
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()

index.php
PHP
<?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);
Output
OUTPUT
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()

index.php
PHP
<?php
print_r(str_getcsv('a,"b,c",d', ",", '"', "\\"));
Output
OUTPUT
Array
(
    [0] => a
    [1] => b,c
    [2] => d
)

A safe import loop

Imported files are untrusted input. Check every row.

index.php
PHP
<?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";
Output
OUTPUT
1 good, 2 rejected

Export a CSV download

index.php
PHP
<?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.

index.php
PHP
<?php
function csvSafe(string $value): string
{
    return preg_match('/^[=+\-@]/', $value) === 1 ? "'" . $value : $value;
}

echo csvSafe("=HYPERLINK(\"http://evil\")") . "\n";
echo csvSafe("Normal text");
Output
OUTPUT
'=HYPERLINK("http://evil")
Normal text
lightbulb
Encoding
Excel opens UTF-8 CSV files more reliably when the file starts with a byte order mark ("\xEF\xBB\xBF"). Add it when your users open the export in Excel.