CSV en PHP: fgetcsv, fputcsv y SplFileObject para leer y escribir ficheros CSV

PHP tiene soporte nativo para leer y escribir ficheros CSV con las funciones fgetcsv() y fputcsv(), y la clase SplFileObject ofrece una interfaz orientada a objetos sobre las mismas. Son herramientas esenciales para importaciones y exportaciones de datos.

Leer un CSV con fgetcsv()

<?php
$handle = fopen('productos.csv', 'r');
if ($handle === false) {
    throw new RuntimeException('No se puede abrir el fichero');
}

// Saltar cabecera
fgetcsv($handle);

$productos = [];
while (($fila = fgetcsv($handle, 0, ';')) !== false) {
    $productos[] = [
        'sku'    => $fila[0],
        'nombre' => $fila[1],
        'precio' => (float) str_replace(',', '.', $fila[2]),
        'stock'  => (int) $fila[3],
    ];
}
fclose($handle);

echo count($productos) . " productos importadosn";
?>

El tercer parámetro de fgetcsv() es el separador (por defecto coma, pero muchos CSV europeos usan punto y coma).

Importar con conversión de encoding

Los ficheros CSV exportados desde Excel en Windows suelen venir en CP1252 (Windows-1252):

<?php
$handle = fopen('clientes_excel.csv', 'r');
while (($fila = fgetcsv($handle, 0, ';')) !== false) {
    // Convertir cada campo de CP1252 a UTF-8
    $fila = array_map(
        fn($campo) => mb_convert_encoding($campo, 'UTF-8', 'CP1252'),
        $fila
    );
    // Usar $fila...
}
fclose($handle);
?>

Escribir un CSV con fputcsv()

<?php
$pedidos = [
    [1001, 'Ana García',   '2024-06-01', 149.99],
    [1002, 'Luis Martín',  '2024-06-02',  89.50],
    [1003, 'María López',  '2024-06-03', 320.00],
];

$handle = fopen('pedidos.csv', 'w');
// BOM UTF-8 para que Excel lo abra correctamente
fwrite($handle, "xEFxBBxBF");

fputcsv($handle, ['ID', 'Cliente', 'Fecha', 'Total'], ';');
foreach ($pedidos as $pedido) {
    fputcsv($handle, $pedido, ';');
}
fclose($handle);
?>

Exportar CSV con descarga directa

<?php
// Cabeceras HTTP para forzar la descarga
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="pedidos-' . date('Y-m-d') . '.csv"');
header('Cache-Control: no-cache, must-revalidate');

$output = fopen('php://output', 'w');
fwrite($output, "xEFxBBxBF"); // BOM para Excel

fputcsv($output, ['ID', 'Cliente', 'Fecha', 'Total'], ';');

// Consulta a BD (ejemplo con PDO)
$stmt = $pdo->query('SELECT id, cliente, fecha, total FROM pedidos ORDER BY fecha DESC');
while ($fila = $stmt->fetch(PDO::FETCH_ASSOC)) {
    fputcsv($output, array_values($fila), ';');
}

fclose($output);
exit;
?>

SplFileObject para lectura orientada a objetos

<?php
$fichero = new SplFileObject('productos.csv');
$fichero->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
$fichero->setCsvControl(';', '"');

$cabecera = null;
foreach ($fichero as $fila) {
    if ($cabecera === null) {
        $cabecera = $fila;
        continue;
    }
    $registro = array_combine($cabecera, $fila);
    echo $registro['nombre'] . ': ' . $registro['precio'] . "n";
}
?>

Leer ficheros CSV grandes sin cargar en memoria

Para ficheros de varios GB, el enfoque de iterar fila a fila con fgetcsv() o SplFileObject mantiene el consumo de memoria constante:

<?php
$fichero = new SplFileObject('ventas_anuales.csv');
$fichero->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY);
$fichero->setCsvControl(';');

$total = 0.0;
$lineas = 0;

foreach ($fichero as $i => $fila) {
    if ($i === 0) continue; // cabecera
    $total += (float) $fila[3]; // columna importe
    $lineas++;
    if ($lineas % 10000 === 0) {
        echo "Procesadas $lineas líneas...n";
    }
}

echo "Total ventas: " . number_format($total, 2) . " €n";
?>

Errores comunes

  • Separador incorrecto: Excel guarda con punto y coma en configuraciones europeas. Si el CSV tiene un solo campo gigante, el separador es incorrecto.
  • Caracteres especiales y comillas: fputcsv() entrecomilla automáticamente los campos que contienen el separador o saltos de línea. Si el CSV de origen no lo hace bien, usa str_getcsv() con el parámetro enclosure.
  • BOM doble: si añades el BOM UTF-8 y el fichero ya lo tiene, Excel verá caracteres extra al inicio. Lee los primeros 3 bytes para verificar antes de añadirlo.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP