Laravel5.5: セッションの保存にRedisを使う (Heroku)

本番環境で使っているHerokuでのセッションの保存先を、デフォルトのファイルからRedisへ変更します。
ただし、これは必須ではありません。保存先がファイルのままでも全く問題ありません。
また、HerokuでRedisを利用するには、無料プランであってもクレジットカードの登録が必要です。
以下では、[Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli)をインストール済みとして進めます。


# 親記事
[Laravel 5.5で基本的なCRUDを作る - Qiita](http://qiita.com/sutara79/items/ef30fcdfb7afcb2188ea)


# アドオンを追加
:link: [Create a new instance](https://devcenter.heroku.com/articles/heroku-redis#create-a-new-instance)

```text:PowerShell
# 無料プランでRedisを使う
> heroku addons:create heroku-redis:hobby-dev
```

アドオンの`Hobby Dev`プランは無料ですが、クレジットカードの登録が必要です。
下記のページから登録画面へ行けます。
:link: https://heroku.com/verify

登録していないと下記のように警告されます。

```
> heroku addons:create heroku-redis:hobby-dev
Creating heroku-redis:hobby-dev on sutara79-laravel... !
 !    Please verify your account to install this add-on plan (please enter a credit card) For more information, see
 !    https://devcenter.heroku.com/categories/billing Verify now at https://heroku.com/verify
```

# 認証情報を取得
下記のコマンドで得られる`REDIS_URL`の中のパスワード、ホスト、ポートをLaravelで使います。

```text:PowerShell
> heroku config | Select-String REDIS

REDIS_URL:         redis://<ユーザー>:<パスワード>@<ホスト>:<ポート>
```

ただし、公式ドキュメントで警告されているとおり、`REDIS_URL`は**いつでも変更される**可能性があるそうです。
単純に値をコピーするのではなく、動的に`REDIS_URL`から必要な値を取り出さなくてはなりません。

> In order for Heroku to manage this add-on for you and respond to a variety of operational situations, the REDIS config vars may change at any time. Relying on the config var outside of your Heroku app may result in you having to re-copy the value if it changes.

:link: [Create a new instance](https://devcenter.heroku.com/articles/heroku-redis#create-a-new-instance)


# 動的に認証情報を取り出す
下の記事が大変参考になりました。
:link: [Heroku上のLaravelでRedisを使う - Qiita](http://qiita.com/kuropen/items/222af1e4a84d7fe70bb1)

```php:config/database.php
// ファイル冒頭に追加
if (getenv('REDIS_URL')) {
    $url = parse_url(getenv('REDIS_URL'));

    putenv('REDIS_HOST='.$url['host']);
    putenv('REDIS_PORT='.$url['port']);
    putenv('REDIS_PASSWORD='.$url['pass']);
}
```

:link: [PHP: parse_url - Manual](http://php.net/manual/ja/function.parse-url.php)
:link: [PHP: getenv - Manual](http://php.net/manual/ja/function.getenv.php)
:link: [PHP: putenv - Manual](http://php.net/manual/ja/function.putenv.php)

## ローカルで動作確認
URLが正しく分解されることを確認します。
あらかじめ、ローカルでもRedisを使えるようにしておいてください。
:link: [セッションの保存にRedisを使う (ローカル環境)](https://qiita.com/sutara79/items/f4ff80c6c513f3b49c08))

下記のように環境設定を変更してください。

```sh:.env
# コメントアウトする
# REDIS_HOST=127.0.0.1
# REDIS_PASSWORD=null
# REDIS_PORT=6379

# 上の設定をHerokuのREDIS_URLの形式にあてはめる
REDIS_URL=redis://foo:null@127.0.0.1:6379
```

あとは上の記事での確認方法と同じです。
あらかじめ作成しておいたルートにブラウザからアクセスします。(`https://(ドメイン)/test-session`)
そして、セッションが保存されていることをRedisのGUIツールで確認します。
確認が終わったらHerokuへプッシュしてください。

```text:PowerShell
> git push heroku master
```


# Herokuで実際にRedisを使う
```text:PowerShell
# Herokuでのセッションの保存先を`redis`に変更
> heroku config:set SESSION_DRIVER=redis
```

## 動作確認
ローカルでの動作確認と同じく、まずは`https://(ドメイン)/test-session`へブラウザからアクセスします。
次に、セッションが保存されていることを確かめたいのですが、HerokuではGUIは用意されていないようなのでコマンドで確認します。

下記のようにオプションでHerokuアプリ名を指定すれば、1回のコマンドでHerokuのRedisに接続できます。
:link: [(Heroku) redis:cli](https://devcenter.heroku.com/articles/heroku-redis#redis-cli)

```text:PowerShell
> heroku redis:cli -a sutara79-laravel -c sutara79-laravel
```

ちなみに、`redis:cli`のヘルプは下記のとおりです。

```text:PowerShell
> heroku redis:cli --help
Usage: heroku redis:cli [DATABASE] [flags]

opens a redis prompt

Flags:
 -a, --app      (required) app to run command against
 -c, --confirm
 -r, --remote   git remote of app to use
```

接続後は普通に[Redisのコマンド](https://redis.io/commands)を使えます。
まず、[KEYS \*](https://redis.io/commands/keys)で全てのキーを取得し、その中からLaravelのセッション用に使われているものを探し出し、そのキーの中身を[GET](https://redis.io/commands/get)で取得します。
その中に`こんにちはこんにちは!!`も含まれており、セッションがきちんとRedisに保存されているのが分かります。
なお、切断には[QUIT](https://redis.io/commands/quit)を使います。
自分のPCにインストールしたRedisでは`exit`も使えたのですが、それは公式に提供されたコマンドではないようですね。

手順をまとめます。

```text:PowerShell
# Redisに接続
> heroku redis:cli -a sutara79-laravel -c sutara79-laravel
Connecting to redis-angular-23368 (REDIS_URL):


# すべてのキーを取得
> keys *
1) laravel:SeDXaIe5ffKdZhdeHpgy8wLnhjyXJTOSps5o43fJ


# キーの中身をGETで取得
# 「こんにちはこんにちは!!」が含まれていることを確認
> get laravel:SeDXaIe5ffKdZhdeHpgy8wLnhjyXJTOSps5o43fJ
s:316:"a:6:{s:6:"_token";s:40:"gz7JGwGUOFdatn2uQfxhaG1CYGoPJKiB0vTufxLW";s:6:"locale";s:2:"en";s:9:"_previous";a:1:{s:3:"url";s:50:"http://sutara79-laravel.herokuapp.com/test-session";}s:22:"PHPDEBUGBAR_STACK_DATA";a:0:{}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:3:"foo";s:32:"こんにちはこんにちは!!";}";


# 切断にはQUITを使う
> quit
OK

# (EXITは使えない)
> exit
ERR unknown command 'exit'
```