Link to home
Start Free TrialLog in
Avatar of marcparillo
marcparillo

asked on

Download multiple files with Perl

Im in a bind with downloading files.  I want the website visitor to click a series of boxes depending on what files they want to download and send the request to a Perl script to initiate the download.  I have a perl script that will download one file -- it works.   Is there a way to download an entire folder containing several files?  I've also tried using Archive::Zip to place all the requested files into one zip file to download, but that may be an unnecessary step.  Another problem with Archive::Zip:  the files, once downloaded, reveal the folder structure of my server -- probably not a good idea.

Can anyone suggest a secure and reliable module, if one exists, that will initiate the download of several requested files at the same time?

Thanks.


Avatar of jhurst
jhurst

This is not really a perl question as much as an html protocol question.  

Sadly the answer is sort of NO.

The hrml protocol returns a response.  Not the "a" response.

There are kluges, such as mime, etc but realistically your zip approach is the best choice since none of the kludges is reliable and cross platform
Will Archive::Zip still reveal the directory structure if you chdir() into the appropriate directory before calling addFile for the file?
Avatar of marcparillo

ASKER

mjcoyne -- your suggestion worked.  Hadn't thought of chdir() into the appropriate directory.
Is it possible to chdir() a couple of different places in the same script?

The files to download are in separate folders.  Is it possible to chdir() around the server and collect files to download?
When I try this -- I get an Internal Server Error.
(I suppose I could also move all the folders I want into the same folder before building the zip file and then download the files, but it would be nice to move around the server)


#head on over to FOLDER1 add a bunch of files stored in an array
chdir ('/var/www/vhosts/mydomain.com/httpdocs/FOLDER1/');
foreach $i (@file){
  $zip->addFile("$i");
}
#now go to a different directory and add one more file from FOLDER2
chdir ('/var/ww/vhosts/mydomain.com/httpdocs/FOLDER2/');
$zip->addFile("$anotherfile.txt");
            
die 'Cannot create $zip_file_name: $!\n' if $zip->writeToFileNamed("$zip_file_name") != AZ_OK;
you can change directory as many times as you need in the script.

Sounds like you have a solution here.
Here's the script that works -- with only chdir one time -- in case anyone's interested:

#!/usr/bin/perl

use CGI;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS ) || die "Can't find Module";
my $zip = Archive::Zip->new();
my $q = new CGI;

my $i;

#read in variables, including an array of files
my @file = $q->param('file');
my $file2 = $q->param('file2');
my $zip_file_name="MyFiles.zip";


#chdir into appropriate directory
chdir ('/var/www/vhosts/mydomain.com/httpdocs/FOLDER1/');

foreach $i (@file){
  $zip->addFile("$i");
}

#add a different file from a different folder
$zip->addFile("FOLDER2/$script.txt");
            
die 'Cannot create $zip_file_name: $!\n' if $zip->writeToFileNamed("$zip_file_name") != AZ_OK;

#start downloading
$path = '/var/www/vhosts/mydomain.com/httpdocs/FOLDER1/';
$filepath = "$path$zip_file_name";
my $size= -s $filepath;
my $buff;

print "Content-type: application/forced-download\r\n";
print "Content-Length: $size\r\n";
print "Content-disposition: attachment;filename=$zip_file_name\r\n\r\n";
open(FILE, "<$filepath") || die;
binmode FILE;
binmode STDOUT;
while (read FILE, $buff, 1024) {
 print $buff;
}
close(FILE);

jhurst -- do you know why I would get an Internal Server Error when I try to chdir a couple of times in the same script?
no, it makes no sense that you get that internal server error.

I wonder if you are trying to change to some directory that is not permitted though.  

I suspect that you may be running on a Microsoft server and "enough said" if that is the case.
I get a Premature End of Script Headers when I try to

chdir('/path/to/one/folder/');

and then

chdir('/path/to/a/different/folder/');

It's a unix server -- I'll check the permissions again -- but I'm in the httpdocs directory so all should be okay.

is it apache ?

If so this is VERY strange.  I would just expect that an attept to change to a directory that is not permitted would just fail in perl.  The one thing that I do see that is different in what you do and when I do when I user chdir, is that I do not have the trailing /.  This does not mean that you are wrong, or even that I am right, it is just something that I note is different.
SOLUTION
Avatar of mjcoyne
mjcoyne

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Avatar of Tintin
Tintin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
kblack05.

perldoc CGI::Carp

Thanks Tintin, I am aware, however this method will also redirect console and syslog errors and give a logged record.

Regards
Thanks everyone.
I can now chdir freely and I learned a few things about error tracing.

I'll split up the points.