#TL;DR
FuelPHPでセッション情報をMemcacheやRDBMSなどを使って複数ノードで共有する場合には、
- app/config/crypt.php
を複数ノードで同じ値となるように設定する必要がある。
#背景
Webアプリを複数ノードで構成して、ロードバランサでセッション維持をしない場合には、どのノードにユーザの再アクセスがあってもセッションを維持するために、セッションストアとしてMemcacheやRDBMSなどを使うと思います。
例えば、以下のような構成。
このような構成を FuelPHP で行う場合の注意点を書いておきます。
図と、以降の説明では ElastiCache(Redis)を使っていますが、注意点についてはRDBMSだろうが普通のMemcacheだろうが同じです。
#セッションストアの指定
FuelPHP では、セッションストアの指定を app/config/session.php でまず指定します。(なお、環境に応じて設定を変更したい場合は、 config/staging/session.php などに記述すればOK)
Redisを使うのであれば、session.phpの記述は以下のようになります。
<?php
return array(
'driver' => 'redis',
'redis' => array(
'cookie_name' => 'fuelrid',
'database' => 'default',
),
);
さらにRedisの場合は、db.phpに接続先の情報を記述します。
<?php
return array(
'redis' => array(
'default' => array(
'hostname' => 'xxxxxx.yyyyyy.nnnn.apne1.cache.amazonaws.com',
'port' => 6379,
'timeout' => null,
)
),
);
セッションストアとして他のシステムを使う場合はなどは、下記公式ドキュメントを参照するとよいです。
#暗号キー設定
で、ここからが重要で、これだけの設定だけでは、本質的にはセッションの共有ができません。
ロードバランサが別ノードに新たにリクエストを振るたびに、セッションが維持できないという症状がでます。(環境の作り方次第では、下記情報が同じになっているので、意図せず正しくは動作することもあります)
これは、FuelPHP ではセッションIDをCookie名に設定する時に暗号化を行っているのですが、この時に使用する暗号キーがノード毎に異なることが原因です。
この暗号キーはデフォルトでは設定されておらず、必要となったときに初めて app/config/crypt.php に自動的に生成されます。
ファイルの内容は以下のようなものです。
<?php
return array(
'crypto_key' => '9eEBP8okkcz4xAo9rU5h4f7Q',
'crypto_iv' => 'HncqRUWjEl2Y53sqawnK4Y7Q',
'crypto_hmac' => 'ra4OxkVxYthofVMlAk0ncQrQ',
);
この内容を複数のノードで同じとなるようにします。
crypto_key, crypto_iv, crypto_hamc の3つが必要となり、それぞれ以下の条件を満たす必要があります。そうでなければ、再作成されてしまいノード毎に異なることになってしまします。
- base64デコード可能な文字列
- 文字列の長さは4の倍数
core/classes/crypt.php の _init() メソッドを見るとわかると思います。
そこからの抜粋で下記のようなコードで暗号キーに必要な値を生成できます。
<?php
function safe_b64encode($value)
{
$data = base64_encode($value);
$data = str_replace(array('+','/','='), array('-','_',''), $data);
return $data;
}
$crypto = '';
for ($i = 0; $i < 8; $i++)
{
$crypto .= safe_b64encode(pack('n', mt_rand(0, 0xFFFF)));
}
echo $crypto . "\n";
#参考