By manipulating the headers, you can cause the
client browser to want to save the incoming data
to disk:
header("Content-type: application/octet-stream");
// optionally, tell the prowser the default filename
// (the user can,of course, still change it in the
// save-as dialog box):
header("Content-Disposition: attachment; ilename=my_csv.txt");
Then just write your csv data. Be sure you don't output anything else,
as it, too, would end up in the saved csv file.