How to create and download a csv file from php script?
Asked Answered
S

9

122

I am a novice programmer and I searched a lot about my question but couldn't find a helpful solution or tutorial about this.

My goal is I have a PHP array and the array elements are showing in a list on the page.

I want to add an option, so that if a user wants, he/she can create a CSV file with array elements and download it.

I don't know how to do this. I have searched a lot too. But yet to find any helpful resource.

Please provide me some tutorial or solution or advice to implement it by myself. As I'm a novice please provide easy to implement solutions.

My array looks like:

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

)
Sculptress answered 27/4, 2013 at 11:35 Comment(6)
phpExcel for a CSV file is a bit too much..php.net/manual/en/function.fputcsv.phpMazuma
Show your array structure and I c an provide some code to turn the elements into a csvAspersorium
@Aspersorium I have added the array structure in the postSculptress
how can add the column title in csv file ?Sculptress
possible duplicate of Export to CSV via PHPWaring
possible duplicate of Create a CSV File for a user in PHPEason
B
259

You can use the built in fputcsv() for your arrays to generate correct csv lines from your array, so you will have to loop over and collect the lines, like this:

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

To make the browsers offer the "Save as" dialog, you will have to send HTTP headers like this (see more about this header in the rfc):

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

Putting it all together:

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: text/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);
}

And you can use it like this:

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

Update:
Instead of the php://memory you can also use the php://output for the file descriptor and do away with the seeking and such:

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);
    }
}   
Bennion answered 27/4, 2013 at 11:58 Comment(11)
why not echo the generated CSV lines directly in the loop?Adroit
@AlexShesterov, the main reason is that fputcsv() doesn't return the generated line, it will need a file descriptor to write to. You could rewind, write, clear the buffer on every iteration though if you are memory constrained. Or just use a real temporary file instead.Bennion
@Bennion how can I add column title for the csv ?Sculptress
@user2302780: You just prefix your data with a row of column names. You can use the keys from the data-arrays with something like $data = array_merge(array(array_keys($data[0])), $data);Bennion
Why writing to a file before outputting? If a function doesn't return the result, use ob_start and ob_get_contents to intercept.Nefarious
@Schien, sometimes you need to perform things like iconv() on the whole output and it's easier yo grab it from the php://memory (not in the example above). I feel like using the output buffer is hackish, but it might just very well be matter of taste (just add an extra option to the function to control it's behavior).Bennion
With php://output generate this error: fseek() stream does not support seeking, but with php://memory works like a charm!Yean
@JoseRojas that is to be expected since once you put something over the wire (that what outputting things with php means conceptually) you can't go back on that. To use php://output see the second updated code sample.Bennion
Is there a way to also include the column headings of the table?Wideopen
@Ben: You should be able to do so with grabbing the keys of the first "line" and sending it to the output first (assuming your array keys are the columns): fputcsv($f, array_keys(reset($array)), $delimiter); in front of the foreach of the linesBennion
For utf-8 encoding: https://mcmap.net/q/180632/-how-to-create-and-download-a-csv-file-from-php-scriptGnni
A
24

That is the function that I used for my project, and it works as expected.

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'] ), $delimiter );

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

    fclose( $handle );

    // flush buffer
    ob_flush();
    
    // use exit to get rid of unexpected output afterward
    exit();
}
Aureus answered 30/1, 2019 at 4:29 Comment(2)
I had a hard time trying to implement it in wordpress send_headers hook, cos every time it add all current page html to the end of csv file. These answer halp me a lot, but I use it without buffer operations.Dalmatia
clean output buffer solved for me the problem that before the usage of these code rows in the beginning and at the end of the formed file were empty rows.Urba
T
21

I don't have enough reputation to reply to @complex857 solution. It works great, but I had to add ; at the end of the Content-Disposition header. Without it the browser adds two dashes at the end of the filename (e.g. instead of "export.csv" the file gets saved as "export.csv--"). Probably it tries to sanitize \r\n at the end of the header line.

Correct line should look like this:

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

In case when CSV has UTF-8 chars in it, you have to change the encoding to UTF-8 by changing the Content-Type line:

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

Also, I find it more elegant to use rewind() instead of fseek():

rewind($f);

Thanks for your solution!

Telamon answered 24/10, 2013 at 16:46 Comment(1)
I've never experienced the -- at the end of the filenames myself, however I've updated the answer (why not just submit an edit?)Bennion
M
19

Try... csv download.

<?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();
?>
Marcellamarcelle answered 14/5, 2014 at 13:13 Comment(4)
will break if a field value contains , that's why i prefer tsv (tab is more rare than , and we can replace it or something)Weir
Simple and easy. ThxLeicester
"exit():" - thank you!! I was getting the whole HTML of my page after the data I wantedClock
I understand this is slightly irrelevant, but how would I do this with a woocommerce product? So instead of reading from database, it reads from variables already present on the single product page. Example: $product->get_id(); then exports these to a csv on a link click?Oneiric
C
9

Use the below code to convert a php array to 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);
Christadelphian answered 12/11, 2016 at 11:5 Comment(0)
G
4

Update for UTF-8 Encoding
Updating @complex857 's answer

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

    // open the "output" stream
    $f = fopen('php://output', 'w');
    // Write utf-8 bom to the file
    fputs($f, chr(0xEF) . chr(0xBB) . chr(0xBF));

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

May be a bit ugly code but it works!

Gnni answered 21/2, 2022 at 12:19 Comment(0)
A
3

If you're array structure will always be multi-dimensional in that exact fashion, then we can iterate through the elements like such:

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

That's one way to do it ... you could do it manually but this way is quicker and easier to understand and read.

Then you would manage your headers something what complex857 is doing to spit out the file. You could then delete the file using unlink() if you no longer needed it, or you could leave it on the server if you wished.

Aspersorium answered 27/4, 2013 at 20:44 Comment(0)
E
2

This function can generate a downloadable CSV file, you can set up the name and the delimiter without tricky functions (UTF-8 encoding in header function).

/**
 * Array2CSVDownload
 * 
 */
function Array2CSVDownload($array, $filename = "export.csv", $delimiter=";") {

    // force object to be array, sorry i was working with object items
    $keys = array_keys( (array) $array[0] );
    // use keys as column titles
    $data = [];
    array_push($data, implode($delimiter, $keys));
    // working with items
    foreach ($array as $item) {
        $values = array_values((array) $item);
        array_push($data, implode($delimiter, $values)); 
    }
    // flush buffer
    ob_flush();
    // mixing items
    $csvData = join("\n", $data);
    //setup headers to download the file
    header('Content-Disposition: attachment; filename="'.$filename.'";');
    //setup utf8 encoding
    header('Content-Type: application/csv; charset=UTF-8');
    // showing the results
    die($csvData);

}   
Exsanguine answered 1/9, 2022 at 2:21 Comment(0)
C
0

THIS IS THE ULTIMATE UTF-8 COMPATIBLE - array to csv function in PHP 100%

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


    // clean output buffer
    ob_end_clean();

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


    // Write utf-8 bom to the file
    fputs($handle, chr(0xEF) . chr(0xBB) . chr(0xBF));

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

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

    fclose($handle);

    // flush buffer
    ob_flush();

    // use exit to get rid of unexpected output afterward
    exit();
  } 
Cleora answered 6/3, 2024 at 18:43 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.