はじめに
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オブジェクトを作成したところ、
正常にファイルをダウンロードすることができました。