はじめに
この記事が私の初投稿になります。
アウトプットの機会を増やしていくため、継続的に記事を書いていこうと思います。
今回は実際の業務で苦戦した「マルチパートアップロードを使用したAWS S3へのファイル保存」についてです。
この辺のトピックはネットの情報が古かったり有益な情報に出会えなかったため、私と同じような状況の方の手助けになれば幸いです。
また間違いなどがございましたら、ご指摘のほどよろしくお願い致します。
背景
私が業務でS3を使用した背景ですが、以下のような理由から採用することにしました。
※S3の詳細は割愛しますが、サーバーとは別のところにファイルを保存したい場合に使用するドライブみたいなものですかね!(ざっくりしすぎかな、、、)
- 容量が1GBを超える動画コンテンツを扱うため
- S3に置いたコンテンツはCloudFront(詳細は公式を参照してください)経由で高速でアクセスできるため
実行環境など
- PHP8.2
- Laravel10
- MySQL
- EC2
- RDS
- S3
- github
などなど。
S3のバケット作成やcloudfrontのディストリビューションは作成済みの前提で記載します。
マルチパートアップロード
今回のwebアプリはS3へ動画をアップしてそこから配信したわけですが、LaravelでのS3アップロード処理は以下のように非常にシンプルに記述できるようになっています。
Storage::putFile('s3', $request->file('inputタグのname属性値'));
しかし、容量がせいぜい1MBにも満たないような軽量ファイルなら上記で全然OKなのですが冒頭でも記載した通り、扱うコンテンツが1GBを超えてくるので上記の方法では処理時間が長くなるだけでなく、リクエストタイムアウトやCPU負荷など様々なネガティブ要素が出てきてしまいます。
そこで登場するのがマルチパートアップロードです!
詳細はこちらに記載の通りです。これを使えば処理時間も早くなりかつ大容量のファイルも扱えます。(公式によると最大5TBのファイルまでOKだそうです笑)。原理としては大きなファイルを手元で分割してS3へアップしていき、最後に結合する処理をSDKとして行ってくれます。(ありがたい!!)
処理例
前置きが長くなりましたが、ここで具体例を記載していきます。実際のプロダクトのコードは載せれないので、それに近い記載をしています。
// S3への保存
$file = $request->file('適宜差し替え');
if (!$file->isValid() || !file_exists($file->getRealPath())) {
return \back()->with('message', 'アップロードに失敗しました ');
}
$contents = fopen($file->getRealPath(), 'r');
$s3Client = App::make('aws')->createClient('s3', [
'region' => env('AWS_DEFAULT_REGION'),
]);
$key = 'ここはS3オブジェクトを格納するパスを指定';
$uploader = new MultipartUploader($s3Client, $contents, [
'bucket' => env('AWS_BUCKET'),
'key' => $key,
'ACL' => 'public-read',
'ContentType' => $file->getMimeType(),
]);
try {
$result = $uploader->upload();
// matadataの更新
$copyResult = $s3Client->copyObject([
'Bucket' => env('AWS_BUCKET'),
'Key' => $key,
'CopySource' => env('AWS_BUCKET') . '/' . rawurlencode($key),
'ACL' => 'public-read',
'ContentType' => $file->getMimeType(),
'MetadataDirective' => 'REPLACE'
]);
} catch (MultipartUploadException $e) {
echo $e->getMessage() . "\n";
}
SDKの導入はこちらを参照しました。
上記コードのポイントとしてはまず以下の記述です
$s3Client = App::make('aws')->createClient('s3', [ 'region' => env('AWS_DEFAULT_REGION'), ]);
Laravel標準のAppクラスによってS3クライアント情報を作成できます。
マルチパートアップロードを実施しているのは以下の記載です。
$result = $uploader->upload();
また、この直後にメタデータの更新を行っている理由ですが、マルチパートアップロードを行うと動画ファイルのmimeTypeがvideo/mp4となっていないためここで書き換えています。
(もっと最適なやり方ご存じの方いましたらご教示いただけると幸いです。)
上記でS3へのアップができるかと思います!
最後に
今回はlaravel側の設定やS3の設定はネット上に沢山記事があるため割愛しました。
アプリ側の記述に関してはあまり記事が見当たらなかったのでそこにフォーカスして書きました。
最後まで目を通していただきありがとうございます!!