LaravelでIntervention Imageを使って加工した画像をS3へ保存する

# はじめに
PHPで画像の加工を行う場合いろいろな方法がありますが、フレームワークにLaravelを利用している場合は「Intervention Image」がオススメです。

導入が簡単でリサイズやクロップの記述も簡単といいことずくめなのですが、
加工した画像をS3へアップロードする際に少し躓いたので備忘録として記します。

なお、Laravelのバージョンは5.7にて確認しています。

# Intervention Image
http://image.intervention.io/getting_started/introduction
画像処理のライブラリであるGDと共にIntervention Imageをサーバへインストールします。

```
# yum install php-gd
# systemctl reload httpd.service
# php composer.phar require intervention/image
```

Laravelの設定ファイルの$providers配列にIntervention Imageのサービスプロバイダを追加します。

```php:config/app.php
'providers' => [
    Intervention\Image\ImageServiceProvider::class,
],
```

同じく設定ファイルの$aliases配列にファサードを追加します。

```php:config/app.php
'aliases' => [
    'Image' => Intervention\Image\Facades\Image::class,
],
```

キャッシュをクリアして準備は完了です。

```
# php artisan config:clear
```

# putメソッドを利用した画像アップロード
putメソッドを利用した場合は下記の様にシンプルに記述できます。
生成されたIntervention Imageのインスタンスをstringへキャストするのがポイントでしょうか。

詳しくはlaracastsの下記のフォーラムで質疑されていました。
https://laracasts.com/discuss/channels/laravel/image-intervention-with-laravel-53?page=1

```php:app/Http/Controllers/SampleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Intervention\Image\Facades\Image;

class SampleController extends Controller
{
     /**
     * Handle a image upload request for the application.
     *
     * @param  $request
     * @return \Illuminate\Http\Response
     */
    public function upload(Request $request)
    {
        // バリデーション
        Validator::make($request->all(), [
            'image' => 'file|image|max:1024|nullable'
        ])->validate();

        if ($request['image']) {
            $file = $request->file('image');
            $name = $file->getClientOriginalName();

            // 画像を横幅300px・縦幅アスペクト比維持の自動サイズへリサイズ
            $image = Image::make($file)
                ->resize(300, null, function ($constraint) {
                    $constraint->aspectRatio();
                });

            // configファイルに定義したS3のパスへ画像をアップロード
            Storage::put(config('filesystems.s3.url').$name, (string) $image->encode());
        }

        return redirect()->route('index');
    }
}
```

# putFileAsメソッドを利用した画像アップロード
putメソッドを利用できれば簡単でしたが、実際にはS3へアップする際にファイル名を指定したい場合もあるでしょう。
その場合はputFileAsメソッドを利用するのですが、putメソッドのようにシンプルな記述でできずに悩みました。調べてもあまり情報が見つからない。

結局、リサイズした画像をいったんローカルへ保存してからS3へアップロードし、その後ローカルの画像を削除する、といった流れで行いました。

```php:app/Http/Controllers/SampleController.php
<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Http\File;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Intervention\Image\Facades\Image;

class SampleController extends Controller
{
     /**
     * Handle a image upload request for the application.
     *
     * @param  $request
     * @return \Illuminate\Http\Response
     */
    public function upload(Request $request)
    {
        // バリデーション
        Validator::make($request->all(), [
            'image' => 'file|image|max:1024|nullable'
        ])->validate();

        if ($request['image']) {
            $now = date_format(Carbon::now(), 'YmdHis');
            $file = $request->file('image');
            $name = $file->getClientOriginalName();

            // 画像を横幅300px・縦幅アスペクト比維持の自動サイズへリサイズして一時ファイル保存先へ格納
            $tmpFile = $now . '_' . $name;
            $tmpPath = storage_path('app/tmp/') . $tmpFile;
            $image = Image::make($file)
                ->resize(300, null, function ($constraint) {
                    $constraint->aspectRatio();
                })
                ->save($tmpPath);

            // configファイルに定義したS3のパスへ指定したファイル名で画像をアップロード
            Storage::putFileAs(config('filesystems.s3.url'), new File($tmpPath), $file, 'public');

            // 一時ファイルを削除
            Storage::disk('local')->delete('tmp/' . $tmpFile);
        }

        return redirect()->route('index');
    }
}
```

# おわりに
putメソッドがシンプルな記述だったので、putFileAsメソッドでも同様にできると油断したため、予想以上にはまってしまいました。