Outputting CSV Data as a File Download
If you ever need to save a set of columnar data as a csv file on the server, doing so using fopen() and fputcsv() is pretty simple. What you may not know, and what I didn't know until recently, was how to take that same data and return it as a downloadable csv file (not saved on the server). Turns out, accomplishing this task in Drupal is just as easy as saving a file but with one minor tweak.
Saving To a File
As a recap for some, and a primer for others, here's how we'd take some data and save it as a file on the server:
- // Let's get the 50 most recently created published nodes.
- $nodes = db_query('SELECT nid, title FROM {node} WHERE status = 1 ORDER BY created DESC LIMIT 50');
- // Open the file for writing.
- $fh = fopen('nodes.csv', 'w');
- // Add a header row
- fputcsv($fh, array(t('NID'), t('Title'));
- // Loop through our nodes and write the csv data.
- foreach($nodes as $node) {
- fputcsv($fh, array($node->nid, $node->title));
- }
- // Close & save the file.
- fclose($fh);
This code queries for a set of data, then opens a csv file and writes the values to it. Pretty simple stuff. But what if you want to present this to the browser as a file download, instead of saving to the server?
Saving as a File Download
Fortunately, we only need to change a few lines:
- // Let's get the 50 most recently created published nodes.
- $nodes = db_query('SELECT nid, title FROM {node} WHERE status = 1 ORDER BY created DESC LIMIT 50');
- // Add the headers needed to let the browser know this is a csv file download.
- drupal_add_http_header('Content-Type', 'text/csv; utf-8');
- drupal_add_http_header('Content-Disposition', 'attachment; filename = nodes.csv');
- // Instead of writing to a file, we write to the output stream.
- $fh = fopen('php://output', 'w');
- // Add a header row
- fputcsv($fh, array(t('NID'), t('Title'));
- // Loop through our nodes and write the csv data.
- foreach($nodes as $node) {
- fputcsv($fh, array($node->nid, $node->title));
- }
- // Close the output stream.
- fclose($fh);
In case you didn't catch that, first we needed to add some headers to let the browser know that we're sending a file download. Then, instead of opening a file to write to, we write to php's output stream. Now, when a user clicks a link, or enters the url to a page with this code, they will be prompted to save a file with the data formatted as csv.
Although simple, this was something I'd never had to do before so I thought I'd share this in case others hadn't either.
Tags