Comment créer et télécharger un fichier csv à partir d'un script php?

89

Je suis un programmeur novice et j'ai beaucoup cherché sur ma question mais je n'ai pas trouvé de solution ou de tutoriel utile à ce sujet.

Mon objectif est d'avoir un tableau PHP et les éléments du tableau s'affichent dans une liste sur la page.

Je veux ajouter une option, de sorte que si un utilisateur le souhaite, il / elle puisse créer un fichier CSV avec des éléments de tableau et le télécharger.

Je ne sais pas comment faire ça. J'ai beaucoup cherché aussi. Mais encore à trouver une ressource utile.

Veuillez me fournir un tutoriel ou une solution ou des conseils pour l'implémenter moi-même. En tant que novice, veuillez fournir des solutions faciles à mettre en œuvre.

Mon tableau ressemble à:

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] => 
        )

)
user2302780
la source
2
phpExcel pour un fichier CSV est un peu trop .. php.net/manual/en/function.fputcsv.php
Damien Pirsy
Montrez votre structure de tableau et je vais fournir du code pour transformer les éléments en csv
semi-rapide
@ half-fast J'ai ajouté la structure du tableau dans le post
user2302780
2
comment ajouter le titre de la colonne dans le fichier csv?
user2302780
duplication possible de l' exportation vers CSV via PHP
Michal Mau

Réponses:

200

Vous pouvez utiliser le fputcsv () intégré pour vos tableaux pour générer des lignes csv correctes à partir de votre tableau, vous devrez donc boucler et collecter les lignes, comme ceci:

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

Pour que les navigateurs proposent la boîte de dialogue "Enregistrer sous", vous devrez envoyer des en-têtes HTTP comme celui-ci (voir plus sur cet en-tête dans le rfc ):

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

Mettre tous ensemble:

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

Et vous pouvez l'utiliser comme ceci:

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

Mise à jour: au
lieu du, php://memoryvous pouvez également utiliser le php://outputpour le descripteur de fichier et supprimer la recherche et autres:

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);
    }
}   
complexe857
la source
2
pourquoi pas echoles lignes CSV générées directement dans la boucle?
Alex Shesterov
1
@AlexShesterov, la raison principale est que fputcsv()ne renvoie pas la ligne générée, il aura besoin d'un descripteur de fichier pour écrire. Vous pouvez rembobiner, écrire, effacer la mémoire tampon à chaque itération si vous êtes limité en mémoire. Ou utilisez simplement un vrai fichier temporaire à la place.
complex857
@ complex857 comment puis-je ajouter un titre de colonne pour le csv?
user2302780
@ user2302780: Vous préfixez simplement vos données avec une ligne de noms de colonnes. Vous pouvez utiliser les clés des tableaux de données avec quelque chose comme$data = array_merge(array(array_keys($data[0])), $data);
complex857
1
@JoseRojas c'est à prévoir car une fois que vous avez mis quelque chose sur le fil (ce que signifie conceptuellement sortir des choses avec php), vous ne pouvez pas revenir en arrière. Pour l'utiliser, php://outputconsultez le deuxième exemple de code mis à jour.
complex857
18

Je n'ai pas assez de réputation pour répondre à la solution @ complex857. Cela fonctionne très bien, mais je devais ajouter; à la fin de l'en-tête Content-Disposition. Sans cela, le navigateur ajoute deux tirets à la fin du nom de fichier (par exemple, au lieu de "export.csv", le fichier est enregistré sous "export.csv-"). Il essaie probablement de nettoyer \ r \ n à la fin de la ligne d'en-tête.

La ligne correcte devrait ressembler à ceci:

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

Dans le cas où CSV contient des caractères UTF-8, vous devez changer le codage en UTF-8 en modifiant la ligne Content-Type:

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

De plus, je trouve plus élégant d'utiliser rewind () au lieu de fseek ():

rewind($f);

Merci pour votre solution!

Luxian
la source
2
Je n'ai jamais expérimenté la --fin des noms de fichiers moi-même, mais j'ai mis à jour la réponse (pourquoi ne pas simplement soumettre une modification?)
complex857
14

Essayez ... télécharger 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();
?>
Indrajeet Singh
la source
se cassera si une valeur de champ contient, c'est pourquoi je préfère tsv (tab est plus rare que, et nous pouvons le remplacer ou quelque chose)
oriadam
14

C'est la fonction que j'ai utilisée pour mon projet, et cela fonctionne comme prévu.

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();
}
Sajidur Rahman
la source
1
J'ai eu du mal à essayer de l'implémenter dans le hook wordpress send_headers, car chaque fois qu'il ajoute toute la page html actuelle à la fin du fichier csv. Celles-ci me répondent beaucoup, mais je l'utilise sans opérations de tampon.
Oleg Apanovich le
le tampon de sortie propre a résolu pour moi le problème qu'avant l'utilisation de ces lignes de code au début et à la fin du fichier formé étaient des lignes vides.
Sharunas Bielskis
8

Utilisez le code ci-dessous pour convertir un tableau php en 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);
Kiran Reddy
la source
3

Si votre structure de tableau sera toujours multidimensionnelle de cette manière exacte, nous pouvons parcourir les éléments comme ceux-ci:

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

C'est une façon de le faire ... vous pouvez le faire manuellement, mais cette méthode est plus rapide et plus facile à comprendre et à lire.

Ensuite, vous gérez vos en-têtes, ce que complex857 fait pour cracher le fichier. Vous pouvez ensuite supprimer le fichier en utilisant unlink () si vous n'en avez plus besoin, ou vous pouvez le laisser sur le serveur si vous le souhaitez.

demi-rapide
la source
-2

Utilisez le suivant,

echo "<script type='text/javascript'> window.location.href = '$file_name'; </script>";
Ashwin Balani
la source