90
90

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

S3から直接ダウンロードさせるときにファイル名を差し替える

Last updated at Posted at 2013-11-26

ユーザにAmazon S3からファイルを直接ダウンロードしてもらいたいことがありますが、その際にファイル名を差し替えたいこともあります。
調べたところ、S3には、ファイル名を差し替えるための機能が用意されていました。
権限まわりの仕様を知らなくて少し手間取ったので、今回はそのあたりの内容を交えてメモします。

追記: LaravelのFilesystemを利用している場合はこのメソッドを使うと一発でPre-Signed URLを発行したりダウンロード時のファイル名を指定したりできます。v5.4あたりで追加されたようです。

どんな機能が用意されているか

S3のオブジェクトは、以下のようなURLを使ってGETで取りにいくことができますが、

  • http://[bucket].s3.amazonaws.com/[key]

イメージとしては、URLに次のような感じでリクエストパラメータを含めると、ファイル名を差し替える(レスポンスヘッダをカスタマイズする)ことができます。(関連ドキュメントはこちら)

  • http://[bucket].s3.amazonaws.com/[key]?response-content-disposition=[filename]

ただし、これだけだと権限エラーになります。
これについて、ドキュメントには以下のような注釈があります。

You must sign the request, either using an Authorization header or a Pre-signed URL, when using these parameters. They can not be used with an unsigned (anonymous) request.

どうやらanonymousユーザはリクエストパラメータを使えないらしく、これは対象のオブジェクトが一般公開されていたとしても変わりません。リクエストをSignする必要があります。

リクエストをSignする

というわけでリクエストをSignします。(関連ドキュメントはこちら)
Signするには、AWS SDKのgetObjectUrl()を使います。

PHP版の例
$client = S3Client::factory(array(
    'key'    => [access_key],
    'secret' => [secret_key]
));
$opt = array("ResponseContentDisposition" => 'attachment; filename="[filename]"');
$url = $client->getObjectUrl($bucket, '[key]', '[expiration]', $opt);

こうすると、次のようなURLが作られます。

  • https://[bucket].s3.amazonaws.com/[key]?response-content-disposition=attachment%3B%20filename%3D%22hoge%22&AWSAccessKeyId=&Expires=1111&Signature=

このURLにアクセスすれば、ファイル名が差し替わった状態でダウンロードすることができます。

なお、URLにはAccessKeyIdが含まれています。これは、リクエストを事前にSign(Pre-Signed URL)した場合には必ず含まれるようですが、シークレットアクセスキーがなければ何もできないので公開しても問題ないようです。それでも「なんか気持ち悪い」と感じる場合は、何の権限ももたないか、あるいはread権限のみがあるIAMアカウントを作ってそれでSignしても良いかもしれません。

日本語のファイル名を扱う

Content-Dispositionは以下のようにして日本語のファイル名を扱うことができます。

Content-Disposition: attachment; filename*=UTF-8''[UTF-8のファイル名をURLエンコードしたもの]

ただし、こちらのテスト結果を見る限りではIE8はこの方法では対応できないようです。
IE8の場合のみShift-JISを使えば良さそうですが、そうすると今度はAmazon側が対応していないような気もします。
※このあたりはちょっとまだ検証しきれていません(すみません)

90
90
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
90
90

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?