Crea un file CSV per un utente in PHP


220

Ho dei dati in un database MySQL. Sto inviando all'utente un URL per ottenere i suoi dati come file CSV.

Ho coperto l'e-mail del link, query MySQL, ecc.

Come posso, quando fanno clic sul collegamento, avere un pop-up per scaricare un CVS con il record da MySQL?

Ho già tutte le informazioni per ottenere il record. Non vedo come fare in modo che PHP crei il file CSV e consenta loro di scaricare un file con estensione .csv.

Risposte:


280

Provare:

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

echo "record1,record2,record3\n";
die;

eccetera

Modifica: ecco uno snippet di codice che utilizzo per codificare facoltativamente i campi CSV:

function maybeEncodeCSVField($string) {
    if(strpos($string, ',') !== false || strpos($string, '"') !== false || strpos($string, "\n") !== false) {
        $string = '"' . str_replace('"', '""', $string) . '"';
    }
    return $string;
}

11
notare che le regole per i CSV sono importanti. Per garantire una buona visualizzazione, metti le doppie virgolette attorno ai tuoi campi e non dimenticare di sostituire le doppie virgolette all'interno dei campi per raddoppiare le virgolette: `echo '"' .str_replace ('"', '" "', $ record1). '","'. str_replace ....
Mala,

46
Giusto per chiarire, l'intestazione HTTP Content-Type corretta per CSV è text / csv, non application / csv. Dubito che qualsiasi browser moderno si occuperà in entrambi i modi, ma poiché ci sono standard che potremmo anche usarli.
Fentie,

10
In generale, seguire RFC 4180 quando si generano file CSV. tools.ietf.org/html/rfc4180
Oleg Barshay,

5
@Oleg Barshay: OMG, che RFC è un capolavoro: "Se le virgolette doppie vengono utilizzate per racchiudere i campi, allora una doppia virgoletta che appare all'interno di un campo deve essere sfuggita precedendola con un'altra doppia virgoletta". UN ALTRO DOPPIO PREVENTIVO!
aefxx il

465
header("Content-Type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");

function outputCSV($data) {
  $output = fopen("php://output", "wb");
  foreach ($data as $row)
    fputcsv($output, $row); // here you can change delimiter/enclosure
  fclose($output);
}

outputCSV(array(
  array("name 1", "age 1", "city 1"),
  array("name 2", "age 2", "city 2"),
  array("name 3", "age 3", "city 3")
));

php: // output
fputcsv


64
Più persone hanno bisogno di vederlo e votarlo. Questa è facilmente la risposta migliore in questa pagina. PHP ha già funzioni integrate per la formattazione del contenuto CSV. Tutti dovrebbero usarli. Ottima risposta, @Andrey :)
maček,

