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

I have many files that are not in my public_html folder that I want to provide access to without moving them into a web-enabled folder. Aside from gif images, I have been unsuccessful at doing this. What I've done is open the file, write it to an array, and then try to print the array out to the browser hoping the browser will somehow get the idea that it is binary data and present me with an option to download the file. GIF images get displayed using this technique, everything else just spits out a bunch of hex-code. Am I asking for the impoassible?
  • Comment on Binary output ot browser/force download?

Replies are listed 'Best First'.
Re: Binary output ot browser/force download?
by cfreak (Chaplain) on Jul 24, 2002 at 21:06 UTC

    You are almost there, before you print the array to need to tell it the content type of the file in question. If its a gif

    print "Content-type: image/gif\n\n";

    Or if its an application:

    print "Content-type: application/octet-stream\n\n";

    There are some others, you should just search around for them.

    To force a download you can do a couple of things.
    1. Before your content header you can do this:

    print "Content-disposition: attachment\n";

    However I understand that doesn't work in some versions of IE. So the second thing you can do is pass your filename as though it were part of the path. Anything after the cgi filename is considered path info and is recognized as a parameter, however the browser thinks its just a path and downloads it with the correct filename and everything. If you are using CGI you can set it up like this:

    my $cgi = new CGI; my $filename = $cgi->path_info();

    When you call that with a path like this:

    http://your-domain.com/cgi-bin/script.cgi/your_file.doc
    $filename will have "/your_file.doc" in it, you can remove the leading slash, print out the type and the rest of the file your browser will simply download "your_file.doc"

    Hope that helps
    Chris

    Lobster Aliens Are attacking the world!
Re: Binary output ot browser/force download?
by tosh (Scribe) on Jul 24, 2002 at 21:07 UTC
    It sounds like what you're doing is correct but you'll need to set the MIME type and of course send the data.

    I use a system which allows download of all sorts of files, and since I can't be 100% sure of the accuracy of the file extension I do the following
    print "Content-Type: application/x-unknown-download_file\nContent-Disp +osition: attachment\; filename=\"".$fileOBJ->data('filename')."\"\nCo +ntent-Length: $size\n\n";
    I use the line:
    Content-Disposition: attachment\;
    to force the browser to download the file rather than try to display the file, and the application/x-unknown-download_file is a MIME type I made up (you can make up your own, it's fun) so that the browser doesn't think it knows the file type.

    As for the actual output of the data, that's a fairly easy:
    open(my $DLFILE, $file); my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, +$blksize,$blocks) = stat($DLFILE); print "Content-Type: application/x-unknown-download_file\nContent-Disp +osition: attachment\; filename=\"".$fileOBJ->data('filename')."\"\nCo +ntent-Length: $size\n\n"; # here's the downloading part, no arrays needed while ($bytes = read($DLFILE,$buffer,16384)) { print $buffer; }
    That should do it.

    Tosh
Re: Binary output ot browser/force download?
by mfriedman (Monk) on Jul 24, 2002 at 20:57 UTC
    What MIME type are you sending in your headers? You'll need to send the appropriate type to get the browser to behave correctly. You'll also need to send a filename header unless you want the client machine to save the file as the name of your script.