Laravel5.4 ファイル複数ダウンロード(画像でもテキストでも)


ファイルダウンロード処理の実装

主な方法
・Response::download
(サーバー上のファイルダウンロード)(IEだと文字化け可能性)
・Response::make()
(文字化けはないが、ファイル内容をキャストしてコピーするので、大容量には向かない)
・Storage::disk()->download (バージョン的に使えない)
・phpの処理で作る (カスタマイズできる)

ダウンロード参考記事
大容量・laravel・phpファイルダウンロード参考記事

今回は、ファイル内容はそんなに重くなく、また既にファイルの中身をバイナリデータで持っていたので、Response::make()を使用することにした。
(Storage->disk('s3')->get(ファイルパス)でバイナリデータは取得していた。)

$headers = [
                'Content-Type' => $mineType,
                'Content-Disposition' => 'attachment; filename="' . $fileName . '"'
           ];
return Response::make($fileBinaryData, 200, $headers);

これでファイルダウンロードは完了。

複数ダウンロードを実装する

{{Form::button('ダウンロード', ['class' => 'on-download'])}}
<script>
$('.on-download').on('click', function(){
    handleDownload("samplel1.jpg");
    handleDownload("samplel2.jpg");
    handleDownload("samplel3.jpg");
});

function handleDownload(name) {

    const route = "{{route(download)}}";

    // IE
    if (window.navigator.msSaveBlob) {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", route, true);
        xhr.responseType = "blob";
        xhr.onload = function (e) {
            var blob = xhr.response;
            window.navigator.msSaveBlob(blob, name);
        }
        xhr.send();
        return;
    }

    // chrome,firefox
    const a = document.createElement('a');
    a.download = name;
    a.href = route;

    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);


}
</script>

aタグのdownload属性を使用して、ダウンロード処理を実装する。download属性を持つaタグを生成してclickで実行させ、消すを繰り返す.
IEはdownload属性をサポートしていないので、一つのファイルがダウンロードされるくらいなので、IE用に処理を分岐させる。ダウンロードする画像数分タブが表示されては消えるようにしているため、msSaveBlobで保存する。

今回こうやって使用した

僕が今回実際に使ったときは、テーブルの行ごとの先頭にチェックボックスが存在し、チェックが入ったレコードのファイルだけをダウンロードさせるというものだった。

なので、checkboxにdata属性でfileIdとfileNameを渡す必要があった。ダウンロードボタンを押した瞬間に、checkが入ってるもののチェックボックスからfileIdとfileNameを取り出して、それをeach文で、handleDownload(fileId, fileName)(fileIdはrouteを生成するときにどのファイルをダウンロードさせるかを判定するためにくっつけて渡す)を複数回実行させることで、課題をクリアした。

aタグのdownload属性を使って、直接ファイルをダウンロードさせる方法もあるが、僕の場合ダウンロード履歴をDBに保存する必要があったため、いったんスクリプトを経由した。

参考記事

まとめ

複数画像ファイルをダウンロードさせることにすごいはまった。
つぎからはいけそう。
今度はダウンロード後を検知する方法を知りたいなぁ。