2
Peccato che fputcsv () non funzioni correttamente però :( bugs.php.net/bug.php?id=50686
gou1

4
Bello, ma la outputCSVfunzione è inutilmente complicata. Puoi semplicemente foreachfinire $array, inviando i suoi valori direttamente in fputcsv. Non c'è bisogno di questo __outputCSVe il array_walk:)foreach($data as $vals) {fputcsv($filehandler,$vals);}
Sygmoral,

Sto riscontrando alcuni problemi con i caratteri francesi nell'array perché alla fine ho bisogno che .csv sia aperto in Excel. Soffoca i personaggi accentati. Cose come "Prévalence","age 1","city 1" qualsiasi idea? Fare casini con UTF-8 non ha aiutato finora.
Voodoo,

1
Il delimitatore @theosem dipende dalle impostazioni di esportazione del sistema operativo o di Excel. Ho aggiunto una nota sul delimitatore.
Andrii Nemchenko,

19

Ecco una versione migliorata della funzione da php.net pubblicata da @Andrew.

function download_csv_results($results, $name = NULL)
{
    if( ! $name)
    {
        $name = md5(uniqid() . microtime(TRUE) . mt_rand()). '.csv';
    }

    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename='. $name);
    header('Pragma: no-cache');
    header("Expires: 0");

    $outstream = fopen("php://output", "wb");

    foreach($results as $result)
    {
        fputcsv($outstream, $result);
    }

    fclose($outstream);
}

È davvero facile da usare e funziona perfettamente con i set di risultati MySQL (i) / PDO.

download_csv_results($results, 'your_name_here.csv');

Ricordati di exit()dopo aver chiamato questo se hai finito con la pagina.


Come si cambia il separatore da, a; ?
Grumpy

1
come dovremmo aggiungere un pulsante per attivare questo evento, in modo che l'utente possa scaricare il file CSV su richiesta?
CanCeylan,

Avrò "SyntaxError: token imprevisto ILLEGAL" con la riga "fopen (" php: // output "," w ");" Quando lo cambio in "$ fp = fopen ('stats.csv', 'w');" non mostra errori. Ma poi ovviamente non funziona. Come dovrei risolverlo?
CanCeylan,

@CanCeylan, Questa è una domanda a sé stante e ho bisogno di maggiori dettagli per risolverlo.
Xeoncross,

1
Aggiungi fputcsv($outstream, array_keys($results[0]));poco prima foreachdi includere anche le intestazioni di colonna.
Justin,

16

Oltre a quanto già detto, potrebbe essere necessario aggiungere:

header("Content-Transfer-Encoding: UTF-8");

È molto utile quando si gestiscono file con più lingue in essi, come nomi di persone o città.


9

Il thread è un po 'vecchio, lo so, ma per riferimento futuro e per noobs come me:

Tutti gli altri qui spiegano come creare il CSV, ma mancano una parte fondamentale della domanda: come collegare. Per collegarti al download del file CSV, devi solo collegarti al file .php, che a sua volta risponde come file .csv. Le intestazioni PHP lo fanno. Ciò consente cose interessanti, come l'aggiunta di variabili alla stringa di query e la personalizzazione dell'output:

<a href="my_csv_creator.php?user=23&amp;othervariable=true">Get CSV</a>

my_csv_creator.php può funzionare con le variabili fornite nella stringa di query e ad esempio utilizzare query di database diverse o personalizzate, modificare le colonne del CSV, personalizzare il nome del file e così via, ad esempio:

User_John_Doe_10_Dec_11.csv

1
Chiunque legga questo, è MOLTO diffidente nei confronti di questo approccio. Scommetto che gli ingressi non vengono sfuggiti correttamente e questo può portare a grandi buchi di sicurezza nella tua applicazione.
Calumbrodie,

Il suo metodo è molto sicuro e funziona benissimo. Puoi facilmente controllare l'accesso con la sessione e anche archiviare tutte le informazioni che vuoi mettere in un CSV in una sessione var. Quindi disinseriscilo come parte del processo convertendolo in un CSV. Vorrei solo suggerire di utilizzare var di sessione anziché una stringa di query.
Inorganik,

1
Non ci sono falle di sicurezza di per sé con questo metodo. Finché il file php di riferimento fa il suo lavoro di risanamento e controllo degli accessi. Ma non ha davvero senso mostrare tutto questo qui. Il punto del post è che puoi collegarti a qualunque url generi il csv.
danielson317,

8

Crea il tuo file quindi restituisci un riferimento con l'intestazione corretta per attivare Salva con nome - modifica quanto segue in base alle necessità. Inserisci i tuoi dati CSV in $ csvdata.

$fname = 'myCSV.csv';
$fp = fopen($fname,'wb');
fwrite($fp,$csvdata);
fclose($fp);

header('Content-type: application/csv');
header("Content-Disposition: inline; filename=".$fname);
readfile($fname);

1
L'uso di "inline" Content-Disposition significa che il browser dovrebbe tentare di mostrarlo senza scaricare (IE tende a incorporare un'istanza di Excel per questo). "allegato" è ciò che è necessario per forzare un download.
Gert van den Berg,

5

Ecco un esempio di funzionamento completo che utilizza PDO e include le intestazioni di colonna:

