はじめに
PHPでWebアプリケーションを開発する際、ユーザーのログイン状態やカート情報を保持するためにセッションは欠かせない機能です。セッションのデータをどこにどのように保存するかを決める「セッションモジュール(ハンドラ)」は、アプリケーションのパフォーマンスやスケーラビリティに直結します。
今回解説する session_module_name() は、現在使用中のセッションモジュール名を取得・変更できる関数です。地味に見えて、複数サーバー構成やRedis・Memcachedとの連携時に非常に重要な役割を果たします。
関数の概要
| 項目 | 内容 |
|---|
| 関数名 | session_module_name() |
| 所属 | PHP セッション関数 |
| 導入バージョン | PHP 4以降 |
| PHP 8.x | 対応済み |
構文
session_module_name(string $module = ?): string|false
パラメータ
| パラメータ | 型 | 説明 |
|---|
$module | string(省略可) | 設定したいセッションモジュール名。省略すると現在の値を返すのみ。 |
戻り値
- 引数なし(取得):現在のセッションモジュール名(文字列)を返します。
- 引数あり(変更):変更前のモジュール名(文字列)を返します。
- 失敗時:
false を返します。
⚠️ 注意:session_start() を呼び出した後に session_module_name() でモジュールを変更しようとすると、エラーが発生します。必ず session_start() の前に呼び出してください。
基本的な使い方
モジュール名の取得
<?php
// セッションを開始する前に確認
$moduleName = session_module_name();
echo "現在のセッションモジュール: " . $moduleName;
// 出力例: 現在のセッションモジュール: files
モジュール名の変更
<?php
// session_start() の前に変更する
$oldModule = session_module_name('user'); // カスタムハンドラへ変更
echo "変更前のモジュール: " . $oldModule; // 変更前の名前を返す
session_start();
代表的なモジュール名
| モジュール名 | 説明 |
|---|
files | デフォルト。サーバーのファイルシステムに保存 |
user | session_set_save_handler() で登録したカスタムハンドラを使用 |
memcache | Memcacheモジュール使用時(pecl/memcache) |
memcached | Memcachedモジュール使用時(pecl/memcached) |
redis | RedisSessionHandler使用時 |
sqlite | SQLiteに保存(古い環境) |
実践的なクラスベースの使用例
例1:セッションモジュール診断クラス
<?php
/**
* セッションモジュール診断クラス
* 現在の環境でどのモジュールが使用されているかを診断する
*/
class SessionModuleDiagnostics
{
private array $knownModules = [
'files' => 'ファイルシステム(デフォルト)',
'user' => 'カスタムユーザーハンドラ',
'memcache' => 'Memcache(pecl/memcache)',
'memcached' => 'Memcached(pecl/memcached)',
'redis' => 'Redis',
'sqlite' => 'SQLite',
];
public function diagnose(): array
{
$current = session_module_name();
return [
'module_name' => $current,
'description' => $this->knownModules[$current] ?? '不明なモジュール',
'save_path' => session_save_path(),
'is_file_based' => ($current === 'files'),
'session_status'=> $this->getStatusLabel(session_status()),
];
}
private function getStatusLabel(int $status): string
{
return match ($status) {
PHP_SESSION_DISABLED => '無効',
PHP_SESSION_NONE => '有効(未開始)',
PHP_SESSION_ACTIVE => '有効(開始済み)',
default => '不明',
};
}
public function report(): void
{
$info = $this->diagnose();
echo "=== セッションモジュール診断レポート ===\n";
foreach ($info as $key => $value) {
printf("%-20s: %s\n", $key, $value);
}
}
}
$diag = new SessionModuleDiagnostics();
$diag->report();
/*
出力例:
=== セッションモジュール診断レポート ===
module_name : files
description : ファイルシステム(デフォルト)
save_path : /var/lib/php/sessions
is_file_based : 1
session_status : 有効(未開始)
*/
例2:Redis セッションハンドラ切り替えクラス
<?php
/**
* 環境に応じてセッションストレージを切り替えるクラス
* 本番環境ではRedis、開発環境ではファイルを使用する例
*/
class SessionStorageConfigurator
{
private string $environment;
private array $redisConfig;
public function __construct(string $environment, array $redisConfig = [])
{
$this->environment = $environment;
$this->redisConfig = array_merge([
'host' => '127.0.0.1',
'port' => 6379,
'auth' => null,
'ttl' => 1800,
], $redisConfig);
}
public function configure(): string
{
if (session_status() === PHP_SESSION_ACTIVE) {
throw new \RuntimeException('セッション開始後は設定を変更できません');
}
$previousModule = session_module_name();
if ($this->environment === 'production' && extension_loaded('redis')) {
$this->configureRedis();
$applied = 'redis';
} else {
// ファイルシステム(デフォルトのまま)
$applied = session_module_name(); // 'files'
}
echo "環境: {$this->environment}\n";
echo "変更前モジュール: {$previousModule}\n";
echo "適用モジュール: {$applied}\n";
return $applied;
}
private function configureRedis(): void
{
$dsn = "tcp://{$this->redisConfig['host']}:{$this->redisConfig['port']}";
if ($this->redisConfig['auth']) {
$dsn .= "?auth={$this->redisConfig['auth']}";
}
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', $dsn);
// ※ Redis拡張の設定では session_module_name('redis') ではなく
// ini_set で save_handler を設定するケースもある
}
}
$configurator = new SessionStorageConfigurator('development');
$configurator->configure();
例3:カスタムDBセッションハンドラクラス
<?php
/**
* MySQLにセッションデータを保存するカスタムハンドラ
* session_module_name('user') と組み合わせて使用する
*/
class DatabaseSessionHandler implements \SessionHandlerInterface
{
private \PDO $pdo;
public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}
public function open(string $path, string $name): bool
{
return true;
}
public function close(): bool
{
return true;
}
public function read(string $id): string|false
{
$stmt = $this->pdo->prepare(
"SELECT data FROM sessions WHERE id = :id AND expires_at > NOW()"
);
$stmt->execute([':id' => $id]);
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
return $row ? $row['data'] : '';
}
public function write(string $id, string $data): bool
{
$stmt = $this->pdo->prepare(
"INSERT INTO sessions (id, data, expires_at)
VALUES (:id, :data, DATE_ADD(NOW(), INTERVAL :ttl SECOND))
ON DUPLICATE KEY UPDATE data = :data, expires_at = DATE_ADD(NOW(), INTERVAL :ttl SECOND)"
);
return $stmt->execute([
':id' => $id,
':data' => $data,
':ttl' => (int) ini_get('session.gc_maxlifetime'),
]);
}
public function destroy(string $id): bool
{
$stmt = $this->pdo->prepare("DELETE FROM sessions WHERE id = :id");
return $stmt->execute([':id' => $id]);
}
public function gc(int $max_lifetime): int|false
{
$stmt = $this->pdo->prepare("DELETE FROM sessions WHERE expires_at < NOW()");
$stmt->execute();
return $stmt->rowCount();
}
}
// --- 登録と利用 ---
/*
$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
$handler = new DatabaseSessionHandler($pdo);
session_set_save_handler($handler, true);
// 'user' モジュールを明示的に指定
$prev = session_module_name('user');
echo "変更前: {$prev}\n"; // files
session_start();
$_SESSION['user_id'] = 42;
*/
例4:セッションモジュール切り替えファクトリ
<?php
/**
* 利用可能な拡張に応じて最適なセッションモジュールを自動選択するクラス
*/
class SessionModuleFactory
{
/** 優先順位順のモジュール候補 */
private array $preferenceList;
public function __construct(array $preferenceList = [])
{
$this->preferenceList = $preferenceList ?: [
['module' => 'redis', 'extension' => 'redis'],
['module' => 'memcached', 'extension' => 'memcached'],
['module' => 'memcache', 'extension' => 'memcache'],
['module' => 'files', 'extension' => null], // フォールバック
];
}
public function selectBest(): string
{
foreach ($this->preferenceList as $candidate) {
$ext = $candidate['extension'];
if ($ext === null || extension_loaded($ext)) {
echo "選択されたモジュール: {$candidate['module']}\n";
return $candidate['module'];
}
echo "スキップ(拡張なし): {$candidate['module']}\n";
}
return 'files'; // 最終フォールバック
}
public function applyBest(): string
{
if (session_status() === PHP_SESSION_ACTIVE) {
throw new \RuntimeException('セッション開始後は変更不可');
}
$best = $this->selectBest();
$prev = session_module_name(); // 現在値を取得
if ($best !== 'files' && $best !== 'user') {
// Redisなどは ini_set で設定するため、ここではログのみ
echo "モジュール '{$best}' の適用には別途 ini_set が必要な場合があります\n";
}
echo "適用前モジュール: {$prev}\n";
return $best;
}
}
$factory = new SessionModuleFactory();
$factory->applyBest();
/*
出力例(Redis拡張なし、Memcachedあり):
スキップ(拡張なし): redis
選択されたモジュール: memcached
適用前モジュール: files
モジュール 'memcached' の適用には別途 ini_set が必要な場合があります
*/
例5:セッションモジュールのユニットテスト補助クラス
<?php
/**
* テスト時にセッションモジュールを安全に切り替え・復元するクラス
* PHPUnit などのテスト環境での利用を想定
*/
class SessionModuleSwitcher
{
private ?string $originalModule = null;
private bool $wasActive = false;
public function setUp(string $targetModule = 'user'): void
{
// セッションが動いていれば一旦閉じる
if (session_status() === PHP_SESSION_ACTIVE) {
$this->wasActive = true;
session_write_close();
}
$this->originalModule = session_module_name();
echo "テスト用モジュール設定: {$this->originalModule} → {$targetModule}\n";
session_module_name($targetModule);
}
public function tearDown(): void
{
if ($this->originalModule !== null) {
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
session_module_name($this->originalModule);
echo "モジュール復元: {$this->originalModule}\n";
$this->originalModule = null;
}
}
public function getCurrentModule(): string
{
return session_module_name();
}
}
// テスト利用イメージ
$switcher = new SessionModuleSwitcher();
$switcher->setUp('user');
echo "現在のモジュール: " . $switcher->getCurrentModule() . "\n";
// ... テスト処理 ...
$switcher->tearDown();
例6:セッションモジュール情報をJSON出力する監視クラス
<?php
/**
* セッションモジュールの状態を監視・JSON出力するクラス
* ヘルスチェックエンドポイントや管理画面での利用を想定
*/
class SessionModuleMonitor
{
public function getStatus(): array
{
$module = session_module_name();
$savePath = session_save_path();
$status = [
'module' => $module,
'save_path' => $savePath ?: '(php.ini のデフォルト)',
'session_id' => session_id() ?: null,
'gc_maxlifetime'=> (int) ini_get('session.gc_maxlifetime'),
'cookie_secure' => (bool) ini_get('session.cookie_secure'),
'cookie_httponly'=> (bool) ini_get('session.cookie_httponly'),
'use_strict_mode'=> (bool) ini_get('session.use_strict_mode'),
'checked_at' => date('Y-m-d H:i:s'),
];
// モジュール固有の警告
$status['warnings'] = $this->getWarnings($module, $status);
return $status;
}
private function getWarnings(string $module, array $status): array
{
$warnings = [];
if ($module === 'files' && php_uname('s') === 'Linux') {
$warnings[] = '複数サーバー構成ではセッション共有ができません。Redisなどを検討してください。';
}
if (!$status['cookie_secure']) {
$warnings[] = 'session.cookie_secure が無効です。HTTPS環境では有効化を推奨します。';
}
if (!$status['cookie_httponly']) {
$warnings[] = 'session.cookie_httponly が無効です。XSS対策のため有効化を推奨します。';
}
if (!$status['use_strict_mode']) {
$warnings[] = 'session.use_strict_mode が無効です。セッション固定攻撃への耐性を高めるため有効化を推奨します。';
}
return $warnings;
}
public function toJson(): string
{
return json_encode($this->getStatus(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
}
$monitor = new SessionModuleMonitor();
echo $monitor->toJson();
/*
出力例:
{
"module": "files",
"save_path": "(php.ini のデフォルト)",
"session_id": null,
"gc_maxlifetime": 1440,
"cookie_secure": false,
"cookie_httponly": false,
"use_strict_mode": false,
"checked_at": "2025-09-01 12:00:00",
"warnings": [
"複数サーバー構成ではセッション共有ができません。Redisなどを検討してください。",
"session.cookie_secure が無効です。HTTPS環境では有効化を推奨します。",
...
]
}
*/
関連関数との比較
| 関数 | 役割 |
|---|
session_module_name() | セッションモジュール(ハンドラ種別)の取得・変更 |
session_set_save_handler() | user モジュール用のカスタム保存ハンドラを登録 |
session_save_path() | セッションデータの保存先パス(URL)を取得・変更 |
session_start() | セッションを開始(これより前に設定が必要) |
ini_set('session.save_handler', ...) | php.ini レベルでハンドラを変更(Redis等で使用) |
session_module_name() と ini_set() の使い分け
files ↔ user の切り替え:session_module_name() が直接使える
- Redis・Memcached の設定:多くの場合
ini_set('session.save_handler', 'redis') と ini_set('session.save_path', ...) の組み合わせを使う
- どちらも
session_start() より前に呼ぶ必要がある点は共通
よくある使用シーンまとめ
- 現在のモジュール確認:デバッグや管理画面でのヘルスチェック
- テスト環境でのモジュール切り替え:ファイルベースとカスタムハンドラを切り替えてテスト
- カスタムDBハンドラ登録時:
session_set_save_handler() と組み合わせて 'user' を指定
- 環境別設定:開発では
files、本番では Redis という設定の自動切り替え
- セキュリティ監査:セッション設定の一括チェックと警告出力
注意点・落とし穴
<?php
// ❌ NG:session_start() の後で変更しようとするとエラー
session_start();
session_module_name('user'); // Warning: Cannot change save handler when session is active
// ✅ OK:session_start() の前に変更する
session_module_name('user');
session_start();
<?php
// ❌ NG:'redis' を直接指定してもRedis拡張が入っていなければ機能しない
session_module_name('redis'); // 拡張がなければセッション開始時にエラー
// ✅ OK:拡張の存在を確認してから設定する
if (extension_loaded('redis')) {
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379');
}
session_start();
まとめ
| 項目 | 内容 |
|---|
| 関数名 | session_module_name(?string $module): string|false |
| 主な用途 | セッション保存モジュールの取得・変更 |
| 呼び出しタイミング | 必ず session_start() より前 |
| 戻り値 | 現在(または変更前)のモジュール名 |
| デフォルト値 | files |
| カスタムハンドラ使用時 | 'user' を指定し session_set_save_handler() と併用 |
session_module_name() は一見地味な関数ですが、スケールアウトが必要な本番環境や、テストコードの品質向上において非常に重要な役割を担います。デフォルトの files モジュールで問題ない小規模アプリでも、将来の拡張に備えてこの関数の存在を覚えておきましょう。
参考リンク