質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.10%

【PHP】 S3から複数のファイルを選択し、Zip化してダウンロードする機能はどうやって実現できるのか

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,754

score 11

実現したい機能

複数ファイルをZip化してダウンロードする機能を実装したいです。または、Zip化せずに複数ダウンロード機能を実装したいです。
やり方や参考になる記事をご存知でしたら教えていただけると助かります🙇‍♂️

試したこと

※全てCakePHPを使用して実装しています。

①foreach
すでに1つずつのファイルダウンロード機能が実装できているので、foreachで処理を回す。処理は1回目のダウンロード時に終わってしまいますのでこのやり方はできませんでした。

    if ($this->request->is(['patch', 'post', 'put'])) {
        $data = $this->request->data;
        $result = $this->Common->download($data['dl']);
        if ($result['error'] ==  true) {
            $this->Flash->error($result['message']);
            return $this->redirect([]);
        }
    }

    public function download($file_pass = '')
    {
        $params = [
            'Bucket' => S3_BUCKET_NAME,
            'Key' => $file_pass
        ];
        $file_name = str_replace('user_upload/', '', $file_pass);

        $s3 = new S3Client([
            'credentials' => [
                'key' => S3_ACCESS_KEY,
                'secret' => S3_SECRET_KEY
            ],
            'region' => S3_BUCKET_REGION,
            'version' => 'latest'
        ]);

        try {
            $result = $s3->getObject($params);
            $len = $result['ContentLength'];
            header('Content-Type: application/force-download;');
            header('Content-Length: '.$len);
            header('Content-Disposition: attachment; filename= '.$file_name);
            echo $result['Body'];
            return;
        } catch(S3Exception $e) {
            $return = [
                'error' => true,
                'message' => 'ダウンロードに失敗しました。'
            ];
            return $return;
        } 
    }

②記事を参考に

]header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="file.zip"');

require "./aws.phar";
use Aws\S3\S3Client;

$bucket = 'myBucket';

$client = S3Client::factory(array(
    'key'    => getenv('AWS_ACCESS_KEY_ID'),
    'secret' => getenv('AWS_SECRET_KEY')
));

$result = $client->getObject(array(
    'Bucket' => $bucket,
    'Key'    => 'test.txt',
    'SaveAs' => '/tmp/test.txt'
));

$Uri = $result['Body']->getUri();

$fp = popen('zip -r - '.$Uri, 'r');

$bufsize = 8192;
$buff = '';
while( !feof($fp) ) {
   $buff = fread($fp, $bufsize);
   echo $buff;
}
pclose($fp);


参照した記事

③ライブラリ
このライブラリで実現できるか検証しましたが、返り値がバイナリデータで上手く動作しませんでした。

何か方法やアイディアある方は教えていただけると助かります🙇‍♂️

参考にした記事

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/08/23 13:41

    >※全てCakePHPを使用して実装しています。
    CakePHPのタグを追加しておいてください。

    いずれにしても「一度のリクエストで複数ダウンロード」は無理なので(レスポンスヘッダの関係かなと)「ダウンロードしたいファイルをまとめての一つのzipにする」という話ですかね

    キャンセル

  • sawamu

    2019/08/23 14:14

    ありがとうございます!

    >「ダウンロードしたいファイルをまとめての一つのzipにする」
    はい、そういう意味です。

    >CakePHPのタグを追加しておいてください。
    タグの件、承知しました!

    キャンセル

回答 1

checkベストアンサー

0

複数ダウンロードさせるのであれば、フロント側でボタンを押したらJavaScriptでファイルごとにリクエストを発生させてダウンロードさせるといった手法になるかと思います。javascript 複数ダウンロード でググってみてください。

サーバー側でzip化してダウンロードさせるのであれば、S3からの取得はaws-sdkを使用するとして、zipの作成にはPHPのzip拡張に含まれる ZipArchive を使用したほうがいいでしょう。

PHP: ZipArchive - Manual https://www.php.net/manual/ja/class.ziparchive.php

ZipArchive::openで、ファイルを開いた後、addFromStringでS3からのファイルを追加していけばよいでしょう。その後ZipArchiveをcloseして、書き出したファイルを出力すればよいです。

CakePHPであれば、ダウンロードリクエスト用のメソッドが準備されていますのでそれを使用してください。

リクエストとレスポンスオブジェクト - 3.8 https://book.cakephp.org/3.0/ja/controllers/request-response.html#cake-response-file

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/23 17:30 編集

    ご丁寧にリンクなども貼っていただきありがとうございます!ご提案していただいた方法でやってみます🙏

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • PHPに関する質問
  • 【PHP】 S3から複数のファイルを選択し、Zip化してダウンロードする機能はどうやって実現できるのか