david.woosley has asked for the wisdom of the Perl Monks concerning the following question:

Hi.

I'm working on a Linux server that hosts a website using Perl.

I need to download a file to the browser like downloads normally work. The page doesn't change, and the file is immediately downloaded when the user clicks on a link. There are hundreds of thousands of files, and which file gets downloaded depends on the Linux relative path. I do not know the file type. For example, the URL might look like this:

https://www.my-website.com/download.pl?file=path1/path2/filename.ext

What is the Perl code that will accomplish this? I've search the web, and I cannot find a definitive answer. At least not an answer that I understand.

I am not an experienced Perl programmer. Any help will be appreciated.

Thanks,

David

Replies are listed 'Best First'.
Re: Download file to browser
by Corion (Patriarch) on Apr 19, 2024 at 15:41 UTC

    When the browser requests https://www.my-website.com/download.pl?file=path1/path2/filename.ext , you need to respond with the Content-Disposition header. Depending on what way you use to send headers, this might need different code. For Mojolicious, you send headers like the following:

    use File::Basename 'basename'; ... # Serve static file if it exists if (my $asset = $c->app->static->file('path1/path2/filename.ext')) { $c->res->headers->content_disposition('attachment; filename=filena +me.ext'); $c->reply->asset($asset); }
      Hi Corion. What is the $c variable? Please understand that I'm novice Perl programmer. Thanks, David

        The $c variable is the context in Mojolicious. As you don't seem to be using Mojolicious, maybe you can tell us or even better show us the relevant parts of download.pl so we can better tell you how to add the header.

        Please understand that I'm novice Perl programmer. Any help will be appreciated.

        To take your novice Perl skills out of the equation, please take the time to read and understand the following non-Perl references:

        If you're then convinced of the merit of at least attempting to create a minimal reproducible example, have a go at doing that in Perl (you might find Short, Self-Contained, Correct Example useful in this endeavour). If you get stuck, please feel free to ask for assistance, we will be glad to help.

        Attempting to create a minimal reproducible example (even if unsuccessful) should have an added benefit of improving your general Perl skills and knowledge.

        👁️🍾👍🦟
Re: Download file to browser
by cavac (Prior) on Apr 20, 2024 at 22:39 UTC

    Well, if you do not know the file type, assume MIME type "application/octet-stream". It's basically the same as saying to the User Agent (a browser in your case): "Here's some binary stuff of unspecified type".

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
Re: Download file to browser
by TheloniusMonk (Sexton) on Apr 22, 2024 at 12:26 UTC
    Perhaps you found an example like this:
    use CGI; my $html= new CGI; #get the file name from URL ex. http://<server_IP>/cgi-bin/download.cg +i?a=testing.txt my $file= $html->param('a'); # $file is nothing but testing.txt my $filepath= "/var/www/upload/$file"; print ("Content-Type:application/x-download\n"); print "Content-Disposition: attachment; filename=$file\n\n"; open FILE, "< $filepath" or die "can't open : $!"; binmode FILE; local $/ = \10240; while (<FILE>){ print $_; } close FILE; # use Unlink if u want to delete the files after download. #unlink ($filepath);
    There are quite a lot of things to understand and we can't help unless you tell us which pieces you need help with!

      Why do you call print with brackets then again without?

      print ("Content-Type:application/x-download\n"); print "Content-Disposition: attachment; filename=$file\n\n";

      Update: Looks like a copy/paste from SO https://stackoverflow.com/questions/15294815/perl-cgi-to-download-a-file-via-web-browser:

      use CGI; my $html= new CGI; #get the file name from URL ex. http://<server_IP>/cgi-bin/download.cg +i?a=testing.txt my $file= $html->param('a'); # $file is nothing but testing.txt my $filepath= "/var/www/upload/$file"; print ("Content-Type:application/x-download\n"); print "Content-Disposition: attachment; filename=$file\n\n"; open FILE, "< $filepath" or die "can't open : $!"; binmode FILE; local $/ = \10240; while (<FILE>){ print $_; } close FILE; # use Unlink if u want to delete the files after download. #unlink ($filepath);

      Ignoring the comment from davorg:

      "Oops. I moved the articles around a bit. The link is not dead; it tells you where to go - perlhacks.com/articles/cgi-programming/cgi-programming-part-2. But to summarise, if I send you a file parameter of "../../../etc/passwd", you send me the file that contains all of your passwords for me to crack at my leisure. – Dave Cross Jan 19, 2017 at 5:56"

        That worked great. Thanks so much, folks. I appreciate your efforts more than you can imagine.
      A reply falls below the community's threshold of quality. You may see it by logging in.