RitoLabo

LaravelのFlysystem-aws-s3でAmazon S3と連携しファイル操作を行う

  • 公開:
  • 更新:
  • カテゴリ: PHP Laravel
  • タグ: PHP,Laravel,Flysystem,FileStorage,Amazon S3,5.5,5.4,5.3,cache,5.6

今回は、Laravelのファイルストレージ機能であるFlysystemを使ってAmazon S3と連携し、ファイルの保存や読み出しなど一連の操作を行います。

アジェンダ
  1. 開発環境
  2. Amazon S3について
  3. flysystem-aws-s3-v3導入
  4. 設定ファイル編集
    1. サーバの日時設定について
  5. S3へのファイルの保存・読み出し
  6. キャッシュ設定(Cache-Control)

開発環境

今回の開発環境は以下の通りです。

  • Linux CentOS 7
  • Apache 2.4
  • PHP 7.1
  • Laravel

Laravelのバージョンに関しては、5.6/5.5/5.4/5.3にて動作確認済みです。

Laravelのルートディレクトリを「laravel/」とします。

今回の作業にはcomposerを使います。未導入の場合は予めインストールを行ってください。

尚、ファイルストレージについての基礎や、ローカルでのファイル操作を行う場合に関しては、 前回の記事であるlocal/publicディスク編を参考にしてください。

Amazon S3について

作業に入る前に、S3について少し紹介しておきます。

Amazon S3とは、Amazon Web Service が提供するクラウドストレージサービスです。Simple Storage Serviceの、頭文字を取ってS3という名称になっています。

S3の最も良いところといえば、なんといってもその安さです。1GB突っ込んでも1ドル100円換算で2.5円とかそんなレベル。そして容量はもちろん無制限なので、大概のものはここに入れておけば問題なく運用できます。

ファイル取得のレスポンスも早いので、WEBサービスを構築する上では今結構スタンダードになっていると思います。

また、S3に保存したファイルを非公開扱いにも出来ます。非公開設定のファイルやディレクトリに関しては許可されたアカウント以外からでは扱えないので、データを溜めておいたり、色々な使い方もできます。

flysystem-aws-s3-v3導入

LaravelのファイルストレージとS3を連携させるには、専用のパッケージを導入する必要があります。

パッケージは公式でもアナウンスのある league/flysystem-aws-s3-v3 を導入します。

Laravelのルートディレクトリへ移動し、以下のcomposerコマンドを叩いてインストールを行います。

# composerでパッケージを追加
composer require league/flysystem-aws-s3-v3 ~1.0

インストールが完了したら、composer.jsonを開いて追加されているかを確認します。

laravel/composer.json
"require": {
"php": ">=7.0.0",
"laravel/framework": "5.5.*",
"laravel/socialite": "^3.0",
"laravel/tinker": "~1.0",
"league/flysystem-aws-s3-v3": "~1.0" // ← 追加されている事を確認
},

設定ファイル編集

次に、LaravelとS3が同期出来るように、アカウント情報を設定します。

まずは、Flysystemの設定ファイルを確認します。ファイルを開くと下の方に以下の記述があります。

laravel/config/filesystems.php
'disks' => [
's3' => [
'driver' => 's3',
'key' => env('AWS_KEY'),
'secret' => env('AWS_SECRET'),
'region' => env('AWS_REGION'),
'bucket' => env('AWS_BUCKET'),
],
],

この部分がS3の設定情報を格納している部分になるのですが、指定されているのがこんな形式になっています。

env('AWS_KEY'),
env('AWS_SECRET'),
env('AWS_REGION'),
env('AWS_BUCKET'),

これは.envファイルから設定情報を読み取っているメソッドになります。したがって、S3の設定情報はここに直接記載するのではなく、.envファイルに記載していきます。

わざわざ.envファイルに記載するのはセキュリティという観点からですが、もう一方で、そうした方が色々な設定情報が散らばらなくて良いという利点もあります。

それでは.envファイルにS3の設定情報を記載します。

laravel/.env
AWS_KEY=[アクセスキー]
AWS_SECRET=[シークレットキー]
AWS_REGION=[リージョン(東京ならap-northeast-1)]
AWS_BUCKET=[バケット名]

これで基本設定は完了です。

サーバの日時設定について

S3と連携を行うにあたって一点注意すべき事があります。それは、サーバの日時設定です。

LaravelからS3を操作する際に、アプリケーション側のの日時設定がきちんと行われていないとエラーになります。

Linuxで動かす場合には、dateコマンドにて、適切な日時設定が行われているか確認してください。

S3へのファイルの保存・読み出し

それでは実際にLaravelからS3へのファイル操作を行っていきます。百聞は一見に如かず、まずは一通りの流れをコントローラに記述しました。

<?php
namespace App\Http\Controllers;

use Storage; // ← (1)

