はじめに
LaravelでAmazon S3からファイルを非同期でダウンロードする方法をご紹介します。
環境
- PHP 8.0.16
- Laravel Framework 9.6.0
PHP
public function fileDownload(Request $request) { $filePath = $request->input('filePath'); $s3 = Storage::disk('s3'); if (!$s3->exists($filePath)) { // ファイルが存在しない場合の処理(例外を投げるなど) } // ファイルのMIMEタイプを取得 $mimeType = $s3->mimeType($filePath); // S3から取得したファイルをJSONで送信するためにBase64でエンコード $result = base64_encode($s3->get($filePath)); return [ 'result' => $result, 'type' => $mimeType ]; }
ポイントは、S3から取得したファイルをBase64でエンコードしているところでしょうか。
JSONはバイナリデータに対応していないようなので、
バイナリデータのファイルをBase64でエンコードすることで、
JSONでファイルを送信することを実現しています。
JavaScript
$.ajax({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, url: 'sample/url', type: 'POST', data: { filePath: 'sample/file.jpg' } }).then(response => { const arrBuffer = base64ToArrayBuffer(response.result); // Base64をArrayBufferに変換 const mimeType = response.type; const blob = new Blob([arrBuffer], {type: mimeType}); // ArrayBufferでBlobオブジェクトを作成 const link = document.createElement('a'); link.download = 'file.jpg'; // ファイル名を指定 link.href = URL.createObjectURL(blob); // オブジェクトURLを作成 link.click(); URL.revokeObjectURL(link.href); // オブジェクトURLを解放 }).catch(error => { // エラー処理 }); /** * Base64をArrayBufferに変換 */ function base64ToArrayBuffer(data) { const binaryStr = atob(data); // Base64のデータをデコード const binaryLen = binaryStr.length; const bytes = new Uint8Array(binaryLen); for (let i = 0; i < binaryLen; i++) { bytes[i] = binaryStr.charCodeAt(i); } return bytes; }
Base64でエンコードされたファイルをデコードしたデータでBlobオブジェクトを作成したところ、
ファイルが破損して正常にファイルをダウンロードすることができなかったので、
Base64でエンコードされたファイルをデコード、
そして、それをArrayBufferに変換したデータでBlobオブジェクトを作成したところ、
正常にファイルをダウンロードすることができました。