CodeIgniterでセッションを共有する

別アプリが稼働している環境へCodeIgniterを追加する必要が出てきました。その際にセッションを共有する必要がありました。
その際の作業内容をメモしておきます。

1. 前提条件

もともと稼働していたアプリは素のPHPで書かれたもので、ざっくり書くと下記のような感じ。

PHP
session_start();
$_SESSION['var'] = 'hoge';


すでに稼働中のため、アプリ側に手を加えることができない状況です。

2. とりあえず動かしてみる

まずは、現状の確認をするためにアプリ、CodeIgniter両方を動かしてみます。

2-1. 既存のアプリ側の挙動

アプリ側のセッションは下記のように生成されます。

$ cd /var/lib/php/session/
$ ls -l
-rw-------  1 root root 0 2017-01-29 19:01 sess_e8ortt053tr6c1nrop7ad1qor1
-rw-------  1 root root 0 2017-02-02 09:10 sess_aagtr98n7mmcpdrq4k492p8ef6

プレフィックスのsess_はphp内でハードコーディングされている定数です。ランダムな英数字は26文字です。セッションクッキーの名前はPHPSESSIDDでした。

2-2. CodeIgniter側の挙動

一方、CodeIgniterは下記のように生成されました。

$ cd /var/lib/php/session/
$ ls -l
-rw-------  1 root root 0 2017-01-29 19:01 ci_session5a5c728caa0cf776de78a14f9da64f149fb86a9f
-rw-------  1 root root 0 2017-02-02 09:10 ci_session61ada784b1fd80dbc6442d4c24ec9c271b50ac39

プレフィックスはci_session、ランダムな英数字は40文字、セッションクッキーの名前はci_sessionでした。

セッションの保存場所は同じでしたが、下記の点が違いました。

セッション共有までの課題

  • セッションクッキーの名前が異なる
  • セッションのファイル名が異なる
    • プレフィックスが異なる
    • ランダムな英数字の文字数が異なる

それぞれを同じになるように調整をする必要があります。

3. セッションクッキーの名前 を合わせる

こちらは簡単です。application/config/config.phpを変更します。$config['sess_cookie_name']を空文字にすることでini_get('session.name');が利用されます。

application/config/config.php
$config['sess_cookie_name'] = '';

4. セッションのファイル名 を合わせる

こちらは、プレフィックス文字数を変更します。

4-1. セッションファイルのプレフィックスを合わせる

Session_files_driver.phpを拡張するため、application/libraries/Session/drivers/MY_Session_files_driver.phpを作成します。ファイルの中は以下の通りです。sess_はハードコーディングします。

MY_Session_files_driver.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
 
class MY_Session_files_driver extends CI_Session_files_driver  {
 
    public function open($save_path, $name)
    {
        parent::open($save_path, $name);
        $this->_file_path = $this->_config['save_path'].DIRECTORY_SEPARATOR
            .'sess_' // ← ここがポイント
            .($this->_config['match_ip'] ? md5($_SERVER['REMOTE_ADDR']) : '');
 
        return $this->_success;
    }
}

4-2. セッションファイルの文字数を合わせる

ここが一番悩んだところでした。Session.phpの下記の箇所でアプリ側のセッションクッキーが削除されてしまい、セッションの共有ができませんでした。$this->_sid_regexpの正規表現パターンにマッチしていませんでした。

Session.php
// Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers
if (isset($_COOKIE[$this->_config['cookie_name']])
    && (
        ! is_string($_COOKIE[$this->_config['cookie_name']])
        OR ! preg_match('#\A'.$this->_sid_regexp.'\z#', $_COOKIE[$this->_config['cookie_name']])
    )
)
{
    unset($_COOKIE[$this->_config['cookie_name']]);
}

そこで、Session.phpを継承し、$this->_sid_regexpを書き換えます。application/libraries/Session/MY_Session.phpとして下記の内容でファイルを作成します。

MY_Session.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
 
class MY_Session extends CI_Session  {
 
    protected function _configure_sid_length()
    {
        parent::_configure_sid_length();
        $this->_sid_regexp = preg_replace('#\A(.*)\{\d+\}\z#', '${1}+', $this->_sid_regexp);
    }
}

以上で既存のアプリとCodeIgniter間でセッションの共有ができるようになりました。