今回の記事ではRedisをセッションデータストアとして使用する方法を学習していきます。本記事ではRedisサーバと別のRedisクライアントサーバの2台のセットアップが完了していることを前提に解説していきます。これらサーバのセットアップがまだの方は以下の記事を学習してからこちらに戻ってきてください。

RedisをPHPのセッションDBとして使う場合
PHPのセッションにRedisを使用する場合、2つ方法があります。
選択肢1)RedisサーバーのTLSを使用せず、内部ネットワークでのみ接続許可して使用する。
PHPでセッションストアをRedisに指定する場合、TLSに必要なTLSの各証明書をPHPの設定ファイルに記述する方法がないのでデフォルト設定としてRedis+TLSを指定することはできません。なので、TLS無しで安全に通信を行うためには内部ネットワークのみでRedisサーバを使用する必要があります。Redis側でIPの制限やセキュリティーグループを使用してRedisサーバにアクセスできるサーバを制限する必要があります。
Redisをパブリックアクセス可能な状態(0.0.0.0)にしてパスワード指定もIP制限もない場合は誰でもRedisサーバにアクセスすることができてしまうので、こうした制限の追加は必須となります。
選択肢2)PHP側でSessionHandlerInterface のクラスの実装をしてTLSを使用する。
SessionHandlerInterfaceの実装をする際にTLSの各種証明書の設定ができます。ランタイム時にこの実装をセッションハンドラーに渡すことでRedisとはTLSを使った通信が可能になります。
それぞれの設定方法を見ていきましょう。
TLS無しでRedisをセッションDBとして設定する
まずは、Redisサーバ側の設定を行います。
Redisサーバ側の設定
Redisの設定ファイルが以下になるように変更してください。動作確認用の為パスワードはデフォルトのものをそのまま使用しています。
【Redis設定ファイル】
/etc/redis6/redis6.conf
#bind 127.0.0.1 -::1
bind 0.0.0.0
#protected-mode yes
protected-mode no
port 6379
# requirepass foobared
requirepass foobared
【Redisの再起動】
systemctl restart redis6
Redisの再起動がうまくいかない場合はログを確認してみましょう。
/var/log/redis6/redis6.log
クライアントサーバの設定
次にクライアントサーバ側のPHPの設定ファイルを変更していきます。
PHP-FPMの設定ファイル
PHP-FPMのファイルを以下のように変更します。セッションハンドラーにRedisを指定し、保存先にRedisサーバのドメインとパスワードを指定します。
【PHP-FPMの設定ファイル】
/etc/php-fpm.d/www.conf
;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session
php_value[session.save_handler] = redis
php_value[session.save_path] = "tcp://Redisサーバのドメイン又はIP:6379?auth=foobared"
【PHP-FPMを再起動】
sudo systemctl restart php-fpm
編集するファイルはphp-fpmの設定ファイルです。変更する設定ファイルは/etc/php.iniでは無いことに注意しましょう。
設定反映の確認
phpinfo();を使ってReidsがセッションに設定されたことを確認しましょう。
phpinfo.php
<?php
echo phpinfo();
?>
> 以下の様に表示されれば正しく設定されています。
-
session.save_handler redis redis
session.save_path tcp://Redisサーバのドメイン又はIP:6379 tcp://Redisサーバのドメイン又はIP:6379
-
クライアントから非TLSでRedisサーバにアクセス
PHP-FPMのセッションハンドラーにredisを設定してあるので、session_start() 関数が実行されると自動的にPHPのセッションIDをキーとしてRedis上にデータを作成します。
session.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
//セッションの開始
session_start();
//データをセッションに格納
$_SESSION['user'] = 'User';
echo "session set<br/>";
//セッションからデータを取得
$user = $_SESSION['user'];
echo "Data from Session: ".$user;
?>
格納されたデータが取得・表示できていれば成功です。
Redisサーバ側でのセッションデータの確認
Redisはデフォルトでは16個のDBが利用可能で、デフォルトでは0番目のDBが使用されます。セッションキーは次のような “PHPREDIS_SESSION:ランダムな文字列” のフォーマットになります。
【Redis CLIを起動】
sudo redis6-cli
【パスワードを入力】
AUTH foobared
【使用されているデータベースを表示】
INFO keyspace
# Keyspace
db0:keys=2,expires=1,avg_ttl=1424898
【キーの表示】
KEYS *
1) "test_key"
2) "PHPREDIS_SESSION:s8na0poilbcqe2ebj0mjr5b5r7"
【セッションキーからセッションデータを表示】
get PHPREDIS_SESSION:s8na0poilbcqe2ebj0mjr5b5r7
"user|s:5:\"User\";"
クライアントのPHP側でセッションに格納したデータが表示されれば成功です。
セッションキーが見つからない場合は次のようにデータベースの番号を変更しながら全てのキーを表示してみましょう。
SELECT 1 でDBを切り替える
KEYS * で全てのキーを表示してみる
上記の例ではTLSを使用していないので、Redisの設定ファイルのbind項目でIPを制限するかセキュリリティーグループでRedisサーバにアクセスできるサーバを制限する必要がありますが、ここでは紹介していません。各自で試してみましょう。
一つのデータベース内のデータをすべて削除する場合は以下のコマンドを使用します。
FLUSHDB
TLSをオンにしてRedisをセッションDBとして設定する
Redisサーバ側の設定
Redisサーバ側の設定ファイルが以下になるように変更してください。
【Redis設定ファイル】
/etc/redis6/redis6.conf
#bind 127.0.0.1 -::1
bind 0.0.0.0
#protected-mode yes
protected-mode no
#port 6379
port 0
# tls-port 6379
tls-port 6379
# tls-cert-file redis.crt
# tls-key-file redis.key
tls-cert-file /usr/local/etc/openssl/server-redis-rsa.crt
tls-key-file /usr/local/etc/openssl/server-redis-rsa.key
# tls-ca-cert-file ca.crt
tls-ca-cert-file /usr/local/etc/openssl/ca.crt
# tls-auth-clients no
tls-auth-clients yes
# tls-protocols "TLSv1.2 TLSv1.3"
tls-protocols "TLSv1.2 TLSv1.3"
# requirepass foobared
requirepass foobared
【Redisの再起動】
sudo systemctl restart redis6
クライアントサーバ側の設定
セッションハンドラーインターフェースを実装してランタイムで使用するので、PHP-FPMに設定したsession.save_path の設定は不要なので空にしておきます。
【PHP-FPMの設定ファイル】
/etc/php-fpm.d/www.conf
;php_value[session.save_path] = "tcp://Redisサーバのドメイン又はIP:6379?auth=foobared"
php_value[session.save_path] = ""
【PHP-FPMを再起動】
sudo systemctl restart php-fpm
クライアントからTLSでRedisサーバにアクセス
SessionHandlerInterface の実装の例を以下に示します。
session_tls.php
<?php
error_reporting(E_ERROR);
ini_set('display_errors', 1);
class RedisSessionHandler implements SessionHandlerInterface {
private Redis $redis;
private string $prefix;
private int $ttl;
public function __construct(string $host = '127.0.0.1', int $port = 6379, string $password = '', string $prefix = 'PHPSESSID:', int $ttl = 1440) {
$this->redis = new Redis();
$context = [
'stream' => [
'verify_peer' => true,
'cafile' => '/usr/local/etc/openssl/ca.crt',
'local_cert' => '/usr/local/etc/openssl/client-redis-rsa.crt',
'local_pk' => '/usr/local/etc/openssl/client-redis-rsa.key',
],
];
$this->redis->connect($host, $port, 1.5, null, 0, 0, $context);
if ($password !== '') {
if (!$this->redis->auth($password)) {
throw new RuntimeException("Redis authentication failed");
}
}
$this->prefix = $prefix;
$this->ttl = $ttl;
}
public function open($savePath, $sessionName): bool {
return true;
}
public function close(): bool {
return $this->redis->close();
}
public function read($id): string {
$data = $this->redis->get($this->prefix . $id);
return $data !== false ? $data : '';
}
public function write($id, $data): bool {
return $this->redis->setex($this->prefix . $id, $this->ttl, $data);
}
public function destroy($id): bool {
return $this->redis->del($this->prefix . $id) > 0;
}
public function gc($maxLifetime): int|false {
return true;
}
}
$handler = new RedisSessionHandler(
host: 'tls://Redisサーバのドメイン名又はIP',
port: 6379,
password: 'foobared',
prefix: 'PHPREDIS_SESSION:',
ttl: 1800
);
session_set_save_handler($handler, true);
session_start();
//データをセッションに格納
$_SESSION['user'] = 'User-TLS';
echo "session set<br/>";
//セッションからデータを取得
$user = $_SESSION['user'];
echo "Data from Session: ".$user;
?>
格納されたデータが取得・表示できていれば成功です。
Redisサーバ側でのセッションデータの確認
TLSがオンでRedisサーバ上でRedis CLIを起動する場合は各証明書の指定が必要です。
【Redis CLIを起動】
sudo redis6-cli --tls \
--cert /usr/local/etc/openssl/client-redis-rsa.crt \
--key /usr/local/etc/openssl/client-redis-rsa.key \
--cacert /usr/local/etc/openssl/ca.crt \
-h 127.0.0.1 \
-p 6379
【パスワードを入力】
AUTH foobared
【使用されているデータベースを表示】
INFO keyspace
# Keyspace
db0:keys=2,expires=1,avg_ttl=1424898
【キーの表示】
KEYS *
1) "PHPREDIS_SESSION:s8na0poilbcqe2ebj0mjr5b5r7"
【セッションキーからセッションデータを表示】
GET PHPREDIS_SESSION:s8na0poilbcqe2ebj0mjr5b5r7
"user|s:8:\"User-TLS\";"
クライアントのPHP側でセッションに格納したデータが表示されれば成功です。
まとめ
今回の記事ではPHPのセッションストアにRedisを使う方法を学習しました。Redisの使い方には2種類ありましたね。TLSを設定せずに内部ネットワークのみで使用する方法とTLSを設定する方法がありました。共にパスワードを設定しておくとより安全です。それぞれRedisの設定ファイルの変更箇所も確認してきました。最後にセッションハンドラーインターフェースの実装例を示して、TLSを使用したRedisとの通信も学びました。これらのスキルを習得して是非セッション管理に役立てていきましょう。