세션은 일반적으로 서버에 파일로 관리됨
하지만 도메인 간 세션을 공유해야 할 때 세션을 데이터베이스로 관리하는 방식을 많이 씀
// 원래 코드
<?php
// 세션 활성화
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// 세션 값 지정
$_SESSION['key'] = value;
...
// 세션 파괴
$_SESSION = [];
session_destroy();
?>
세션 활성화 후 $_SESSION 글로벌 변수를 사용하면 서버쪽에 세션 값 갖고있는 세션 파일이 생성됨.
*
*
세션을 데이터베이스에 저장하기 위해서는 세션 핸들러 코드를 작성해야함.
open, close, read, write, destroy, gc 함수는 꼭 작성, 나머지 함수는 필요하면 작성
작성 후 session_set_save_handler로 각 함수를 등록시켜야함.
session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid [, callable $validate_sid [, callable $update_timestamp ]]] ) : bool
<?php
class FileSessionHandler
{
private $savePath;
function open($savePath, $sessionName)
{
$this->savePath = $savePath;
if (!is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}
return true;
}
function close()
{
return true;
}
// 세션 값 있는지 확인
// 값 있으면 세션 값 반환, destroy 호출
// 없으면 빈 문자열 반환, write 호출
function read($id)
{
return (string)@file_get_contents("$this->savePath/sess_$id");
}
// 세션을 새로 작성 또는 업데이트
function write($id, $data)
{
return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}
function destroy($id)
{
$file = "$this->savePath/sess_$id";
if (file_exists($file)) {
unlink($file);
}
return true;
}
// 안쓰는 세션, 만료된 세션 등을 삭제
// 세션 활성화 될 때 마다 설정해놓은 확률로 작동한다고 함;;
function gc($maxlifetime)
{
foreach (glob("$this->savePath/sess_*") as $file) {
if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}
return true;
}
}
$handler = new FileSessionHandler();
session_set_save_handler(
array($handler, 'open'),
array($handler, 'close'),
array($handler, 'read'),
array($handler, 'write'),
array($handler, 'destroy'),
array($handler, 'gc')
);
// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');
session_start();
// proceed to set and retrieve values by key from $_SESSION
(php공식사이트 Documentation에서 가져옴)
<?php
require_once('db.class.php');
require_once('errors.php');
$save_path = session_save_path();
// 세션지속시간(세션이 살아있는 시간, 여기선 php.ini 설정값으로 함.
//$SESS_LIFE = get_cfg_var("session.gc_maxlifetime");
$SESS_LIFE = 60 * 60 * 24;
// open()함수 : 디비에 연결작업
function sess_open($savePath, $session_name)
{
try {
DB::connectSession();
} catch (PDOException $e) {
// DB 연결 실패
return false;
}
return true;
}
// close()함수 : 암것도 안한다~ 혹시나 디비를 닫아주고싶으면 여기서 한다.
function sess_close()
{
return true;
}
// read()함수 : $key에 해당되는, 저장된 세션값을 DB에서 가져오기
// 값 있으면 sess_destroy
// 없으면 sess_write
function sess_read($key)
{
global $save_path;
// 현재시간보다 세션지속시간이 크다면( 즉 세션이 살아있다면..) 불러온다
$sess_result = DB::s_query2("SELECT session_value, user_ip, user_id FROM sessions WHERE session_key = :sesskey AND session_expiry > :expiry", array(":sesskey" => $key, ":expiry" => time()));
// 읽을 데이터 없을 때
$sess_value = $sess_result[0]['session_value'];
$user_ip = $sess_result[0]['user_ip'];
if ($sess_value == '') {
if($user_ip == '-1'){
ErrorManager::alert('중복 로그인 방지');
}
return ''; // 세션 새로 생성
} else {
return stripslashes($sess_value);
}
}
// write()함수 : $key세션에 $val값을 저장합니다. 즉 session_register()를 처리해준다
function sess_write($key, $val)
{
global $save_path, $SESS_LIFE;
// 현재시간에 세션지속시간을 더해준다
$expiry = time() + $SESS_LIFE;
$value = addslashes($val);
$user_id = '';
if(strlen($val) > 0){
$val_split = explode(';', $val);
$id_split = explode(':', $val_split[0]);
$user_id = trim($id_split[2], '"');
}
try{
DB::s_query2("UPDATE sessions SET session_value = :sessvalue, user_ip = :overlap_code WHERE session_key <> :sesskey AND user_id = :user_id", array(':sessvalue' => '', ':overlap_code' => '-1', ':sesskey' => $key, ':user_id' => $user_id));
DB::s_query2(
"REPLACE INTO sessions SET session_key = :sesskey, session_value = :sessvalue, session_expiry = :expiry, user_id = :user_id, user_ip = :user_ip",
array(
':sesskey' => $key,
':sessvalue' => $value,
':expiry' => $expiry,
':user_id' => $user_id,
':user_ip' => (strlen($value) == 0) ? '' : $_SERVER['REMOTE_ADDR']
)
);
}catch(PDOException $e){
return false;
}
return true;
}
// destroy()함수 : $key에 해당하는 값을 지워주자. session_unregister()를 처리해준다.
function sess_destroy($key)
{
global $save_path;
try {
DB::s_query2("DELETE FROM sessions WHERE session_key = :sesskey", array(':sesskey' => $key));
} catch (PDOException $e) {
return false;
}
return true;
}
// gc()함수 : 세션지속시간이 현재시간보다 작은 쓰레기 세션들을 지워주자~
function sess_gc($maxlifetime)
{
global $SESS_LIFE, $save_path;
foreach (glob("$save_path/sess_*") as $file) {
$key = explode('_', $file)[1];
if (filemtime($file) + $SESS_LIFE < time()) {
DB::s_query2("DELETE FROM sessions WHERE session_key = :sesskey", array(':sesskey' => $key));
if(file_exists($file)){
unlink($file);
}
}
}
return true;
}
if ( !isset($_SESSION) ){
session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
}
register_shutdown_function('session_write_close');
@session_start();