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

Solved !

Ladies and Gentlemen, you REALLY made my day !
Thanks to all contributors !
Here is the working codesniplet:

sub download { use CGI; $html=new CGI; #print $html->header(-type => 'application/octet-stream', -attachment +=> $_[1]); print $html->header(-type => 'application/zip', -attachment => $_[1]); + open($peunter, "<", $_[0].$_[1]); binmode($peunter); binmode STDOUT; while (read($peunter,$bytes,1024)) { unless (eof()) { chomp($bytes); } print $bytes; } #@data = <$peunter>; close($peunter); #print "@data"; }
Sorting out the file structure exported in the zipfle downloaded, should be a matter of try and error...
Again: thanks a lot for all your hints !

Hello everybody ! First of all let me thank you for tons of hints and tips I have gathered from your forum already ! Yet today I am coming up with a question that I have been trying to look up for weeks, and in fact I did not even find my exact problem:

I am offering some files to download. In order to transport them all together in one leap my idea was to pack them in a zip-file, using archive::zip. Everything seems to be working just fine (no warnings, no errors, nothing) untill I try to open the zip file after the download. All programs on all platforms tested (Windows 7, 8, Mac OSX maverick) report a crc error, stating the files were corrupted. downloading the same files one by one, without zipping them works fine. I am posting my code cutting out those parts that deal with form data extraction and such stuff, assuming here can't be the reason.

#!/usr/bin/perl use warnings; use Archive::Zip qw(:ERROR_CODES :CONSTANTS); . . . use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); $zipName = "../downloads/".$verzeichnis."Download.zip"; $zip = Archive::Zip->new(); $index==0; foreach (@zumzippen) { ##use IO::Compress::Zip qw(:all); #use IO::Compress::Zip qw(:ZIP_CM_STORE); ##$status = zip [ @zumzippen ] => "../downloads/".$verzeichnis."Do +wnload.zip"; # , Autoclose => 1; #Method => ZIP_CM_DEFLATE , Level => + Z_NO_COMPRESSION; $member = $zip->addFile( $_ , @dateiliste[$index]); #$member->desiredCompressionMethod( COMPRESSION_STORED ); #$crc = $zip->computeCRC32( $zipName ); #$member->desiredCompressionLevel( 8 ); $index++; } # $zip->addTree("../downloads/$verzeichnis", "$verzeichnis"); #$status = $zip->writeToFileNamed("../downloads/".$verzeichnis.$zi +pName); $status = $zip->writeToFileNamed($zipName); }

As you can see, I also tried compress::zib with the same results. Any hints/help appreciated !

Thanks to Corion I can alter my question:
The zip file on disk is absolutely fine. Trouble starts when downloading it.
Sorry for confusing things and you guys !
Just in case you are not fed up with someone who doesn't even realise which script is causing the error,
Here comes the download script, again just the relevant part.:

#!/usr/bin/perl #use warnings; . . . sub download { use CGI; $html=new CGI; print $html->header(-type => 'application/octet-stream', -attachment = +> $_[1]); open($peunter, "<", $_[0].$_[1]); binmode($peunter); binmode STDOUT; while (read($pointer,$bytes,1024)) { print $bytes; } #@data = <$peunter>; close($peunter); #print "@data"; }

Replies are listed 'Best First'.
Re: CRC Error on ZIP Files
by hazylife (Monk) on Mar 01, 2014 at 16:09 UTC

    This might not be the cause of your problem, but still:

    $index==0;

    Shouldn't this read $index = 0; instead?

      Hi hazylife!

      you're right, it should indeed. Thanks for pointing out this one. Although you are also right in assuming this is not the cause of my problem. :-) Thanks a lot anyway !

Re: CRC Error on ZIP Files
by AnomalousMonk (Archbishop) on Mar 01, 2014 at 17:00 UTC

    Are you using warnings and strict? The code fragment you posted shows  use warnings; but the following suggests it's not used | there or has been disabled:

    c:\@Work\Perl\monks>perl -wMstrict -le "my $index; $index == 0; ;; my @ra = qw(foo bar); print $ra[$index]; " Useless use of numeric eq (==) in void context at -e line 1. Use of uninitialized value $index in numeric eq (==) at -e line 1. Use of uninitialized value $index in array element at -e line 1. foo

    use warnings; and  use strict; may help you find many instances of questionable code.

    Another question comes to mind about the 'download' method you are using. If a text file is downloaded via a channel that automatically corrects line endings (e.g., cr-lf versus lf), the file will visually appear unchanged, but a binary file may be (almost certainly will be if it's big enough) corrupted. If you're using FTP, are you using ascii or binary mode?

      Hi AnomalousMonk,

      thanks for your reply !
      Warnings seem to be disabled somehow, since I am not receiving any of these
      when running the script. Yet I am aware of the fact, that I should use "strict".
      I must admit that I did not get rid of the bad habit of not declaring my
      variables throughout all these years ...

      To reply to your question: I think (!) I am not using FTP, since I am offering
      and sending the file through the recipients browser. For that I am switching binary
      mode on. Here is the critical code of the prescript running the download.

      sub download { use CGI; $html=new CGI; print $html->header(-type => 'application/octet-stream', -attachment = +> $_[1]); open($peunter, "<", $_[0].$_[1]); binmode($peunter); # while (read($pointer,$bytes,1024)) { # print $bytes; # } @data = <$peunter>; close($peunter); print "@data"; }

        If you are on Windows, you really need to

        binmode STDOUT;
        before printing. On all other operating systems, it's still good practice. Maybe try that, and alternatively, first create the ZIP file on disk, and manually download it through a trusted, different way, just to make sure that the ZIP file itself is not corrupted.

        Apart from Corion's suggestion to include binmode STDOUT (which I think really might be an issue, even if it's not the only issue), you may also want to try:
        print $html->header(-type => 'application/zip', … );
        At least, according to Wikipedia, zip file format is "registered" as an official MIME type.

        Update: I actually don't know whether fixing the mime-type label will make any difference. I'm guessing that the issue is whether or not a carriage-return byte gets added before each line-feed byte, possibly at the receiving end, if not at the transmission end. Note the exact byte count for the original (working) zip file, then compare that to the exact byte count of a downloaded version; if the latter is bigger, there's something like a "unix2dos" filter kicking in at some point in the download process, and that will certainly screw up the zip file.

        print "@data";
        This is your problem. Consider this code:
        $ perl -E'@a=qw/1 2 3/; print "@a"' 1 2 3
        You wanted to print your lines joined by empty string, but "@array" joins array elements with space (read $" for more info on that). Your original, commented-out approach is better: just read your file by, say, 10 kilobytes and immediately send the data to client:
        { local $/ = \10240; print while <$peunter>; }
        In this example I tell Perl to read files with diamond operator (<$filehandle>) by 10240 bytes ($/) and loop printing the file pieces until I reach end-of-file.

        Edit: corrected typo
Re: CRC Error on ZIP Files
by hazylife (Monk) on Mar 02, 2014 at 12:08 UTC
    You might also want to fix the pointer/peunter thing:
    open($peunter, "<", $_[0].$_[1]); # ^^^^^^^^ ... while (read($pointer,$bytes,1024)) { # ^^^^^^^^
Re: CRC Error on ZIP Files
by hazylife (Monk) on Mar 04, 2014 at 11:09 UTC
    Solved !

    SearchigPerl, are you still there? The updated snippet is not entirely correct; in particular, this chomp is a disaster waiting to happen:

    while (read($peunter,$bytes,1024)) { unless (eof()) { chomp($bytes); } print $bytes; }

    $bytes is a binary string, and it might just happen to have a trailing newline that chomp would happily remove, giving you a corrupted ZIP again. And the eof() check is entirely wrong (see the docs, particularly that bit about eof() being a special case).

    There is nothing fundamentally wrong with your original loop:

    while (read($peunter,$bytes,1024)) { print $bytes; }
    So I'd just go with that.
      Hi hazylife,

      yes, I am still there - meaning here, just had to deal with some other major problem on my machine.
      Thanks for your hint, I digged into the documentation regarding the eol subject.
      I am not quite sure whether or not I really got the point. What I learned is, that obviously
      eol is far away from being reliable to determine the last buffer of the file to be transported.
      Yet what I had to realize is that if I go with the original version of the code, I end up
      with a downloaded file showing some more bytes than the original file is showing.
      If I chomp all buffers I end up with a file showing exactly 1 byte less than the original file.
      I tried to determine the last buffer to be transported by it's length. But the result is kind of erratic.
      2 out of three files end up corrupted ... The current version seems to be the only one working fine.
      (on various kinds of files (such as excel files, jpegs, mp4)
      Do have any idea, what I am doing wrong ?

      Cheers
        I'm out of ideas, sorry. If the eof()/chomp construct does actually help, then it would probably be best to leave it be it's a clear sign that some other part of the code is broken. Could you maybe post your whole script somewhere (e.g. pastebin.com, pastie.org, your public scratchpad etc.)?