Exportar a CSV a través de PHP

Respuestas:

308

Personalmente uso esta función para crear contenido CSV desde cualquier matriz.

function array2csv(array &$array)
{
   if (count($array) == 0) {
     return null;
   }
   ob_start();
   $df = fopen("php://output", 'w');
   fputcsv($df, array_keys(reset($array)));
   foreach ($array as $row) {
      fputcsv($df, $row);
   }
   fclose($df);
   return ob_get_clean();
}

Luego puede hacer que su usuario descargue ese archivo usando algo como:

function download_send_headers($filename) {
    // disable caching
    $now = gmdate("D, d M Y H:i:s");
    header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
    header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
    header("Last-Modified: {$now} GMT");

    // force download  
    header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");

    // disposition / encoding on response body
    header("Content-Disposition: attachment;filename={$filename}");
    header("Content-Transfer-Encoding: binary");
}

Ejemplo de uso:

download_send_headers("data_export_" . date("Y-m-d") . ".csv");
echo array2csv($array);
die();
Alain Tiemblo
fuente
1
en el servidor local está funcionando, pero en uno distante muestra una nueva página con contenido y sin ventana de descarga (perdón por mi inglés)
khaled_webdev
2
Puede haber varias razones para los errores, la forma más sencilla de encontrarlos es mirar su archivo apache error.log.
Alain Tiemblo
77
Necesitas hacer una die();llamada justo después echo array2csv();, editará mi respuesta. Asegúrese de generar su csv antes de mostrar algo en su página.
Alain Tiemblo
1
@ ring0 Supongo que poner la fecha pasada en el encabezado deshabilita el almacenamiento en caché de la página, mira el segundo ejemplo php.net/manual/en/function.header.php
Abhishek Madhani
2
Da tipos mime a su navegador para que obtenga un modal de descarga en lugar del csv representado en la ventana actual.
Alain Tiemblo
32

Puede exportar la fecha con este comando.

<?php

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);

$fp = fopen('file.csv', 'w');

foreach ($list as $fields) {
    fputcsv($fp, $fields);
}

fclose($fp);
?>

Primero debe cargar los datos del servidor mysql en una matriz

ynh
fuente
10
O bien, puede hacer el fputcsv () dentro de un bucle de asociación de búsqueda estándar y dejarlo caer directamente de los resultados devueltos.
DampeS8N
10
@ DampeS8N, +1 por el uso de "dejarlo caer" en una oración.
AnchovyLegend
esto se copia sin atribución del manual de PHP para fputcsv
BenK
14

Solo para que conste, la concatenación es muuuucho más rápida (lo digo en serio) que fputcsvo incluso implode; Y el tamaño del archivo es más pequeño:

// The data from Eternal Oblivion is an object, always
$values = (array) fetchDataFromEternalOblivion($userId, $limit = 1000);

// ----- fputcsv (slow)
// The code of @Alain Tiemblo is the best implementation
ob_start();
$csv = fopen("php://output", 'w');
fputcsv($csv, array_keys(reset($values)));
foreach ($values as $row) {
    fputcsv($csv, $row);
}
fclose($csv);
return ob_get_clean();

// ----- implode (slow, but file size is smaller)
$csv = implode(",", array_keys(reset($values))) . PHP_EOL;
foreach ($values as $row) {
    $csv .= '"' . implode('","', $row) . '"' . PHP_EOL;
}
return $csv;
// ----- concatenation (fast, file size is smaller)
// We can use one implode for the headers =D
$csv = implode(",", array_keys(reset($values))) . PHP_EOL;
$i = 1;
// This is less flexible, but we have more control over the formatting
foreach ($values as $row) {
    $csv .= '"' . $row['id'] . '",';
    $csv .= '"' . $row['name'] . '",';
    $csv .= '"' . date('d-m-Y', strtotime($row['date'])) . '",';
    $csv .= '"' . ($row['pet_name'] ?: '-' ) . '",';
    $csv .= PHP_EOL;
}
return $csv;

Esta es la conclusión de la optimización de varios informes, de diez a miles de filas. Los tres ejemplos funcionaron bien en 1000 filas, pero falla cuando los datos eran más grandes.

Axel A. García
fuente
9

Recomiendo parsecsv-for-php para solucionar un número de problemas con líneas nuevas y comillas anidadas.

Estigma
fuente
8

Funciona con más de 100 líneas, si especifica el tamaño del archivo en los encabezados, simplemente llame al método get () en su propia clase

function setHeader($filename, $filesize)
{
    // disable caching
    $now = gmdate("D, d M Y H:i:s");
    header("Expires: Tue, 01 Jan 2001 00:00:01 GMT");
    header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
    header("Last-Modified: {$now} GMT");

    // force download  
    header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");
    header('Content-Type: text/x-csv');

    // disposition / encoding on response body
    if (isset($filename) && strlen($filename) > 0)
        header("Content-Disposition: attachment;filename={$filename}");
    if (isset($filesize))
        header("Content-Length: ".$filesize);
    header("Content-Transfer-Encoding: binary");
    header("Connection: close");
}

function getSql()
{
    // return you own sql
    $sql = "SELECT id, date, params, value FROM sometable ORDER BY date;";
    return $sql;
}

function getExportData()
{
    $values = array();

    $sql = $this->getSql();
    if (strlen($sql) > 0)
    {
        $result = dbquery($sql); // opens the database and executes the sql ... make your own ;-) 
        $fromDb = mysql_fetch_assoc($result);
        if ($fromDb !== false)
        {
            while ($fromDb)
            {
                $values[] = $fromDb;
                $fromDb = mysql_fetch_assoc($result);
            }
        }
    }
    return $values;
}

function get()
{
    $values = $this->getExportData(); // values as array 
    $csv = tmpfile();

    $bFirstRowHeader = true;
    foreach ($values as $row) 
    {
        if ($bFirstRowHeader)
        {
            fputcsv($csv, array_keys($row));
            $bFirstRowHeader = false;
        }

        fputcsv($csv, array_values($row));
    }

    rewind($csv);

    $filename = "export_".date("Y-m-d").".csv";

    $fstat = fstat($csv);
    $this->setHeader($filename, $fstat['size']);

    fpassthru($csv);
    fclose($csv);
}
Bernhard Leichtle
fuente
6

Al igual que @ Dampes8N dijo:

$result = mysql_query($sql,$conecction);
$fp = fopen('file.csv', 'w');
while($row = mysql_fetch_assoc($result)){
    fputcsv($fp, $row);
}
fclose($fp);

Espero que esto ayude.

raíces
fuente