¿Cómo crear y descargar un archivo csv desde un script php?


89

Soy un programador novato y busqué mucho sobre mi pregunta, pero no pude encontrar una solución o tutorial útil sobre esto.

Mi objetivo es tener una matriz PHP y los elementos de la matriz se muestran en una lista en la página.

Quiero agregar una opción, para que si un usuario lo desea, pueda crear un archivo CSV con elementos de matriz y descargarlo.

No se como hacer esto. Yo también he buscado mucho. Pero aún no he encontrado ningún recurso útil.

Por favor, bríndeme algún tutorial, solución o consejo para implementarlo yo mismo. Como soy un novato, proporcione soluciones fáciles de implementar.

Mi matriz se ve así:

Array
(
    [0] => Array
        (
            [fs_id] => 4c524d8abfc6ef3b201f489c
            [name] => restaurant
            [lat] => 40.702692
            [lng] => -74.012869
            [address] => new york
            [postalCode] => 
            [city] => NEW YORK
            [state] => ny
            [business_type] => BBQ Joint
            [url] => 
        )

)

2
phpExcel para un archivo CSV es demasiado .. php.net/manual/en/function.fputcsv.php
Damien Pirsy

Muestre la estructura de su matriz y puedo proporcionar algo de código para convertir los elementos en un csv
medio rápido

@ half-fast He agregado la estructura de matriz en la publicación
user2302780

2
¿Cómo puedo agregar el título de la columna en un archivo csv?
user2302780

Respuestas:


200

Puede usar el fputcsv () incorporado para sus matrices para generar líneas csv correctas desde su matriz, por lo que tendrá que recorrer y recopilar las líneas, así:

$f = fopen("tmp.csv", "w");
foreach ($array as $line) {
    fputcsv($f, $line);
}

Para que los navegadores ofrezcan el cuadro de diálogo "Guardar como", deberá enviar encabezados HTTP como este (consulte más sobre este encabezado en el rfc ):

header('Content-Disposition: attachment; filename="filename.csv";');

Poniendolo todo junto:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    // open raw memory as file so no temp files needed, you might run out of memory though
    $f = fopen('php://memory', 'w'); 
    // loop over the input array
    foreach ($array as $line) { 
        // generate csv lines from the inner arrays
        fputcsv($f, $line, $delimiter); 
    }
    // reset the file pointer to the start of the file
    fseek($f, 0);
    // tell the browser it's going to be a csv file
    header('Content-Type: application/csv');
    // tell the browser we want to save it instead of displaying it
    header('Content-Disposition: attachment; filename="'.$filename.'";');
    // make php send the generated csv lines to the browser
    fpassthru($f);
}

Y puedes usarlo así:

array_to_csv_download(array(
  array(1,2,3,4), // this array is going to be the first row
  array(1,2,3,4)), // this array is going to be the second row
  "numbers.csv"
);

Actualización: en
lugar de php://memory, también puede usar el php://outputpara el descriptor de archivo y eliminar la búsqueda y tal:

function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$filename.'";');

    // open the "output" stream
    // see http://www.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-descriptioq
    $f = fopen('php://output', 'w');

    foreach ($array as $line) {
        fputcsv($f, $line, $delimiter);
    }
}   

2
¿Por qué no echolas líneas CSV generadas directamente en el bucle?
Alex Shesterov

1
@AlexShesterov, la razón principal es que fputcsv()no devuelve la línea generada, necesitará un descriptor de archivo para escribir. Sin embargo, puede rebobinar, escribir, borrar el búfer en cada iteración si tiene limitaciones de memoria. O simplemente use un archivo temporal real en su lugar.
complex857

@ complex857 ¿cómo puedo agregar el título de la columna para el csv?
user2302780

@ user2302780: Simplemente antepone a sus datos una fila de nombres de columna. Puede usar las claves de las matrices de datos con algo como$data = array_merge(array(array_keys($data[0])), $data);
complex857

