Laravel5.1で作るファイルアップロードライブラリLaravel-Staplerの利用方法＆AWS S3との連携Tips

## はじめに（Advent Calendarで書いたネタの続きとおまけ）

以前にLaravel5のAdvent Calendarにて「[Laravelの環境設定＆開発体験自作Laravel5.1ミニマムチュートリアルまとめ](http://qiita.com/fumiyasac@github/items/78a335880f7abb1de8bf)」を書きました。この記事については基本的なデータの追加・変更・削除のチュートリアル的なサンプルになりますが、その際にも使用したファイルアップロード用のライブラリである「Laravel-Stapler」に関しての補足記事になります。

以前のサンプルはローカル環境で動かすことを前提としていたので、アップロードした画像ファイルに関してはLaravel内のpublic配下に保存されるようにしていました。

自分で借りたレンタルサーバーやVPSを利用する場合はこの設定でも問題は特にありませんが、heroku等のクラウドサーバー上にLaravelのアプリケーションを構築する場合には、アップロードしたファイルのデータについてはAmazon S3をはじめとした別ストレージへ格納する必要があります。

今回は外部ストレージにAWS S3を使用するので、その際の実装の方法と手順に関して説明していこうと思います。

また以前に作成したチュートリアルのgithub内にも、どこにAmazon S3に関する設定を記述するかという部分に関しても追加コミットを行いましたので、参考にして頂けましたら幸いです。

[Laravel5.1でCRUDアプリケーションを作成する簡易チュートリアル](https://github.com/fumiyasac/laravel-minimum-tutorial)

## 0. Laravel-Staplerの特徴とAWS S3の設定に関する参考資料等

Laravel-Staplerは以前に作成したチュートリアルでも少し触れていますが、こちらはRuby on Railsで有名はファイルアップロードのGemである「Paperclip」にインスパイアされて作成されたLaravel用のライブラリになります。

※ちなみにStaplerは日本語で「ホッチキス」という意味になります。名前も「Paperclip」という元のGemを意識していますね。

このライブラリの主な特徴としては、

+ Paperclipと似たような記述での設定ができる
+ 設定周りやモデルファイル側に設定を追記すればOKなので導入がしやすい
+ 英語ではありますがドキュメントや設定が詳しく書かれている

という点が個人的には気に入っている点でもあります。

Laravelはライブラリが多く公開されていますが、特に画像のアップロードについては自前で実装するのは骨が折れる処理の一つでもありますので、知っておくと重宝する場面があるのではないかと思います。

また、このサンプルを作成するにあたってはこちらの情報を参考にして作成しました。
[Managing images with Laravel-stapler and Amazon s3](http://www.8balldigital.co.uk/posts/laravel-stapler-amazon-s3-tutorial)

あとは補足資料としてはLaravel-staplerに関するリポジトリ情報や元になったPaperclipに関する情報を下記へまとめておきました。

+ [CodeSleeve/laravel-staplerに関するGithub](https://github.com/CodeSleeve/laravel-stapler)
+ [参考その1：laravel-staplerの元になっている「stapler」](https://github.com/CodeSleeve/stapler)
+ [参考その2：インスパイア元の「Paperclip」](https://github.com/thoughtbot/paperclip)

Laravel-staplerの設定に関する情報については「stapler」のリポジトリのドキュメントを参考にしてみてください。英語ではありますが、設定の記述に関してはほとんど同じなのとコード例が多く掲載されていますので参考にできるかと思います。

###### ★0-1. 前提：環境構築や実践した環境に関して

私の環境で試したのでOSやMAMPのバージョンは下記の通りになっています。

+ OS：10.10.5 Yosemite
+ MAMP：Ver.3.4（最新版のVer3.5でも問題はないはず）
+ Laravel：5.1 ※LTSバージョン

※ MySQLはMAMPのものを使用しています。
※こちらは以前に私が書いた記事のチュートリアルを元に作成しています。

###### ★0-2. 前提：Amazon S3側の設定に関しての参考資料

AWS S3まわりの設定に関しては「[PaperclipとAWS S3を用いた画像アップロード機能作成手順まとめ（2. AWSまわりの下準備とGemのインストール）](http://qiita.com/fumiyasac@github/items/320f80dcab492b3e31ab#2-aws%E3%81%BE%E3%82%8F%E3%82%8A%E3%81%AE%E4%B8%8B%E6%BA%96%E5%82%99%E3%81%A8gem%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)」の手順を参考にしてリージョン・アクセス権・バケットポリシー・CORSの設定を行って頂ければと思います。

__（参考）AWS S3の実際の画面：__
![aws_s3_panel.png](https://qiita-image-store.s3.amazonaws.com/0/17400/e9801e58-5dd5-887d-c58a-0d03f5008999.png)

上記はRuby on Railsの「Paperclip」でファイルアップロード処理を行った際の設定で使用したものになりますが、AWS S3側の設定に関しては同様の設定で特に問題はないと思います。

※ AWS S3側の設定に関してはこの設定で良いかは若干自信ないですが、もし「設定こうしたほうがいいよ」等のご意見があればお気軽にお願いします。また実際のアプリケーションで運用する場合にはセキュリティの設定にも十分に留意するようにお願いします。

## 1. Laravel側で必要なライブラリをインストールする

LaravelでAWS S3へのファイルアップロードを行う場合はLaravel-staplerと一緒に「aws-sdk」を一緒にインストールする必要があります。

+ [AWS SDK for PHP ※Version 2](http://docs.aws.amazon.com/aws-sdk-php/v2/api/index.html)

AWS SDK for PHPに関しては、Laravelに限らずにその他のフレームワークでも使用できます。Versionに関してもバージョンの最新はVersion3までありますが、Laravel-staplerと組み合わせて使用する際にはVersion2の最新版をインストールして使用します。

また今回の実装の想定としましては、[Laravelの環境設定＆開発体験自作Laravel5.1ミニマムチュートリアルまとめ](http://qiita.com/fumiyasac@github/items/78a335880f7abb1de8bf)で作成したサンプルにAWS S3との連携するための記述を追記する形を想定しています。

※上記の部分に関する差分については、[composer self-updateとlaravel-staplerのAWS S3用の設定の雛形作成](https://github.com/fumiyasac/laravel-minimum-tutorial/commit/d1c6bbb716370edd301575d2b5c199e495ead3a9)を参照して頂ければと思います。

###### ★1-1. Laravel側でLaravel-staplerと一緒に必要なライブラリをcomposer.jsonに記述する

Laravel-staplerのインストールが既に済んでいる場合は、aws-sdk-phpに関する記述をcomposer.jsonに追記して下さい。（Laravel-staplerの設定がまだの場合はその記述も行って、インストールの完了後にLaravel-staplerの有効化の作業も行って下さい。）

```json:composer.json
"require": {
    "php": ">=5.5.9",
    "laravel/framework": "5.1.*",
    "laravelcollective/html": "~5.0",
    "laravel-ja/comja5": "^1.0",
    "codesleeve/laravel-stapler": "1.0.*",
    "aws/aws-sdk-php": "2.4.*" //この部分を追記する
},
```

記述が終わった際は下記のコマンドでAWS SDK for PHPを作成しているLaravelアプリケーションにインストールして下さい。またLaravel-staplerの設定ファイルをconfig配下に書き出す為のコマンドも実行して下さい。

```
$ sudo composer update
$ php artisan vendor:publish
```

上記のartisanコマンドを実行するとconfigディレクトリ内にlaravel-staplerディレクトリが作成されその中の構成は下記のようになっています。

+ config/laravel-stapler/bindings.php
+ config/laravel-stapler/filesystem.php
+ config/laravel-stapler/s3.php
+ config/laravel-stapler/stapler.php

今回はこの中のs3.phpにAWS S3に関する記述を書いていきます。
（一応laravelのvendor配下の中に直接記述しても良いですがバージョンアップ等のからみもあるので設定ファイルの記述はconfigに書き出すようにしたほうが良いと思います）

## 2. AWS S3に関する設定の追記とモデルファイルの変更を行う

前の手順にてひとまずは設定に関する準備は整いましたので、今回は以前に作成したチュートリアルの部分からAWS S3アップロード処理のための拡張を行っていきます。最小限の構成の場合は下記の部分を少し追記するだけでできます。

また、Laravel-Staplerを使うという宣言も忘れないように追加しておいて下さい。

```php:config/app.php
return [

    //——(省略)—-

    //サービス・プロバイダーの設定
    'providers' => [

        //——(省略)—-
        Codesleeve\LaravelStapler\Providers\L5ServiceProvider::class,
    ],

    //——(省略)—-

];
```

ここまででLaravel-Staplerを使用する下準備は完了です。

###### ★2-1. config/laravel-stapler/s3.phpの設定

先ほど作成したconfig/laravel-stapler/s3.phpの内部は下記のようになっています。このファイル内にAWS S3に関する設定内容を記述していきます。この部分に関しては各モデルファイル内に記述しても問題なく動作をしますが、全アプリケーションで適用させる部分についてはこのファイルに記述しています。

```php:config/laravel-stapler/s3.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | S3 Client Config
    |--------------------------------------------------------------------------
    |
    | This is array holds the default configuration options used when creating
    | an instance of Aws\S3\S3Client.  These options will be passed directly to 
    | the s3ClientFactory when creating an S3 client instance.
    |
    */

    //自分のAWS S3ストレージへの設定パラメータを設定する
    's3_client_config' => [
        'key' => 'Your Key String here.', //アクセスキーIDを入れてください
        'secret' => 'Your Secret Key String here.', //シークレットキーを入れてください
        'region' => Aws\Common\Enum\Region::TOKYO, //東京リージョンの場合の記述
        'scheme' => 'http',
    ],

    /*
    |--------------------------------------------------------------------------
    | S3 Object Config
    |--------------------------------------------------------------------------
    |
    | An array of options used by the Aws\S3\S3Client::putObject() method when
    | storing a file on S3.
    | AWS Documentation for Aws\S3\S3Client::putObject() at 
    | http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.S3.S3Client.html#_putObject
    |
    */

    //自分のAWS S3ストレージ内のバケット名とアクセス制御リストを設定する
    's3_object_config' => [
        'Bucket' => 'Your Bucket', //作成したバケット名を入れてください
        'ACL' => Aws\S3\Enum\CannedAcl::PUBLIC_READ_WRITE, //パブリックに読み込みと書き込みが可能の場合の記述
    ],

    /*
    |--------------------------------------------------------------------------
    | S3 Path
    |--------------------------------------------------------------------------
    |
    | This is the key under the bucket in which the file will be stored.
    | The URL will be constructed from the bucket and the path.
    | This is what you will want to interpolate. Keys should be unique,
    | like filenames, and despite the fact that S3 (strictly speaking) does not
    | support directories, you can still use a / to separate parts of your file name.
    |
    */

    'path' => ':attachment/:id/:style/:filename',

];
```

このファイル内には、

+ S3 Client Config
+ S3 Object Config
+ S3 Path

の設定に関しての記載がありますので、自分のAWS S3に関する設定をしていきます。
今回の想定としては、バケット内に __「uploads/(クラス名)/(ID)/(画像サイズ名)/ファイル」__ という構成でアップロードファイルの管理を行う想定でいます。

各モデルに対応するアップロードファイルへのURLやパスの設定はTopic.phpに行い、s3.phpにはAWS S3に関する設定を記載していきます。

上記ソース内でリージョンとACLに関する定数に関するリファレンスは下記を参照して記述しました。こちらはAWS SDK for PHPの設定に関する記述のほんの1部分になります。

+ [Class Region に関するリファレンス](http://docs.aws.amazon.com/aws-sdk-php/v2/api/class-Aws.Common.Enum.Region.html) 
+ [Class CannedAcl に関するリファレンス](http://docs.aws.amazon.com/aws-sdk-php/v2/api/class-Aws.S3.Enum.CannedAcl.html) 

※この部分にはかなり重要な情報を記載していますので、リポジトリを管理する際等には注意をお願いします。

###### ★2-2. app/Topic.phpの設定

以前に作成したチュートリアルに関しても、モデルファイル（app/Topic.php）の設定を変更する必要があります。AWS S3の格納場所に関してはクラス名を使いたかったので画像URLと格納場所パスの部分に関しては部分的にモデルファイルに記載しています。
AWS S3の設定をモデルファイルに反映させるためには、 `'storage' => 's3'` の記述をすることで可能です。

```php:app/Topic.php
<?php
namespace App;

use Codesleeve\Stapler\ORM\StaplerableInterface;
use Codesleeve\Stapler\ORM\EloquentTrait;

use Illuminate\Database\Eloquent\Model;

class Topic extends Model implements StaplerableInterface {
  
  //Staplerの読み込み
  use EloquentTrait;
  
  protected $fillable = array('title', 'body', 'published', 'eyecatch');

  //コンストラクタ
  public function __construct(array $attributes = array()) {
    
    //画像の投稿設定
    $this->hasAttachedFile('eyecatch', [
      
      //画像の切り取るサイズのパターン
      'styles' => [
        'large' => '640x480#',
        'medium' => '300x200#',
        'thumb' => '100x75#'
      ],
      
      //格納ディレクトリ(AWS S3配下のパスと画像のアクセスURLに関する設定)
      'url' => '/uploads/topics/:id/:style/:filename',
      'path' => '/uploads/topics/:id/:style/:filename',
      
      //AWS S3のストレージを使用する(config/laravel-stapler/s3.phpの設定を反映させる) 
      'storage' => 's3',
    ]);
    parent::__construct($attributes);
  }

}
```

以上でAWS S3へのファイルアップロードができるようになります。上記の設定や実装とAWS S3の準備が問題なくできていればローカル環境下でもファイルアップロードができますので参考に少しでもなれば幸いに思います。

__■ Screen Captureその1:__
![sample1.png](https://qiita-image-store.s3.amazonaws.com/0/17400/4ed7b6b8-b250-829f-0715-3422149732ba.png)

__■ Screen Captureその2:__
![sample2.png](https://qiita-image-store.s3.amazonaws.com/0/17400/4b68ea72-4900-8364-b835-2961a64838d6.png)

※上記は画像のアップロードができた際のスクリーンキャプチャになります。

## 3. あとがき

Advent Calendarを書いた時から結構時間が経過していましたが、今年の初めに「Paperclip」に関する手順をQiitaに投稿したことやPaperclipにかなり似ているLaravel-staplerに関しても同じような感じでできるのではないかと思い試してみた次第です。

日本語のドキュメントがあまりないのが唯一の泣き所ではありますが、英語の実装例のドキュメントは割と充実していることや更新等も行われているライブラリですので、Laravelで画像のアップロードをする際には是非とも活用してみてはいかがでしょうか。

## 追記とその他

2016/04/13:

+ 今回の記事のポイントとなる部分を勉強会にて発表する機会がありましたので、その際に使用したスライドもここに共有致します。下記資料も皆様のご理解の参考となれば幸いです。
+ 参考スライド：[言語は違うけどもインスパイアされて作られたとあるライブラリ（PaperclipとLaravel-stapler）](http://www.slideshare.net/fumiyasakai37/papercliplaravelstapler-60716244)