http://www.perlmonks.org?node_id=26724

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I want to allow users to download various items I have stored in a database. Some of these items are plain text that I want to allow a user to download as a text file. Others are blobs.

How can I allow a user to do this. Can I just have the Perl program print to STDOUT or do I need to print out Content type headers.

Another question I have is how I can make the default item that goes into the save as box be something other than the .pl file.

Replies are listed 'Best First'.
Re: Downloading things from a database
by Russ (Deacon) on Aug 08, 2000 at 06:49 UTC
    Sounds like you have a pretty good handle on this problem. You will have to send the right Content-type header to get the browser to handle the download correctly. Then, STDOUT will send the data to the user.

    Filename in HTTP header? has information about setting a default filename for downloads. merlyn has a link to one of his recent articles about this. Basically, you will set the action attribute of the form to yourscriptname.cgi/FileName

    The '/FileName' part will be ignored by the script, but probably used by the browser when setting the default filename for the download.

    Just as an example, I have a file 'junk.html' with

    <form action=test.cgi/JunkName><input type="submit" name="Test"></form +>
    The '/JunkName' is to make the browser default to JunkName in the file save window.

    This submits to test.cgi, which looks like:

    #!/usr/bin/perl use CGI; print CGI::header(-Content-type=>'text-plain'); print 'This is a file'
    When you click the submit button, the file save dialog comes up with JunkName as the filename.

    Note: this is not a good example of good CGI programming! Concept only, please. :-)

    Russ
    Brainbench 'Most Valuable Professional' for Perl

(bbq) Use Content-Disposition! Re: Downloading things from a database
by BBQ (Curate) on Aug 09, 2000 at 00:17 UTC
    This is a little something that I have been using. Modify at your discretion. It gets the file name and data from a table and prints everything out to the browser printing the name under Content-disposition so that it doesn't prompt the user to save the pl file.

    On a side note: If you don't have the file name, but know the file extension, you can always replace the name with the epoch returned by time().
    sub DownloadFile { my $id = shift; $sth = $dbh->prepare(qq{ select name,data from foo where id = ? and type = 'file' }) or Errors("Could not prepare SQL for file $id: $DBI::errstr"); $rc = $sth->execute($id) or Errors("Could not execute SQL for file $id: $DBI::errstr") +; my ($name,$data) = $sth->fetchrow_array(); my $size = length($data); print "Content-disposition: inline; filename=$name\n"; print "Content-Length: $size\n"; print "Content-Type: application/octet-stream\n\n"; print $data; return(1); }
    I hope that helps!

    #!/home/bbq/bin/perl
    # Trust no1!
Re: Downloading things from a database
by eak (Monk) on Aug 08, 2000 at 08:47 UTC
    You can actually get away with not knowing the content-type, you just default to application/octet-stream. Give the following a try, it is very nice. All you will need to do is perform a length() on the data and give a filename.

    --eric
    use CGI; my $size = length ($blob); my $filename = 'good_data.txt'; print CGI::header( -Content-Disposition => "attachment; filename=$filename", -Content-Type => 'application/octet-stream', -Content-Length => $size, -Pragma => 'no-cache', -Expires => 0 ); print $blob;
      Pragma: no-cache is for client to server, not server to client. Don't add it to code like this. It gives the impression that it is doing something, and then the next person adds it as well. {sigh}

      -- Randal L. Schwartz, Perl hacker

      Note that using the generic application/octet-stream MIME type for information you want the browser to simply save and not render won't always work under some (all?) versions of Internet Explorer. IE has a tendency of taking the MIME type with a grain of salt and doing further examination of the file's extension to determine whether or not IE should attempt to render the content internally. MS Office files (e.g. .doc) are notoriously difficult to bring up a "Save As" dialog, because some versions of IE insist on rendering it in an embedded MS Word window.
        What about very large files? As I see in my tests, this type of download use a lot of memory. Is there a was to do this without using a lot of system resources? Thanks