Posted at

FuelPHPでセッション共有時の注意点

More than 3 years have passed since last update.


TL;DR

FuelPHPでセッション情報をMemcacheやRDBMSなどを使って複数ノードで共有する場合には、


  • app/config/crypt.php

を複数ノードで同じ値となるように設定する必要がある。


背景

Webアプリを複数ノードで構成して、ロードバランサでセッション維持をしない場合には、どのノードにユーザの再アクセスがあってもセッションを維持するために、セッションストアとしてMemcacheやRDBMSなどを使うと思います。

例えば、以下のような構成。

AWS Design.png

このような構成を FuelPHP で行う場合の注意点を書いておきます。

図と、以降の説明では ElastiCache(Redis)を使っていますが、注意点についてはRDBMSだろうが普通のMemcacheだろうが同じです。


セッションストアの指定

FuelPHP では、セッションストアの指定を app/config/session.php でまず指定します。(なお、環境に応じて設定を変更したい場合は、 config/staging/session.php などに記述すればOK)

Redisを使うのであれば、session.phpの記述は以下のようになります。


session.php

<?php

return array(
'driver' => 'redis',
'redis' => array(
'cookie_name' => 'fuelrid',
'database' => 'default',
),
);


さらにRedisの場合は、db.phpに接続先の情報を記述します。


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.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";


参考