1
@JoseRojas eso es de esperar, ya que una vez que pones algo sobre el cable (lo que significa generar cosas con php conceptualmente) no puedes volver atrás. Para usar, php://outputvea el segundo ejemplo de código actualizado.
complex857

18

No tengo suficiente reputación para responder a la solución @ complex857. Funciona muy bien, pero tuve que agregar; al final del encabezado Content-Disposition. Sin él, el navegador agrega dos guiones al final del nombre del archivo (por ejemplo, en lugar de "export.csv", el archivo se guarda como "export.csv--"). Probablemente intente desinfectar \ r \ n al final de la línea del encabezado.

La línea correcta debería verse así:

header('Content-Disposition: attachment;filename="'.$filename.'";');

En caso de que CSV tenga caracteres UTF-8, debe cambiar la codificación a UTF-8 cambiando la línea Content-Type:

header('Content-Type: application/csv; charset=UTF-8');

Además, me parece más elegante usar rewind () en lugar de fseek ():

rewind($f);

¡Gracias por tu solución!


2
Nunca he experimentado el --al final de los nombres de archivo, sin embargo, he actualizado la respuesta (¿por qué no enviar una edición?)
complex857

14

Prueba ... descargar csv.

<?php 
mysql_connect('hostname', 'username', 'password');
mysql_select_db('dbname');
$qry = mysql_query("SELECT * FROM tablename");
$data = "";
while($row = mysql_fetch_array($qry)) {
  $data .= $row['field1'].",".$row['field2'].",".$row['field3'].",".$row['field4']."\n";
}

header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="filename.csv"');
echo $data; exit();
?>

se romperá si un valor de campo contiene, por eso prefiero tsv (la pestaña es más rara que, y podemos reemplazarla o algo así)
oriadam

14

Esa es la función que utilicé para mi proyecto y funciona como se esperaba.

function array_csv_download( $array, $filename = "export.csv", $delimiter=";" )
{
    header( 'Content-Type: application/csv' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '";' );

    // clean output buffer
    ob_end_clean();

    $handle = fopen( 'php://output', 'w' );

    // use keys as column titles
    fputcsv( $handle, array_keys( $array['0'] ) );

    foreach ( $array as $value ) {
        fputcsv( $handle, $value , $delimiter );
    }

    fclose( $handle );

    // flush buffer
    ob_flush();

    // use exit to get rid of unexpected output afterward
    exit();
}

1
Me costó mucho intentar implementarlo en wordpress send_headers hook, porque cada vez que agrega todo el html de la página actual al final del archivo csv. Estas respuestas me detienen mucho, pero las uso sin operaciones de búfer.
Oleg Apanovich

El búfer de salida limpio me resolvió el problema de que antes del uso de estas filas de código al principio y al final del archivo formado había filas vacías.
Sharunas Bielskis

8

Utilice el siguiente código para convertir una matriz php a CSV

<?php
   $ROW=db_export_data();//Will return a php array
   header("Content-type: application/csv");
   header("Content-Disposition: attachment; filename=test.csv");
   $fp = fopen('php://output', 'w');

   foreach ($ROW as $row) {
        fputcsv($fp, $row);
   }
   fclose($fp);

3

Si su estructura de matriz siempre será multidimensional de esa manera exacta, entonces podemos iterar a través de los elementos como tales:

$fh = fopen('somefile.csv', 'w') or die('Cannot open the file');

for( $i=0; $i<count($arr); $i++ ){
    $str = implode( ',', $arr[$i] );
    fwrite( $fh, $str );
    fwrite( $fh, "\n" );
}
fclose($fh);

Esa es una forma de hacerlo ... podría hacerlo manualmente, pero de esta manera es más rápido y fácil de entender y leer.

Luego administraría sus encabezados algo que complex857 está haciendo para escupir el archivo. Luego, puede eliminar el archivo usando unlink () si ya no lo necesita, o puede dejarlo en el servidor si lo desea.


-2

Utilice lo siguiente,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.