简体   繁体   中英

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

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

Rather than that, why not just have your page echo out a csv mime type and then echo out the file to the user?

It works a charm, the file is never created and passed as a one off to the client.

Something like this:

header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

echo "col1,col2";
for($i=0; $i<25;$i++)
{
    echo "key :".$i.", ".($i*$i)."\r\n";
}

You should be able to test that out as is and see how it works.

The added beauty is that most users will be directed to download the file rather than opening it, so the user doesn't even leave the page (most of the time).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM