LaravelとS3を連携させて遊んでみました。
連携方法は3通りありますので、まとめてみます。

環境は次の通りです。

  • PHP 7
  • Laravel 5.3
  • CentOS 6.6 (Vagrant)

Filesystem

1つ目はファイルシステムを利用する方法で。

これは公式ドキュメントで紹介されている方法ですね。
https://laravel.com/docs/5.3/filesystem

ライブラリにleague/flysystem-aws-s3-v3を利用します。

Github : league/flysystem-aws-s3-v3
https://github.com/thephpleague/flysystem-aws-s3-v3

導入

composer.json

"require": {
    "php": ">=5.6.4",
    "laravel/framework": "5.3.*",
    "aws/aws-sdk-php-laravel": "~3.0",
    "league/flysystem-aws-s3-v3": "~1.0"
},

jsonを更新してcomposer updateしましょう!

config/filesystems.php

configにAWSの情報を入れていきます。 環境によって切り替えができるようenv()を利用します。

'default' => env('DEFAULT_STORAGE', 'public'),
:
'disks' => [
    's3' => [
        'driver' => 's3',
        'key'    => env('S3_ACCESS_KEY'),
        'secret' => env('S3_SECRET_KEY'),
        'region' => env('S3_REGION'),
        'bucket' => env('S3_BUCKET'),
    ],
],

これははQiitaのyamatoさんの投稿を参考に、どうせならと、デフォルトもenv()で切り替えられるようにしました。

【Laravel5】Storageファサードでお手軽S3アップロード
http://qiita.com/yamato/items/7b8aab6e1f3556e9aadb

.env

.envで環境別の定義を入れます

DEFAULT_STORAGE=s3
S3_ACCESS_KEY=[access_key]
S3_SECRET_KEY=[secret_keye]
S3_REGION=ap-northeast-1
S3_BUCKET=[bucket_name]

Tokyoリージョンですよー。

PHPコード

$disk = Storage::disk('s3');

// S3 Buketにファイルをアップロード
$disk->put($file_name, $contents);

// S3の完全なリモートURLを得る
$url = $disk->url($file_name);

// ファイル取得はget()
$contents = $disk->get($file_name);

fileと同等のコードで実装することができ、大変使い勝手が良いです。
手元の環境では[file]を、開発環境以上では[S3]を使うといった切り分けが.envで簡潔するというすばらしさ!

通常はこちらをおすすめですね。

AWS-SDK

S3のほかにもAWSのサービスを利用する場合や、S3の事前署名付きURLを利用する場合はAWS-SDKの利用が必須です。

Laravel用としてaws/aws-sdk-php-laravelが提供されておりますのでこれ利用します。

Github : aws/aws-sdk-php-laravel
https://github.com/aws/aws-sdk-php-laravel

導入

READMEに従って設定を入れていきます。

composer.json

"require": {
    "php": ">=5.6.4",
    "laravel/framework": "5.3.*",
    "aws/aws-sdk-php-laravel": "~3.0",
},

いつもの通り、jsonを更新してcomposer updateしましょう!

config/app

'providers' => array(
    // ...
    Aws\Laravel\AwsServiceProvider::class,
)
'aliases' => array(
    // ...
    'AWS' => Aws\Laravel\AwsFacade::class,
)

.env

AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION (default = us-east-1)

aws-sdk-php-laravelでは上記キー名をユーザが任意で決めることが難しそうです。

もしS3以外にもサービスを利用する場合はphp artisan vendor:publishを打つとapp/config/aws.phpが追加され複数のキーを設定することができるようになりますよ。

PHPコード

ファイルアップロード

サーバ上に保存されているファイルをS3にアップする場合は次でOKです。

use Illuminate\Support\Facades\App;
:

$s3 = AWS::createClient('s3');
$s3->putObject([
    'Bucket'     => $bucket_name,
    'Key'        => $key_name,
    'SourceFile' => $path_to_file,
]);

Bodyを利用してアップロードするデータを直接与えることも可能です。

$result = $s3->putObject([
    'Bucket'      => $bucket_name,
    'Key'         => $file,
    'Body'        => $binary,
    'ContentType' => $content_type,
]);

Bodyを指定すると_ContentTypeが[application/octet-stream]でオブジェクトが作成_されてしまいます。
するとS3上の対象オブジェクトにアクセスしても期待通り表示されませんので、アップロード時にContentTypeを指定することが望ましいです。

ContentTypeの指定については以下を参考にいたしました。

遍歴プログラマ日記
AWS SDK for PHP(バージョン3)を使ってオブジェクトをアップロード・ダウンロードする
https://remotestance.com/blog/3044/

ファイル取得

$object = $s3->getObject([
    'Bucket' => $bucket_name,
    'Key'    => $file,
]);

Pre-Signed URL

S3ではオブジェクトのアクセスを制御する方法の一つとしてPre-Signed URL(事前署名付きURL)が利用できます。

ただgetObject()するだけではだめで、次のコードで動作を確認いたしました。

use Illuminate\Support\Facades\App;
:

$s3 = App::make('aws')->createClient('s3');
$cmd = $s3client->getCommand('GetObject', [
    'Bucket' => $bucket_name,
    'Key'    => $file,
]);
$request = $s3->createPresignedRequest($cmd, '+20 minutes');

$presignedUrl = (string) $request->getUri();
echo $presignedUrl;

成功すれば、以下のような非常に長いURLを得ることできます!

https://s3-ap-northeast-1.amazonaws.com/[backet]/[object_key]?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIS4FBP5ND6TD4B5A%2F20160929%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20160929T054404Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=[signature_code]

AWSの参考資料

AWS のリージョンとエンドポイント
https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html

AWS SDK for PHP 3.x
http://docs.aws.amazon.com/aws-sdk-php/v3/api/

まとめ

LaravelとS3の連携には以下が利用できます。

  • ファイルシステムでS3にアクセスする
  • AWS-SDKを利用する

より細かい制御が必要な場合はAWS-SDKを利用してください。
AWSを使うのは楽しいですね!

この記事はtomita@atuwebがお届けしました。



2016年12月04日:Qiitaにも投稿しました。
http://qiita.com/atuweb/items/d9ca80b3655173beb62d