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

Hello.

I recently got information on some other nodes about creating and storing files using CGI.

Now i have the trouble of trying to get the browser to download them. I have a number of files ready for download in different directories on the server. The one i am trying to download here is called $updated - an updated text file.

I understand that the browser was designed not to download the files automatically, but i want it to do something at least that can allow for downloading from a server location.

My questions are: 1. I have tried to use the code from File Download from CGI Script but it doesnt work. I have the following :

print("<BR>DOWNLOAD ATTEMPT 0<BR>"); print ("Content-Type:application/x-download\n"); print ("Content-Disposition:attachment;filename=$updated\n\n"); print("<BR>DOWNLOAD ATTEMPT 1<BR>"); print $html->header(-type => 'application/octet-stream', -Content_Disposition => "attachment", -filename => $updated); print("<BR>DOWNLOAD ATTEMPT 3<BR>"); print $html->header(-type => 'application/octet-stream', -Content_Disposition => "attachment", -filename => $updated); print("<BR>DOWNLOAD ATTEMPT 4<BR>"); print ('<BR><a href="file.txt"></a><BR>'); ## added late print("<BR>DOWNLOAD ATTEMPT 5<BR>"); print ("Content-Disposition:attachment;filename=$updated<BR>"); print ("Content-type: application/octet-stream<BR><BR>"); print("<BR>DOWNLOAD ATTEMPT 6<BR>"); print('<a href="$updated?downloadid=1">download the txt file</a>');
but none of it works. It merely diplays the text on the screen, as described in the node above.

2. If the files were downloaded where do they go if no directory is specified. With some of the code above i found that you could get the browser in theoru to display a save as box (not done working here).

Any ideas ?

MonkPaul.

Janitored by holli - fixed link

Replies are listed 'Best First'.
Re: Download File using CGI
by Joost (Canon) on Jun 01, 2005 at 14:48 UTC
    You can't ouput different files in one response: you're mixing HTML with several files.

    You need a HTML link pointing to a cgi:

    <a href="download.cgi?file=something">download here</a>
    And then in the download.cgi only do the header and file-content:
    print <<ENDH; Content-type: application/octet-stream Content-Disposition: attachment; filename: $updated ENDH open FILE,"< /my/file" or die "Can't open: $!"; binmode FILE; local $/ = \10240; while (<FILE>) { print $_; } close FILE;
      Ok, i have the following code
      #!/usr/bin/perl -w use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw(fatalsToBrowser); my $updated = ""; ## set up the HTML page with the header and title lines print header; # start HTML head print start_html("Download page"); # print title bar with string print <<ENDH; Content-type: application/octet-stream Content-Disposition: attachment; filename: $updated ENDH open FILE,"<updated/$updated" or die "Can't open: $!"; binmode FILE; local $/ = \10240; while (<FILE>) { print $_; } close FILE; print end_html;
      and only
      print('<a href="download.cgi?file=$updated">Download Files here</a>');
      in the other file. Is this right.

      It comes out with an error message, simply $updated not defined. How do i pass the file name and its contents through to this download.cgi script without having to declare it at the top.

      Cheers.

        You're still printing a html header and HTML content before printing the header for the file's content.

        As I said before; you can't mix multiple files in one response - the HTML page is one of those files - the other is the file you want people to download.

        You have several options:

        You print the file's content in the HTML (without the headers, and remember to use escapeHTML() to escape any HTML tags in the file) and people will have to cut & paste to save the content.

        You print the correct headers and the file's content and nothing else and the file can be saved with the correct name when that script is called (if the browser supports the content-disposition header)

        You just link to a static file on the server using a normal <a> tag (by far the easiest, and most efficient).

        As for how to pass the filename (dangerous: you don't want just any file to be downloadable) - see Ovid's CGI course.

        HTTP/CGI is not a perl game. Read the RFC, learn the rules.
Re: Download File using CGI
by wazoox (Prior) on Jun 01, 2005 at 14:45 UTC
    If I get it correctly it looks like you're outputting some text ( print("<BR>DOWNLOAD ATTEMPT 6<BR>") ) BEFORE sending the headers. This can't work, you must send the headers first, before anything else.
    Then I think any of the proposed headers should work.
      Ah, i see

      At the moment i am outputting the contents of the other files to the screen so the user can view them at their discretion, but if a want to be able to download the files then i should, possibly, start a new script that would just print the headers first, thus downloading the files.
      Cheers

      Any ideas on where the files are downloaded to ?

      MonkPaul

        Any ideas on where the files are downloaded to ?

        As mentioned elsewhere in this thread, you can't know where the files are stored after they're downloaded - if they're not just displayed inline anyway.

        You probably shouldn't care about it, since there's nothing you can do about that - the content-dispostion header is just a hint for the browser.

Re: Download File using CGI
by dragonchild (Archbishop) on Jun 01, 2005 at 14:43 UTC
    The answers to most of these questions are browser-dependent. Each browser is free to handle these issues as it sees fit, and that's a good thing.

    Think about it this way - do you really want someone else determining how files you download onto your computer are handled? I don't ...


    • In general, if you think something isn't in Perl, try it out, because it usually is. :-)
    • "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"
Re: Download File using CGI
by tchatzi (Acolyte) on Jun 01, 2005 at 16:05 UTC
    This is how your code should look like for letting others download your files
    use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw(fatalToBrowser); $|=1; my $cgi = new CGI; open FILE, "/whatever/the/path/to/file" or die "Cannot open file for reading: $! "; print $cgi->header("application/octet-stream"); print while(<FILE>); close FILE;


    ``The wise man doesn't give the right answers, he poses the right questions.'' TIMTOWTDI