はじめに
こんにちは!開発チームの遠藤です。
S3 Presigned URLを用いたファイルアップロードの実装例を紹介したいと思います!
S3 Presigned URL (署名付きURL) とは
AWSのストレージサービスであるS3の機能の一つで、
一時的なアクセス権の付与や細かいアクセス制御を行うことができ、
サービス利用するファイルに対して、セキュリティを高めたい場合に効果的です。
詳細は、公式ドキュメントをご覧下さい。
本記事でのS3 Presigned URL発行の流れ
本記事では、APサーバーでの処理は署名付きURL含むアップロードに必要なパラメータの発行のみを行い、ファイルアップロードはAPサーバーを通して行わずクライアントから直接S3にリクエストしています。この構成のメリットは、APサーバーの帯域負荷を軽減できることです。

サーバーコード例
署名付きURL含むアップロード/ダウンロードに必要なパラメータの発行処理のPHPでのコード例です。定数やオブジェクトキーは、ご自身の環境に合わせて読み換えて頂ければと思います。
class S3Adapter
{
  private const BUCKET = "xxxxx";
  private const PRESIGNED_EXPIRED_TIME = "+60 minutes";
  public function __construct(private \Aws\S3\S3Client $s3Client)
  {
  }
  public function createUploadPreSignedParams(): array
  {
    // 一意のバケット内のオブジェクトキーを生成
    $key = (string) \Illuminate\Support\Str::ulid();
    $command = $this->s3Client->getCommand("PutObject", [
      "Bucket" => self::BUCKET,
      "Key" => $key,
    ]);
    $request = $this->s3Client->createPresignedRequest(
      $command,
      self::PRESIGNED_EXPIRED_TIME
    );
    return [
      "key" => $key,
      "url" => (string) $request->getUri(),
    ];
  }
  public function createDownloadPreSignedURL(string $key): string
  {
    $command = $this->s3Client->getCommand("GetObject", [
      "Bucket" => self::BUCKET,
      "Key" => $key,
    ]);
    $request = $this->s3Client->createPresignedRequest(
      $command,
      self::PRESIGNED_EXPIRED_TIME
    );
    return (string) $request->getUri();
  }
}クライアントコード例
// fetchするurlは、上記サーバーコード例の実行結果を返すエンドポイント
const { url, key } = await fetch("/api/s3_signature/").then((res) => res.json());
const file = new File(["foo"], "foo.txt", { type: "text/plain" });
await fetch(url, {
  method: "PUT",
  headers: { "Content-Type": file.type, "X-File-Key": key },
  body: file,
});S3バケットのアクセス許可設定
ブラウザから直接アップロードしているので、S3でのCORS設定が必要になります。
設定方法は、公式ドキュメントをご覧下さい。
最後に
S3 Presigned URLは、AWSが提供しているSDKを用いれば簡単に実装できるので、AWSユーザーは是非使用してみてください!特に、会員制サービスにおけるファイル添付機能には効果的だと思われます!
 
         
         
        
       
              
             
              
            