Laravel のセッションを非 Laravel のプロジェクトと共有する
基本的な手順は kojirockさんのこちらの記事 を参考にさせていただきました。ありがとうございます。
1. 必要なライブラリをインストール
$ composer require illuminate/encryption
2. Laravel用sessionテーブル作成
3. Laravel側session設定
Laravel側の設定なので、このあたりを参照してください
4. Laravel側session設定を共有したいプロジェクトで定数として設定
例えばこんな感じ
<?php define("LARAVEL_APP_KEY", "base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); define("SESSION_NAME", "laravel_session"); define("SESSION_TIME", time() + (120 * 60)); define("SESSION_PATH", "/"); define("SESSION_DOMAIN", null); define("SESSION_SECURE", false); define("SESSION_HTTP_ONLY", true); define("LARAVEL_CIPHER", "AES-256-CBC"); define("DBNAME", "dbname"); define("DBHOST", "127.0.0.1"); define("DBUSER", "hoge"); define("DBPASSWORD", "fuga");
5. SessionHandlerを作成
kojirock さんの記事を参考にしつつ、session_regenerate_id に対応できるように create_sid メソッドを追加しています
<?php namespace MyApp\Session; use Illuminate\Encryption\Encrypter; use Illuminate\Support\Str; class AppSessionHandler implements \SessionHandlerInterface { /** * @var string */ protected $decryptSessionId; /** * @var \PDO */ protected $pdo; /** * AppSessionHandler constructor. * @param string $decryptSessionId * @param \PDO $pdo */ public function __construct($decryptSessionId, \PDO $pdo) { $this->decryptSessionId = $decryptSessionId; $this->pdo = $pdo; } /** * @param string $savePath * @param string $name * @return bool */ public function open($savePath, $name) { return true; } /** * @param string $sessionId * @return string */ public function read($sessionId) { $stmt = $this->pdo->prepare("SELECT payload FROM sessions WHERE id = :id"); $stmt->bindValue(":id", $this->decryptSessionId); $stmt->execute(); $results = $stmt->fetchColumn(); $stmt->closeCursor(); return is_null($results) ? '' : base64_decode($results); } /** * @param string $sessionId * @param string $sessionData * @return bool */ public function write($sessionId, $sessionData) { $sql = <<<SQL INSERT INTO sessions (id, ip_address, user_agent, payload, last_activity) VALUES(:id, :ip_address, :user_agent, :payload, :last_activity) ON DUPLICATE KEY UPDATE last_activity = :last_activity, payload = :payload SQL; if ($this->isEncryptSessionId($sessionId)) { $sessionId = $this->decryptSessionId($sessionId); } $payload = $this->getSavePayload($sessionId, $sessionData); $stmt = $this->pdo->prepare($sql); $stmt->bindValue(":id", $sessionId); $stmt->bindValue(":ip_address", $_SERVER['REMOTE_ADDR']); $stmt->bindValue(":user_agent", $_SERVER['HTTP_USER_AGENT']); $stmt->bindValue(":payload", base64_encode(serialize($payload))); $stmt->bindValue(":last_activity", time()); $stmt->execute(); $results = $stmt->rowCount(); $stmt->closeCursor(); return ($results) ? true : false; } /** * @param string $sessionId * @return bool */ public function destroy($sessionId) { $stmt = $this->pdo->prepare("DELETE FROM sessions WHERE id = :id"); $stmt->bindValue(":id", $this->decryptSessionId); $stmt->execute(); $stmt->closeCursor(); return true; } /** * @return bool */ public function close() { return true; } /** * @param int $maxlifetime * @return bool */ public function gc($maxlifetime) { $stmt = $this->pdo->prepare("DELETE FROM sessions WHERE last_activity < :lastActivity"); $stmt->bindValue(":lastActivity", $maxlifetime); $stmt->execute(); $stmt->closeCursor(); return true; } /** * 新しい sessionIDの作成 * @return string */ public function create_sid() { $sessionId = Str::random(40); return $sessionId; } /** * @param string $sessionId * @param string $sessionData * @return array */ protected function getSavePayload($sessionId, $sessionData) { // DB から保存されているデータを取得 $registeredPayload = $this->read($sessionId); if (strlen($registeredPayload) >= 1) { $registeredPayload = unserialize($registeredPayload); } else { // 保存されているデータがなければ初期化 $registeredPayload = $this->initPayload(); } if (strlen($sessionData) >= 1) { // セッションとして登録したいデータがあれば上書き $payload = unserialize($sessionData); } else { // セッションとして登録したいデータがなければデータを保持 $payload = $registeredPayload; } $payload['_previous'] = ['url' => $_SERVER['HTTP_REFERER']]; return $payload; } /** * payloadの初期化 * @return array */ protected function initPayload() { return $payload = [ '_token' => Str::random(40), '_flash' => ['old' => [], 'new' => []] ]; } /** * 暗号化された sessionID かどうかの判別 * @param $sessionId * @return bool */ protected function isEncryptSessionId($sessionId) { if (is_string($sessionId) && ctype_alnum($sessionId) && strlen($sessionId) === 40) { return false; } else { return true; } } /** * 暗号化された sessionID の復号 * @param $sessionId * @return string */ protected function decryptSessionId($sessionId) { $encryptValue = base64_decode(substr(LARAVEL_APP_KEY, 7)); $encrypter = new Encrypter($encryptValue, LARAVEL_CIPHER); $decryptSessionId = $encrypter->decrypt($sessionId); return $decryptSessionId; } }
6. カスタムセッションハンドラの設定
4. で設定した定数を /var/www/config.php に、5. で設定したSessionHandlerを /var/www/class_session_handler.php に置いていたとして
<?php require_once '/var/www/config.php'; require_once '/var/www/class_session_handler.php'; use Illuminate\Encryption\Encrypter; use Illuminate\Support\Str; use MyApp\Session; ini_set('session.serialize_handler', 'php_serialize'); $encryptValue = base64_decode(substr(LARAVEL_APP_KEY, 7)); $encrypter = new Encrypter($encryptValue, LARAVEL_CIPHER); if (!isset($_COOKIE[SESSION_NAME])) { $sessionId = Str::random(40); $encryptSessionId = $encrypter->encrypt($sessionId); setcookie(SESSION_NAME, $encryptSessionId, SESSION_TIME, SESSION_PATH, SESSION_DOMAIN, SESSION_SECURE, SESSION_HTTP_ONLY); } else { if (is_string($_COOKIE[SESSION_NAME]) && ctype_alnum($_COOKIE[SESSION_NAME]) && strlen($_COOKIE[SESSION_NAME]) === 40) { // regenerate された session_id のときは session_id を暗号化して再格納 $encryptSessionId = $encrypter->encrypt($_COOKIE[SESSION_NAME]); setcookie(SESSION_NAME, $encryptSessionId, SESSION_TIME, SESSION_PATH, SESSION_DOMAIN, SESSION_SECURE, SESSION_HTTP_ONLY); $decryptSessionId = $_COOKIE[SESSION_NAME]; } else { $decryptSessionId = $encrypter->decrypt($_COOKIE[SESSION_NAME]); } $dsn = 'mysql:host=' . DBHOST . ';dbname=' . DBNAME; $pdo = new PDO($dsn, DBUSER, DBPASSWORD); $sessionHandler = new Session\AppSessionHandler($decryptSessionId, $pdo); session_name(SESSION_NAME); session_set_save_handler($sessionHandler, true); }
このあとに session_start() を呼び出せば、Laravel と非 Laravel の双方で読み書きできるセッションが作れると思います