Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to serve output as file without saving it on server

I'm serving some records from a MySQL database using PHP's fputcsv() by creating a file on the server, filling it, then linking to it on the next page.

This works and is great but as this could be sensitive data, I don't want a buch of files hanging about on the server when they were created for (probably) a one-time download.

So what I want to know is this: is there a way to create this file & serve it for download without actually writing a permanent file on the server?

For instance could I create a comma separated string instead of using fputcsv() and serve that with the right headers in an output buffer?

The obvious move is to delete the file but I need to wait until the client downloads it first so that makes it a little difficult to decide when to do it.

Any suggestions welcome

The code:

$fp = fopen($filename, 'w');
fputcsv($fp, array("Last Name", "First Name"));
foreach ($result as $fields) 
{
    fputcsv($fp, $fields);
}
fclose($fp);

http://php.net/manual/en/function.fputcsv.php

like image 402
totallyNotLizards Avatar asked Dec 26 '22 19:12

totallyNotLizards


1 Answers

fputcsv() is a fabulous little function, so I wouldn't abandon it.

Instead, I suggest you play around with PHP's built-in I/O Wrappers

You, can, for example, do this to "stream" your CSV data line-by-line (subject to various output buffers, but that's another story):

<?php
header('Content-type: text/csv; charset=UTF-8');
header('Content-disposition: attachment; filename=report.csv');
$fp = fopen('php://output','w');
foreach($arrays as $array) fputcsv($fp, $array);

That works great, but if something goes wrong, your users will have a broken download.

So, if you don't have too much data, you can just write to an in-memory stream, just swap out php://output with php://memory and move things around:

<?php
$fp = fopen('php://memory','rw');

// our generateData() function might throw an exception, in which case 
// we want to fail gracefully, not send the user a broken/incomplete csv.
try {
    while($row = generateData()) fputcsv($fp, $row);
}catch(\Exception $e){
    // display a nice page to your user and exit/return
}

// SUCCESS! - so now we have CSV data in memory.  Almost like we'd spooled it to a file
//            on disk, but we didn't touch the disk.

//rewind our file handle
rewind($fp);

//send output
header('Content-type: text/csv; charset=UTF-8');
header('Content-disposition: attachment; filename=report.csv');
stream_get_contents($fp);
like image 108
timdev Avatar answered Jan 13 '23 14:01

timdev