$query = $pdo->prepare('SELECT * FROM test WHERE id=?');
$query->execute(array($id));    
$results = $query->fetchAll(PDO::FETCH_ASSOC);
download_csv_results($results, 'test.csv'); 
exit();


function download_csv_results($results, $name)
{            
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename='. $name);
    header('Pragma: no-cache');
    header("Expires: 0");

    $outstream = fopen("php://output", "wb");    
    fputcsv($outstream, array_keys($results[0]));

    foreach($results as $result)
    {
        fputcsv($outstream, $result);
    }

    fclose($outstream);
}

4

Prima fai i dati come una stringa con una virgola come delimitatore (separati da ","). Qualcosa come questo

$CSV_string="No,Date,Email,Sender Name,Sender Email \n"; //making string, So "\n" is used for newLine

$rand = rand(1,50); //Make a random int number between 1 to 50.
$file ="export/export".$rand.".csv"; //For avoiding cache in the client and on the server 
                                     //side it is recommended that the file name be different.

file_put_contents($file,$CSV_string);

/* Or try this code if $CSV_string is an array
    fh =fopen($file, 'w');
    fputcsv($fh , $CSV_string , ","  , "\n" ); // "," is delimiter // "\n" is new line.
    fclose($fh);
*/

3

Ehi Funziona molto bene .... !!!! Grazie Peter Mortensen e Connor Burton

<?php
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

ini_set('display_errors',1);
$private=1;
error_reporting(E_ALL ^ E_NOTICE);

mysql_connect("localhost", "user", "pass") or die(mysql_error());
mysql_select_db("db") or die(mysql_error());

$start = $_GET["start"];
$end = $_GET["end"];

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error());

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    $result.="{$row['email']},";
    $result.="\n";
    echo $result;
}

?>


Evitare NON utilizzare questo codice in produzione, è vulnerabile alle iniezioni SQL
ntzm

2

Metodo semplice -

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

$fp = fopen('data.csv', 'wb');
foreach($data as $line){
    $val = explode(",",$line);
    fputcsv($fp, $val);
}
fclose($fp);

Quindi ogni riga $datadell'array passerà a una nuova riga del file CSV appena creato. Funziona solo per PHP 5 e versioni successive.


2

Puoi semplicemente scrivere i tuoi dati in CSV usando la funzione fputcsv . diamo un'occhiata all'esempio qui sotto. Scrivi l'array dell'elenco nel file CSV

$list[] = array("Cars", "Planes", "Ships");
$list[] = array("Car's2", "Planes2", "Ships2");
//define headers for CSV 
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=file_name.csv');
//write data into CSV
$fp = fopen('php://output', 'wb');
//convert data to UTF-8 
fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF));
foreach ($list as $line) {
    fputcsv($fp, $line);
}
fclose($fp);

1

Il modo più semplice è utilizzare una classe CSV dedicata come questa:

$csv = new csv();
$csv->load_data(array(
    array('name'=>'John', 'age'=>35),
    array('name'=>'Adrian', 'age'=>23), 
    array('name'=>'William', 'age'=>57) 
));
$csv->send_file('age.csv'); 

1

Invece di:

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    $result.="{$row['email']},";
    $result.="\n";
    echo $result;
}

Uso:

$query = "SELECT * FROM customers WHERE created>='{$start} 00:00:00'  AND created<='{$end} 23:59:59'   ORDER BY id";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    echo implode(",", $row)."\n";
}

1

Giunse un'ottima soluzione. Sto solo inserendo il codice totale in modo che un principiante ottenga un aiuto totale

<?php
extract($_GET); //you can send some parameter by query variable. I have sent table name in *table* variable

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=$table.csv");
header("Pragma: no-cache");
header("Expires: 0");

require_once("includes/functions.php"); //necessary mysql connection functions here

//first of all I'll get the column name to put title of csv file.
$query = "SHOW columns FROM $table";
$headers = mysql_query($query) or die(mysql_error());
$csv_head = array();
while ($row = mysql_fetch_array($headers, MYSQL_ASSOC))
{
    $csv_head[] =  $row['Field'];
}
echo implode(",", $csv_head)."\n";

