Archive::Zip を CGI で使う

Archive::Zip を使って、zip ファイルから jpg ファイルを取り出して、ブラウザに返す CGI の例です。


(ただしここでは、カレントディレクトリに Img0051.zip というファイルがあり、その中には DSCN1182.JPG というファイルが格納されているものとします。)

#! /usr/bin/perl

use Archive::Zip;

my $ZIP_FILE_NAME = "Img0051.zip";
my $MEMBER_FILE_NAME = "DSCN1182.JPG";

my $zip;
$zip = Archive::Zip->new();
$zip->read($ZIP_FILE_NAME);

print "Content-type: image/jpeg\n\n";
print $zip->contents($MEMBER_FILE_NAME);


read 関数で zip ファイルを指定する際や、contents 関数でメンバファイルの中身を取り出す際には、それらがうまく行ったかどうかのチェックがほんとうは必要です。ここでは端折ってます。


それ以外にもこのプログラムには問題があって、print $zip->contents($MEMBER_FILE_NAME); のところが、一旦 DSCN1182.JPG の中身を全部メモリに溜め込んで、それを print 文で吐き出すという仕組みになってしまっています。DSCN1182.JPG のサイズが非常に大きい場合に、Perl にそのぶんのメモリを用意させることになります。


次の例では、DSCN1182.JPG の内容をちょっとづつ読んでは吐き出すようにしています。

#! /usr/bin/perl

use Archive::Zip qw(:CONSTANTS);
use strict;

my $ZIP_FILE_NAME = "Img0051.zip";
my $MEMBER_FILE_NAME = "DSCN1182.JPG";

my ($zip, $member, $bufferRef);
$zip = Archive::Zip->new();
$zip->read($ZIP_FILE_NAME);
$member = $zip->memberNamed($MEMBER_FILE_NAME);
$member->desiredCompressionMethod(COMPRESSION_STORED);
$member->rewindData();
print "Content-type: image/jpeg\n\n";
while (! $member->readIsDone()) {
    ($bufferRef) = $member->readChunk();
    print $$bufferRef;
}
$member->endRead();


「ちょっとづつ読んでは吐き出す」の「ちょっとづつ」がどれくらいの大きさなのか、は次のようにするとわかります。

%perl -e "use Archive::Zip; print Archive::Zip::chunkSize()"
32768


デフォルトでは、32768 バイト (32KB) のようです。