class FlySystemS3Controller extends Controller
{
public function index()
{
$disk = Storage::disk('s3'); // ← (2)

| $public_path = '/path/to/project_root/public/';
(3)| $img_path = sprintf('%s%s', $public_path, 'test.jpg');
| $contents = file_get_contents($img_path);

// S3 にファイルをアップロード(パスはバケットディレクトリを起点として相対パスで記述)
$disk->put('test/test.jpg', $contents, 'public'); // ← (4)

// S3の完全URLを得る
$url = $disk->url('test/test.jpg'); // ← (5)
// $url → https://s3-REGION.amazonaws.com/BUCKET_NAME/test/test.jpg みたいな完全URLが返る

// S3上に指定ファイルが存在するか確認
if($disk->exists('test/test.jpg')) { // ← (6)
echo'<pre>'; echo 'exists'; echo'</pre>';
} else {
echo'<pre>'; echo 'NONE'; echo'</pre>';
}

// ファイル取得はget()
$contents = $disk->get('test/test.jpg'); // ← (7)

| $put_path = sprintf('%s%s', $public_path, 'test_put.jpg');
(8)| // サーバに保存(ダウンロード)
| file_put_contents($put_path, $contents);

}
}

上から説明していきます。

use Storage; // ← (1)

まずはStorageクラスをuseします。

$disk = Storage::disk('s3'); // ← (2)

どのディスクを使うかの指定をしています。S3と連携させるので、「s3」を指定しています。

   | $public_path = '/path/to/project_root/public/';
(3)| $img_path = sprintf('%s%s', $public_path, 'test.jpg');
| $contents = file_get_contents($img_path);

ローカルにある画像のフルパスと画像ファイル名を結合させ、 file_get_contents()メソッドで画像ファイルデータを読み込んでいます。

// S3 にファイルをアップロード(パスはバケットディレクトリを起点として相対パスで記述)
$disk->put('test/test.jpg', $contents, 'public'); // ← (4)

ここでputメソッドにて、S3へファイルをアップロードしています。

putメソッドの引数に関しては以下の通りです。

'test/test.jpg'
S3に保存する階層+ファイル名(新たに命名してもOK)
$contents
読み込んだファイルデータ
'public'
視認性の設定。S3では、特に指定なくアップロードしたファイルについては「非公開」となり、外部には公開されません。例えば画像をアップロードして公開するなどの場合には、ここを公開状態にする必要があるので、 その場合には第三引数に「public」を渡します。逆に、公開したくない場合は第三引数は空でOKです。
// S3の完全URLを得る
$url = $disk->url('test/test.jpg'); // ← (5)
// $url → https://s3-REGION.amazonaws.com/BUCKET_NAME/test/test.jpg ← 完全URLが返る

urlメソッドを使うと、S3に保存したファイルの完全URLを取得出来ます。

上記の例なら
https://s3-REGION.amazonaws.com/BUCKET_NAME/test/test.jpg
の形で返ってきます。

// S3上に指定ファイルが存在するか確認
$disk->exists('test/test.jpg') // ← (6)

existsメソッドを使うと、対象のファイルがS3上に存在するどうかを確認できます。

指定している引数には、バケットディレクトリからの相対パスを指定します。

// ファイル取得はget()
$contents = $disk->get('test/test.jpg'); // ← (7)

getメソッドを使うと、画像データを取得できます。

指定している引数には、バケットディレクトリからの相対パスを指定します。

   | $put_path = sprintf('%s%s', $public_path, 'test_put.jpg');
(8)| // サーバに保存(ダウンロード)
| file_put_contents($put_path, $contents);

S3からファイルデータ自体を取り出す時は、getメソッドでS3から取得した画像データに対して保存先のパス(+保存するファイル名)を設定し、file_put_contentsメソッドでローカルに保存しています。

キャッシュ設定(Cache-Control)

アップロード時にキャッシュコントロールを付与したいという場合には設定ファイルに記述する事で設定できます。

laravel/config/filesystems.php
's3_' => [
'driver' => 's3',
'key' => env('AWS_KEY'),
'secret' => env('AWS_SECRET'),
'region' => env('AWS_REGION'),
'bucket' => env('AWS_BUCKET'),
'options' => [
'CacheControl' => 'max-age=999900'
]
]

optionsプロパティに対してCacheControlを設定する事で、キャッシュ設定を付与する事ができます。

ちなみに、この「options」で設定できる項目は以下の通りです。

  • ACL
  • CacheControl
  • ContentDisposition
  • ContentEncoding
  • ContentLength
  • ContentType
  • Expires
  • GrantFullControl
  • GrantRead
  • GrantReadACP
  • GrantWriteACP
  • Metadata
  • RequestPayer
  • SSECustomerAlgorithm
  • SSECustomerKey
  • SSECustomerKeyMD5
  • SSEKMSKeyId
  • ServerSideEncryption
  • StorageClass
  • Tagging
  • WebsiteRedirectLocation

まとめ

以上で一連の作業は完了となります。
Storageクラスのメソッドはまだ他にもあるので、公式のページで見てみると良いと思います。

Amazon S3は容量無制限のストレージに併せて高可用性を兼ね備え、 且つレスポンスも速く表示スピードのボトルネックにもならない非常に優秀なクラウドストレージです。
こういった便利なサービスも上手に使って、優れたWEBアプリケーションを作りだしていきたいですね。