LoginSignup
22
21

More than 5 years have passed since last update.

ブラウザからAmazon S3に直接POSTする(Uploadify3.2を利用)

Last updated at Posted at 2013-03-14

ユーザにブラウザから直接S3にアップロードして欲しいことってあるよね〜
…と思ってググったところ、S3はpostでのアップロードを受け付けてくれるらしい。

Browser-Based Uploads Using POST

というわけでやってみよう。
今回は、UploadifyというFlash製のアップローダを利用した。

1.事前準備

はじめに、ブラウザからS3に何をPOSTするのかを確認しておこう。
まず、formのpost先から。

action="http://[bucket].s3.amazonaws.com/"

次にpostする内容。
主に使いそうなものは以下で、ほかにもこのページに全要素の一覧がある。

postする主な要素 必須 補足
AWSAccessKeyId
acl アクセス権限。private, public-readなど。
key 保存先のフルパス。${filename}を指定するとアップロード元のオリジナルのファイル名が使われる。
policy ポリシードキュメント。JSONで書いて、Base64でエンコードする。匿名で書き込み可能なbucketはpolicyなしでもOK。
signature ポリシードキュメントに対するsignature。HMAC SHA-1を使って、policyをSecret Keyでsignする。こちらもBase64でエンコード。
success_action_redirect アップロード後のリダイレクト先URL。
success_action_status アップロード後にリダイレクトしない場合の、S3からのレスポンスのフォーマットを指定する。Flashの場合は201を推奨とのこと。(Flashはバージョンによっては空bodyのレスポンスを正しく処理できない)

2.crossdomain.xmlの配置

今回利用するUploadifyはFlash製だが、Flashはセキュリティポリシー上、swfから自身の設置されたドメインの外にはアクセスできないようになっている。これを回避するためにcrossdomain.xmlを配置しよう。参考リンク

対象のbucketのルートにcrossdomain.xmlを配置

crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false" />
</cross-domain-policy>

crossdomain.xmlを「パブリックに公開」

crossdomain.xmlがswfから見える必要があるので公開設定にしておく。

3.policyとsignatureを作る

policyとsignatureを作って渡すことで、S3側での認証を行う。
匿名で書き込み可能なbucketの場合はこれらは不要らしいが、さすがに誰でもアップロードできてしまうのはまずそうなので作ることにする。

policyは都度生成し、毎回24時間後に有効期限が切れるように設定、とかが良いのかなあ。良い感じの運用方法をご存知の方は教えてもらえると嬉しいです。

policy

policyには、有効期限(expiration)と条件(conditions)が含まれる。
以下のようにJSONで記述し、base64エンコードして渡す。

{ "expiration": "2013-03-15T09:00:00.000Z",
  "conditions": [
    {"acl": "authenticated-read"},
    {"bucket": "bucket-name"},
    ["success_action_status' => "201"],
    ["starts-with", "$key", "uploads"],
    ["starts-with", "$filename", ""]
  ]
}

※上記の例では次のような条件を指定している

  • 2013年3月15日9時(GMT)までにアップロードしなければならない
  • アクセス権限は authenticated-read でなければならない
  • アップロード先は bucket-name でなければならない
  • success_action_status は 201 でなければならない
  • keyは uploads で始まらなければならない
  • ファイル名はなんでもよい

PHPでpolicyを作ると次のような感じ。

$policy_json = json_encode(array(
        'expiration' => date('Y-m-d\TH:i:s.000\Z', time() + (60 * 60 * 24) - (60 * 60 * 9)),
        'conditions' => array(
            array('acl' => 'authenticated-read'),
            array('bucket' => 'bucket-name'),
            array('success_action_status' => '201'),
            array('starts-with', '$key', 'uploads'),
            array('starts-with', '$filename', '')
        )
));
$policy = base64_encode($policy_json);

signature

signatureはpolicyとセットで渡すもの。HMAC SHA-1を使ってpolicyをAWSのSecret Keyでsignする。

$signature = base64_encode(hash_hmac('sha1', $policy, AWS_SECRET_KEY, true));

4.Uploadifyの設定

あとはボタンを配置してUploadifyに必要な値を渡したらおしまい。

jsとcssを読み込んでボタンを配置

こちらは…ご覧の通りである。

<head><link rel="stylesheet" type="text/css" href="uploadify.css" />
<script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="jquery.uploadify-3.1.min.js"></script><body><input type="file" name="file_upload" id="file_upload" />

Uploadifyの設定

こちらもほぼご覧の通りである。
ただ、2箇所ほどはまったところがある。

  • fileObjNameの指定が必須
    • これを指定しないとPOSTサイズが大きすぎてS3に怒られる
    • 値はなんでもよい
  • aclやsuccess_action_statusなどはすべて事前にpolicyで定義しておく必要がある
    • でないとS3に怒られる
$(function() {
    $('#file_upload').uploadify({
        'swf'      : 'uploadify.swf',
        'uploader' : 'https://bucket-name.s3.amazonaws.com/',
        'fileObjName' : 'file',
        'formData' : {
            'AWSAccessKeyId' : '[Access Keyを指定]',
            'acl' : 'authenticated-read',
            'key' : '[ファイルのパスを指定(ファイル名含む)]',
            'policy' : '<?= $policy ?>',
            'signature' : '<?= $signature ?>',
            'success_action_status' : '201'
        }
    });
});

これで完了!
あとはS3にアップロードされたファイルを煮るなり焼くなりやっちゃって下さい。

22
21
0

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
22
21