Créer un fichier CSV pour un utilisateur en PHP

220

J'ai des données dans une base de données MySQL. J'envoie à l'utilisateur une URL pour obtenir leurs données sous forme de fichier CSV.

J'ai le courrier électronique du lien, la requête MySQL, etc. couvert.

Comment puis-je, lorsqu'ils cliquent sur le lien, avoir une fenêtre contextuelle pour télécharger un CVS avec l'enregistrement à partir de MySQL?

J'ai déjà toutes les informations pour obtenir le dossier. Je ne vois tout simplement pas comment PHP doit créer le fichier CSV et les laisser télécharger un fichier avec une extension .csv.

d -_- b
la source

Réponses:

280

Essayer:

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;

etc

Modifier: voici un extrait de code que j'utilise pour éventuellement coder les champs CSV:

function maybeEncodeCSVField($string) {
    if(strpos($string, ',') !== false || strpos($string, '"') !== false || strpos($string, "\n") !== false) {
        $string = '"' . str_replace('"', '""', $string) . '"';
    }
    return $string;
}
Oleg Barshay
la source
11
notez que les règles pour les CSV sont importantes. Pour garantir un bon affichage, placez des guillemets doubles autour de vos champs et n'oubliez pas de remplacer les guillemets doubles à l'intérieur des champs par des guillemets doubles: `echo '"' .str_replace ('"', '" "', $ record1). '","'. str_replace ....
Mala
46
Juste pour clarifier, l'en-tête HTTP Content-Type correct pour CSV est text / csv, pas application / csv. Je doute que n'importe quel navigateur moderne s'en soucie, mais comme il existe des normes, nous pourrions aussi bien les utiliser.
fentie
10
En général, veuillez suivre la RFC 4180 lors de la génération de fichiers CSV. tools.ietf.org/html/rfc4180
Oleg Barshay
5
@Oleg Barshay: OMG, cette RFC est une pièce maîtresse: "Si des guillemets doubles sont utilisés pour entourer des champs, alors un guillemet double apparaissant à l'intérieur d'un champ doit être échappé en le précédant d'un autre guillemet double.". UN AUTRE DEVIS DOUBLE!
aefxx
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: // sortie
fputcsv

Andrii Nemchenko
la source
64
Plus de gens doivent voir cela et voter. C'est facilement la meilleure réponse sur cette page. PHP a déjà des fonctions intégrées pour formater le contenu CSV. Tout le monde devrait les utiliser. Grande réponse, @Andrey :)
maček
2
Dommage que fputcsv () ne fonctionne pas correctement cependant :( bugs.php.net/bug.php?id=50686
gou1
4
Bien, mais la outputCSVfonction est inutilement compliquée. Vous pouvez juste foreachterminer $array, en envoyant directement ses valeurs fputcsv. Pas besoin de ça __outputCSVet du array_walk:)foreach($data as $vals) {fputcsv($filehandler,$vals);}
Sygmoral
J'ai des problèmes avec les caractères français dans le tableau car j'ai finalement besoin que le fichier .csv soit ouvert dans Excel. Il étouffe les caractères accentués. Des choses comme des "Prévalence","age 1","city 1" idées? Jouer avec UTF-8 n'a pas aidé jusqu'à présent.
Voodoo
1
@theosem Delimiter dépend des paramètres d'exportation du système d'exploitation ou d'Excel. J'ai ajouté une note sur le délimiteur.
Andrii Nemchenko
19

Voici une version améliorée de la fonction de php.net publiée par @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);
}

Il est vraiment facile à utiliser et fonctionne très bien avec les jeux de résultats MySQL (i) / PDO.

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

N'oubliez pas exit()de l'appeler si vous avez terminé avec la page.

Xeoncross
la source
Comment changez-vous le séparateur de, en; ?
Grumpy
1
comment ajouter un bouton pour déclencher cet événement, afin que l'utilisateur puisse télécharger le fichier CSV à la demande?
CanCeylan
Je vais avoir l'erreur "SyntaxError: Token inattendu ILLEGAL" avec la ligne "fopen (" php: // output "," w ");" Quand je le change en "$ fp = fopen ('stats.csv', 'w');" il ne montre pas d'erreur. Mais bien sûr, cela ne fonctionne pas. Comment dois-je le résoudre?
CanCeylan
@CanCeylan, C'est une question à part entière et j'ai besoin de plus de détails pour la résoudre.
Xeoncross
1
Ajoutez fputcsv($outstream, array_keys($results[0]));juste avant votre foreachpour inclure également les en-têtes de colonne.
Justin
16

En plus de tout ce qui a déjà été dit, vous devrez peut-être ajouter:

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

Il est très utile lors de la gestion de fichiers contenant plusieurs langues, comme les noms de personnes ou les villes.

Stan
la source
9

Le fil est un peu vieux, je sais, mais pour référence future et pour les noobs comme moi:

Tout le monde ici explique comment créer le CSV, mais manque une partie fondamentale de la question: comment créer un lien. Pour établir un lien vers le téléchargement du fichier CSV, il vous suffit de créer un lien vers le fichier .php, qui à son tour répond comme étant un fichier .csv. Les en-têtes PHP font cela. Cela permet des trucs sympas, comme l'ajout de variables à la chaîne de requête et la personnalisation de la sortie:

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

my_csv_creator.php peut fonctionner avec les variables fournies dans la chaîne de requête et par exemple utiliser des requêtes de base de données différentes ou personnalisées, modifier les colonnes du CSV, personnaliser le nom de fichier, etc., par exemple:

User_John_Doe_10_Dec_11.csv
LBJ
la source
1
Euh - tous ceux qui lisent ceci doivent se méfier de cette approche. Je parierais que les entrées ne s'échappent pas correctement et cela peut entraîner de gros trous de sécurité dans votre application.
calumbrodie
Sa méthode est très sûre et fonctionne très bien. Vous pouvez facilement contrôler l'accès avec la session, et vous pouvez également stocker toutes les informations que vous souhaitez mettre dans un csv dans une var de session. Ensuite, il suffit de le désactiver dans le cadre du processus de conversion en csv. Je suggérerais simplement d'utiliser des variables de session au lieu d'une chaîne de requête.
inorganik du
1
Il n'y a pas de faille de sécurité en soi avec cette méthode. Tant que le fichier php référencé fait son travail d'assainissement et de vérification d'accès. Mais cela n'a pas vraiment de sens de montrer tout cela ici. Le point de la publication est que vous pouvez créer un lien vers l'URL qui génère le csv.
danielson317
8

Créez votre fichier, puis renvoyez-y une référence avec l'en-tête correct pour déclencher l'enregistrement sous - modifiez les éléments suivants si nécessaire. Mettez vos données CSV dans $ 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);
incompatibilité de type
la source
1
L' utilisation de la disposition de contenu «en ligne» signifie que le navigateur doit essayer de l'afficher sans téléchargement (IE a tendance à incorporer une instance Excel pour cela). "pièce jointe" est ce qui est nécessaire pour forcer un téléchargement.
Gert van den Berg du
5

Voici un exemple de travail complet utilisant PDO et incluant des en-têtes de colonne:

$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);
}
Justin
la source
4

Créez d'abord des données sous forme de chaîne avec une virgule comme délimiteur (séparées par ","). Quelque chose comme ça

$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);
*/
Behzad Ravanbakhsh
la source
3

Hé ça marche très bien .... !!!! Merci Peter Mortensen et 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;
}

?>

Kaddy
la source
N'utilisez PAS ce code en production, il est vulnérable aux injections SQL
ntzm
2

Méthode simple -

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

Ainsi, chaque ligne du $datatableau ira à une nouvelle ligne de votre fichier CSV nouvellement créé. Il ne fonctionne que pour PHP 5 et versions ultérieures.

user244641
la source
2

Vous pouvez simplement écrire vos données dans CSV en utilisant la fonction fputcsv . regardons l'exemple ci-dessous. Écrire le tableau de liste dans un fichier 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);
Shahbaz
la source
1

Le moyen le plus simple consiste à utiliser une classe CSV dédiée comme celle-ci:

$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'); 
Sergiu
la source
1

Au lieu de:

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

Utilisation:

$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";
}
Joshua
la source
1

Déjà une très bonne solution est venue. Je mets juste le code total pour qu'un débutant obtienne une aide 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";
}

?>

J'ai enregistré ce code dans csv-download.php

Maintenant, voyez comment j'ai utilisé ces données pour télécharger le fichier csv

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

Donc, lorsque j'ai cliqué sur le lien, il télécharge le fichier sans m'amener à la page csv-download.php du navigateur.

zahid9i
la source
0

Pour qu'il l'envoie au format CSV et lui donne le nom du fichier, utilisez header ():

http://us2.php.net/header

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

En ce qui concerne la création du CSV lui-même, il vous suffit de parcourir l'ensemble de résultats, de formater la sortie et de l'envoyer, comme vous le feriez pour tout autre contenu.

Gavin M. Roy
la source
0

Écrire votre propre code CSV est probablement une perte de temps, utilisez simplement un package tel que league / csv - il traite de toutes les choses difficiles pour vous, la documentation est bonne et elle est très stable / fiable:

http://csv.thephpleague.com/

Vous devrez utiliser le compositeur. Si vous ne savez pas ce qu'est un compositeur, je vous recommande fortement de jeter un œil: https://getcomposer.org/

John Hunt
la source
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 );
?>
Vish00722
la source
0

Comment écrire dans un fichier CSV en utilisant un script PHP? En fait, je le cherchais aussi. C'est une tâche facile avec PHP. fputs (gestionnaire, contenu) - cette fonction fonctionne efficacement pour moi. Vous devez d'abord ouvrir le fichier dans lequel vous devez écrire du contenu à l'aide de 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);
}
ntzm
la source
Il est toujours préférable d'ajouter le code à lui-même au lieu de lier, car les liens ont tendance à changer ou à disparaître avec le temps.
Sgoettschkes
Votre réponse est à un fil très ancien. Alors qu'en 2008, il était courant de créer vos propres lignes séparées par des virgules, la bonne méthode depuis PHP 5.1.0 serait d'utiliser la fonction fputcsv intégrée ( php.net/fputcsv ). Soyez prudent lorsque vous lisez d'anciens fils pour vous assurer que les informations qu'ils contiennent sont toujours pertinentes.
Luke Mills
-1

Mettez dans la $outputvariable les données CSV et l'écho avec les en-têtes corrects

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;
Lorenzo Massacci
la source