//now I'll bring the data.
$query = "SELECT * FROM $table";
$select_c = mysql_query($query) or die(mysql_error()); 

while ($row = mysql_fetch_array($select_c, MYSQL_ASSOC))
{
    foreach ($row as $key => $value) {
            //there may be separator (here I have used comma) inside data. So need to put double quote around such data.
        if(strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
            $row[$key] = '"' . str_replace('"', '""', $value) . '"';
        }
    }
    echo implode(",", $row)."\n";
}

?>

Ho salvato questo codice in csv-download.php

Ora guarda come ho usato questi dati per scaricare il file CSV

<a href="csv-download.php?table=tbl_vfm"><img title="Download as Excel" src="images/Excel-logo.gif" alt="Download as Excel" /><a/>

Quindi, quando ho cliccato sul link, scarica il file senza portarmi alla pagina csv-download.php sul browser.


0

Per farlo inviare come CSV e fargli dare il nome del file, usa header ():

http://us2.php.net/header

header('Content-type: text/csv');
header('Content-disposition: attachment; filename="myfile.csv"');

Per quanto riguarda la creazione del CSV stesso, dovrai semplicemente scorrere il set di risultati, formattando l'output e inviandolo, proprio come faresti con qualsiasi altro contenuto.


0

Scrivere il proprio codice CSV è probabilmente una perdita di tempo, basta usare un pacchetto come league / csv: si occupa di tutte le cose difficili per te, la documentazione è buona ed è molto stabile / affidabile:

http://csv.thephpleague.com/

Dovrai utilizzare il compositore. Se non sai cos'è il compositore, ti consiglio vivamente di dare un'occhiata: https://getcomposer.org/


0
<?
    // Connect to database
    $result = mysql_query("select id
    from tablename
    where shid=3");
    list($DBshid) = mysql_fetch_row($result);

    /***********************************
    Write date to CSV file
    ***********************************/

    $_file = 'show.csv';
    $_fp = @fopen( $_file, 'wb' );

    $result = mysql_query("select name,compname,job_title,email_add,phone,url from UserTables where id=3");

    while (list( $Username, $Useremail_add, $Userphone, $Userurl) = mysql_fetch_row($result))
    {
        $_csv_data = $Username.','.$Useremail_add.','.$Userphone.','.$Userurl . "\n";
        @fwrite( $_fp, $_csv_data);
    }
    @fclose( $_fp );
?>

0

Come scrivere nel file CSV usando lo script PHP? In realtà stavo anche cercando quello. È un compito facile con PHP. fputs (gestore, contenuto) - questa funzione funziona in modo efficiente per me. Per prima cosa devi aprire il file in cui devi scrivere il contenuto usando fopen ($ CSVFileName, 'wb').

$CSVFileName = test.csv”;
$fp = fopen($CSVFileName, wb’);

//Multiple iterations to append the data using function fputs()
foreach ($csv_post as $temp)
{
    $line = “”;
    $line .= Content 1 . $comma . $temp . $comma . Content 2 . $comma . 16/10/2012″.$comma;
    $line .= \n”;
    fputs($fp, $line);
}

È sempre preferito aggiungere il codice in modo tale da non essere collegato, poiché i collegamenti tendono a cambiare o scomparire nel tempo.
Sgoettschkes,

La tua risposta è a un thread molto vecchio. Mentre, nel 2008, era una pratica standard per costruire il proprio separato da virgole linee, il metodo corretto da PHP 5.1.0 sarebbe quella di utilizzare il costruito in funzione fputcsv ( php.net/fputcsv ). Fai attenzione quando leggi i vecchi thread per assicurarti che le informazioni in essi contenute siano ancora pertinenti.
Luke Mills,

-1

Inserisci nella $outputvariabile i dati CSV ed esegui l'eco con le intestazioni corrette

header("Content-type: application/download\r\n");
header("Content-disposition: filename=filename.csv\r\n\r\n");
header("Content-Transfer-Encoding: ASCII\r\n");
header("Content-length: ".strlen($output)."\r\n");
echo $output;
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.