WordPressで安全にPHPセッションを管理する方法と注意点

※本ブログの目的は個人の備忘録であり、コードは参考用として掲載しています。
実際に使用される際は、ご自身の環境で十分に動作確認を行ってください。
コードの利用によって生じたいかなる問題についても責任を負いかねますので、あらかじめご了承ください。

WordPressでは元々「セッションレス」で動作しますが、例えば ログインしていないユーザーのアクセス制御一時的なページフラグ管理 のためにPHPセッションを使うことがあります。

しかし、session_start() をそのまま使うとサイトヘルス警告やREST APIトラブルにつながることがあります。

PHPセッションの基本

PHPセッションはサーバー上にファイルを作り、ユーザーごとの一時データを管理します。

session_start(); // セッション開始
$_SESSION['key'] = 'value'; // データ保存
session_write_close(); // ロック解除
  • session_start() を呼ぶとセッションファイルが排他ロックされます。
  • session_write_close() を呼ばないと、同じユーザーからの次のHTTPリクエスト(ページ遷移やAjax、REST APIなどの情報のリクエスト)がブロックされることがあります。

トラブルの例

サイトヘルス警告

session_start() 関数の呼び出しによって PHP セッションが作成されました。
これは REST API およびループバックリクエストを妨害します。
HTTP リクエストを行う前に、session_write_close() を使ってセッションを閉じる必要があります。

WordPressはREST APIや内部ループバックリクエストを多用するため、セッションファイルがロックされるとリクエストがブロックされます。

セッションロックによる遅延

  • AjaxやREST APIが動作しない、遅延する
  • POST処理後にリダイレクトが止まることがある

全ページでセッションを開始すると不要な負荷

全ページで session_start() を呼ぶと、サーバーに余計なデータのやり取りが発生します。

安全にセッションを使う方法

必要なページだけでセッションを開始

同じリクエスト内で二重に session_start() を呼ぶと 警告が出る ことがあります。

PHP_SESSION_NONE は「セッションは有効だがまだ開始されていない」状態を表します。これをチェックすることで、同じリクエストで二重に session_start() が呼ばれるのを防げます。

PHP_SESSION_NONE をチェックしてから開始することで、不要な警告を防ぎ、安全にセッションを開始できます。

add_action('template_redirect', function() {
    // 会員限定ページだけでセッション開始
    if (is_page(array('members','premium')) && session_status() === PHP_SESSION_NONE) {
        session_start();
    }
}, 1);

フラグを書き込んだらすぐ閉じる

PHPセッションは排他ロックがかかるため、開きっぱなしの状態では同じユーザーから送信される次のHTTPリクエスト(ページ遷移やAjax、REST API呼び出しなど)が処理待ちになり、リクエストの応答が遅れたりタイムアウトすることがあります。

session_write_close() を呼ぶことでセッションのロックが解除され、次のHTTPリクエストもブロックされずにスムーズに処理されるようになります。

if (is_page('members') && isset($_POST['agree'])) {
    $_SESSION['member_access_granted'] = true;
    session_write_close(); // ロックを解除
    wp_redirect(home_url('/members/dashboard/'));
    exit;
}

用途ごとにセッション名を分ける(必要に応じて)

用途ごとにセッション名を分けることで、同じドメイン内で複数のアプリケーションや機能がセッションを使ってもデータが衝突せず、独立して管理できます。

function my_start_session() {
    if (is_page(array('members', 'premium')) && session_status() === PHP_SESSION_NONE) {
        if (is_page('members') {
            session_name('members_session');
        } elseif (is_page('premium')) {
            session_name('premium_session');
        }
        session_start();
    }
}
add_action('template_redirect', 'my_start_session', 1);

アクセス制御時にチェック

フラグがセットされていないユーザーはログインページや利用規約ページにへリダイレクトする、などの処理を実行させます。

if (is_page('premium') && empty($_SESSION['member_access_granted'])) {
    wp_redirect(home_url('/members/login/'));
    exit;
}

実務での推奨フロー

  • 会員ページやフラグ管理ページなどの必要なページだけで session_start()
  • フラグを書き込んだらすぐに session_write_close()
  • 不要ページではセッションを立ち上げない

まとめ

  • WordPressでは「全ページでセッションを開始」は避ける
  • 必要ページでのみセッション開始 → 書き込み後はすぐ閉じる

こうすることで、REST APIやAjaxの遅延を防ぎつつ、安全にPHPセッションを利用できます。

参考