[PHP]AWS S3から複数ファイルをzipダウンロードする
AWS SDK for PHP バージョン 3 で AWS S3 から複数のファイルを ZIP にしてダウンロードする方法。
PHP の拡張ライブラリ ZipArchive を使っても ZIP ダウンロードはできるけれど、 maennchen/ZipStream-PHP というライブラリを使うと簡単に実装できるので、 maennchen/ZipStream-PHP の使い方。
ZipStream-PHP とは
PHP の ZIP ストリーミングライブラリ。
maennchen/ZipStream-PHP
バージョン 1.0.0 以上は PHP 7.1 以降が必須。
バージョン 0.5.2 は PHP 7.0 以降が必須。
おすすめの理由
ストリーミングでファイルを読み込み、圧縮して、ダウンロードさせるとこまでやってくれる。
ストリーミングなので、サーバーに一時ファイルが生成されない。メモリを大量に消費しない。
「 S3 対応」と謳っている。
ZipStream-PHP の使い方
PHP 7.0 の環境しかなかったため、バージョン 0.5.2 の使い方。
バージョン 1 系とは options の指定の仕方が異なる。
All options parameters to all function have been moved from an array to structured option objects.
composer でインストール
$ composer require maennchen/zipstream-php
S3 から複数ファイルをダウンロードするサンプルコード
// ライブラリをロードする
require 'vendor/autoload.php';
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
$bucket = "YOUR-BUCKET-NAME";
// S3 インスタンスの生成
$s3Client = new S3Client([
'version' => 'latest',
'region' => 'YOUR-REGION'
]);
// Amazon S3 ストリームラッパーを登録
$s3Client->registerStreamWrapper();
// 画面から送られてきたファイル名のリスト(チェックボックスでダウンロードしたいファイル名を選択)
$keyList = filter_input(INPUT_POST, 'hoge', FILTER_DEFAULT,FILTER_REQUIRE_ARRAY);
// ZIP ファイル名
$zipName = 'ZIP-FILE-NAME.zip';
// オプション設定
$options = array(
'content_type' => 'application/zip',
'comment' => 'this is a TEST'
);
// ZipStream インスタンス生成
$zip = new ZipStream\ZipStream($zipName, $options);
foreach ($fileList as $key) {
$file = "s3://" . $bucket . "/" . $key;
//addFileFromStream
if ($streamRead = fopen($file, 'r')) {
$zip->addFileFromStream($key, $streamRead);
fclose($streamRead);
} else {
throw new RuntimeException('Could not open stream for reading');
}
}
// ZIP ストリームを閉じる
$zip->finish();
説明
ZipStream
インスタンス生成時に、第一引数に ZIP ファイル名と、第二引数にオプション設定の配列を渡す。
第二引数は省略可。
addFileFromStream()
の第一引数が、 ZIP の中のファイル名となる。ディレクトリを含めてもいい。
Content_Type
に指定される MIME タイプのデフォルトは 'application/x-zip'
になっている。
$options
で、 HTTP ヘッダの 'Content-Type'
と 'Content-Disposition'
、コメントなどを指定できる。
$headers = array(
'Content-Type' => $content_type,
'Content-Disposition' => $disposition,
'Pragma' => 'public',
'Cache-Control' => 'public, must-revalidate',
'Content-Transfer-Encoding' => 'binary'
);
$disposition
はこうなってる。
$disposition .= "; filename=\"{$this->output_name}\"";
ZIP ファイル名が日本語だと IE や Edge では文字化けする。。。
日本語ファイル名を使えるようにする ( IE , Edge 対応)
IE , Edge で日本語ファイル名を扱うには、 HTTP ヘッダで Content-Disposition: attachment; filename*=UTF-8''URLエンコードしたファイル名
を送る。
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($filename));
だがしかし、下記のコードとなっているため、オプションで filename
の後に *=UTF-8
とかを追加できない。
$disposition = 'attachment';
if (isset($opt[self::OPTION_CONTENT_DISPOSITION])) {
$disposition = $opt[self::OPTION_CONTENT_DISPOSITION];
}
if ($this->output_name) {
$disposition .= "; filename=\"{$this->output_name}\"";
}
なので、 vendor/maennchen/zipstream-php/src/ZipStream.php を修正した。 569 行あたり
if ($this->output_name) {
//$disposition .= "; filename=\"{$this->output_name}\"";
$urlencoded = rawurlencode($this->output_name);
$disposition .= "; filename*=UTF-8''{$urlencoded}";
}