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

Hello Monks, I'm trying to use Archive::Zip with info given in the link to the cgi. The file to be zipped is already on the server http://domain.com/files/downloadazip.cgi?link=text.txt the perl code I'm using is...
#!/usr/bin/perl -w #use strict; use Archive::Zip qw(:ERROR_CODES :CONSTANTS); use CGI qw(:standard); if (param('link')){ my $id = param("link"); my $obj = Archive::Zip->new(); my $file_member = $obj->addFile( $id ); if ($obj->writeToFileNamed('download.zip') != AZ_OK) { print header; print "Bad something or other!"; } else { print header; print "<a href='download.zip'>archive created click to download</ +a>"; } }
When I run this I get a zip file with no contents. If I replace $id with "zipthis.txt" (the file on the server) everything works. I can't find an example of a program like this so I come the the mighty perl monks to answer my question and record an answer for others that may have this problem. Also, how would I make the perl file redirect to the zip file so it will download after the zip file is created? This will replace the else statement above. I tried
#my $query=new CGI; #print $query->redirect('http://domain.com/files/download.zip');
but I get a whole bunch of text instead of the option to save or open. Thank You.

Replies are listed 'Best First'.
Re: Archive::Zip with cgi empty zip file
by CSJewell (Beadle) on Mar 30, 2009 at 04:21 UTC

    For the redirection part, it's a poor idea to try and call the same module using both method and function calling. One or the other really needs to be chosen.

    Option 1: Make it all function calls by importing redirect, as well.

    #!/usr/bin/perl -w #use strict; use Archive::Zip qw(:ERROR_CODES :CONSTANTS); use CGI qw(:standard :nph redirect); my $id; if ($id = param('link')){ my $obj = Archive::Zip->new(); my $file_member = $obj->addFile( $id ); if ($obj->writeToFileNamed('download.zip') != AZ_OK) { print header(type => 'text/plain'); print "Bad something or other!"; } else { print redirect('http://domain.com/files/download.zip'); } }

    Option 2: Make it all method calls, by not importing any functions.

    #!/usr/bin/perl -w #use strict; use Archive::Zip qw(:ERROR_CODES :CONSTANTS); use CGI qw(:nph); my $q = CGI->new(); my $id; if ($id = $q->param('link')){ my $obj = Archive::Zip->new(); my $file_member = $obj->addFile( $id ); if ($obj->writeToFileNamed('download.zip') != AZ_OK) { print $q->header(type => 'text/plain'); print "Bad something or other!"; } else { print $q->redirect('http://domain.com/files/download.zip'); } }

    I've also done three other things:

    1. I made it a non-parsed-headers (nph) script. Otherwise, the first thing that is send by Apache (or other web servers) to your browser is a 200 OK header, as far as I can recall, and the redirect won't work. (When I write a script for my web server, I make it nph if I do anything other than output standard pages, so I'm not sure.) You'll need to tell your web server that it's a nph script. [For Apache, you just need to call it something that begins with 'nph-', I don't know about others.]
    2. I put the $id assignment in the if statement. That should work (I haven't -c checked this code) and it eliminates having to call CGI->param('link') twice.
    3. I assumed you were sending text to the browser, rather than HTML, for the error checking, since it didn't look like HTML. If it is, take out the type parameter.
      Thanks, I renamed the file to nph-zipdownloader.cgi, Added :nph and redirect to the use CGI statement and consolidated the if statement with the assignment to the variable as well as adding the print redirect stuff and everything works. The zip file even has the text file in it. Link to the code http://domain.com/nph-zipdownloader.cgi?link=test.txt Here's the final code.
      #!/usr/bin/perl -w use Archive::Zip qw(:ERROR_CODES :CONSTANTS); use CGI qw(:standard :nph redirect); if (my $id = param('link')){ $obj = Archive::Zip->new(); my $file_member = $obj->addFile( $id ); if ($obj->writeToFileNamed('download2.zip') != AZ_OK) { print header(type => 'text/plain'); print "Error in archive creation!"; #error checking } else { print redirect('http://domain.com/files/download2.zip'); } }
      This is great, there's so much more I'm going to do with this code now that its making the zip file with content.