Come creare e scaricare un file csv dallo script php?


89

Sono un programmatore alle prime armi e ho cercato molto sulla mia domanda ma non sono riuscito a trovare una soluzione utile o un tutorial su questo.

Il mio obiettivo è avere un array PHP e gli elementi dell'array vengono visualizzati in un elenco sulla pagina.

Voglio aggiungere un'opzione, in modo che se un utente lo desidera, può creare un file CSV con elementi dell'array e scaricarlo.

Non so come farlo. Anch'io ho cercato molto. Ma ancora per trovare una risorsa utile.

Per favore, forniscimi qualche tutorial o soluzione o consiglio per implementarlo da solo. Poiché sono un principiante, fornisci soluzioni facili da implementare.

Il mio array è simile a:

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 per un file CSV è un po 'troppo .. php.net/manual/en/function.fputcsv.php
Damien Pirsy

Mostra la struttura dell'array e fornisco del codice per trasformare gli elementi in un csv
mezzo veloce

@ mezzo veloce ho aggiunto la struttura dell'array nel post
user2302780

2
come si può aggiungere il titolo della colonna nel file csv?
user2302780

possibile duplicato di Export to CSV via PHP
Michal Mau

Risposte:


200

Puoi usare fputcsv () integrato per i tuoi array per generare linee csv corrette dal tuo array, quindi dovrai eseguire il loop e raccogliere le linee, in questo modo:

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

Per fare in modo che i browser offrano la finestra di dialogo "Salva con nome", dovrai inviare intestazioni HTTP in questo modo (vedi di più su questa intestazione nell'RFC ):

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

Mettere tutto insieme:

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);
}

E puoi usarlo in questo modo:

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"
);

Aggiornamento:
invece di php://memorypuoi anche usare il php://outputper il descrittore di file e farla finita con la ricerca e simili:

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
perché non echole linee CSV generate direttamente nel ciclo?
Alex Shesterov

1
@AlexShesterov, il motivo principale è che fputcsv()non restituisce la riga generata, avrà bisogno di un descrittore di file su cui scrivere. Potresti riavvolgere, scrivere, cancellare il buffer ad ogni iterazione anche se hai limiti di memoria. Oppure usa semplicemente un vero file temporaneo.
complex857

@ complex857 come posso aggiungere il titolo della colonna per il csv?
user2302780

@ user2302780: devi solo anteporre ai tuoi dati una riga di nomi di colonna. È possibile utilizzare le chiavi degli array di dati con qualcosa di simile a$data = array_merge(array(array_keys($data[0])), $data);
complex857

1
@JoseRojas ci si deve aspettare dal momento che una volta che hai messo qualcosa in rete (che cosa significa produrre cose con php concettualmente) non puoi tornare indietro. Per utilizzare php://outputvedere il secondo esempio di codice aggiornato.
complex857

18

Non ho abbastanza reputazione per rispondere alla soluzione @ complex857. Funziona benissimo, ma ho dovuto aggiungere; alla fine dell'intestazione Content-Disposition. Senza di esso il browser aggiunge due trattini alla fine del nome del file (ad esempio, invece di "export.csv" il file viene salvato come "export.csv--"). Probabilmente cerca di disinfettare \ r \ n alla fine della riga di intestazione.

La linea corretta dovrebbe essere simile a questa:

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

Nel caso in cui CSV contenga caratteri UTF-8, è necessario modificare la codifica in UTF-8 modificando la riga Content-Type:

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

Inoltre, trovo più elegante usare rewind () invece di fseek ():

rewind($f);

Grazie per la tua soluzione!


2
Non ho mai sperimentato personalmente la --fine dei nomi dei file, tuttavia ho aggiornato la risposta (perché non inviare semplicemente una modifica?)
complex857

14

Prova ... download 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();
?>

si romperà se un valore di campo contiene, ecco perché preferisco tsv (la scheda è più rara di, e possiamo sostituirla o qualcosa del genere)
oriadam

14

Questa è la funzione che ho usato per il mio progetto e funziona come previsto.

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
Ho avuto difficoltà a tentare di implementarlo nell'hook send_headers di wordpress, perché ogni volta che aggiunge tutto l'html della pagina corrente alla fine del file csv. Queste risposte mi ostacolano molto, ma lo uso senza operazioni di buffer.
Oleg Apanovich

buffer di output pulito ha risolto per me il problema che prima dell'uso di queste righe di codice all'inizio e alla fine del file formato erano righe vuote.
Sharunas Bielskis

8

Usa il codice seguente per convertire un array php in 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

Se la tua struttura di array sarà sempre multidimensionale in quel modo esatto, allora possiamo iterare attraverso gli elementi in questo modo:

$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);

Questo è un modo per farlo ... potresti farlo manualmente ma in questo modo è più veloce e più facile da capire e leggere.

Quindi gestiresti le tue intestazioni in modo simile a quello che complex857 sta facendo per sputare il file. Puoi quindi eliminare il file usando unlink () se non ne hai più bisogno, oppure puoi lasciarlo sul server se lo desideri.


-2

Utilizza il seguente,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.