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.