By W. J. 길모머(W. J. Gilmore), 역 한빛 리포터 1기 이상훈
지난 기사에서 세션 추적으로 웹사이트에 완전히 새로운 영역을 추가할 수 있음을 알 수 있었다. 이번 주에는 우리가 배운 것을 토대로 어떻게 사용자 세션 데이터를 저장하는 커스텀 함수를 만드는가를 보여주고자 한다. 이 함수들이 어떻게 만들어지는지 보기 전에 먼저 왜 이러한 작업을 하고자 하는지 자문하는 기회를 가져보자.
왜 PHP가 기본적으로 제공하는 파일 사용 방식 대신에 커스텀 함수를 만들어야 하는 것일까? 이는 세션 데이터를 저장하는 데 데이터베이스를 활용하기 위해서이다. 데이터베이스에 적재된 세션 데이터는 효율적일 뿐만 아니라, 세션 정보를 다른 도메인이나 네트워크를 통해서도 쉽게 검색할 수 있어서 유용하다.
설정
지난 기사 내용을 기억해보면 각 세션 확인(SID) 번호에 따라 각 파일에 기본적으로 세션 정보가 기록된다. 또한 세션 정보는 공유메모리와 커스텀 저장 함수를 생성함으로써 기록될 수도 있다. 이 글에서는 커스텀 저장 함수를 이용한 설정에 대해서 설명할 것이다.
php.ini파일을 열어서 다음 지시자를 찾는 것부터 시작한다.
session.save_handler = files ; handler used to store/retrieve data
|
이 글의 후반부에서 생성할 커스텀 저장함수를 이용하기 위해서는 session.save_handle를 다음과 같이 설정해야 한다.
session.save_handler = user ; handler used to store/retrieve data
|
이는 PHP 엔진에 사용자 고유의 저장 함수를 정의할 것임을 의미한다. 정확히 어떻게 구현될 것인가는 곧 보게 될 것이다.
함수
어떤 저장 매체를 사용하든지 간에, 6가지 함수를 정의해야 한다. 이 함수는 php 엔진에서 세션 관리 기능을 수행하는 데 필요한 작업을 수행한다. 여기에서는 각 함수의 목적과 변수를 정의하도록 하겠다.
session_open($session_save_path, $session_name)
|
session_open() 함수는 세션 관리 과정에서 사용하는 요소를 초기화하는 간단한 함수다. 두 개의 입력 변수 $session_save_path와 $session_name은 php.ini에서 볼 수 있는 설정 지시자를 가리킨다. 뒤에 나올 리스트에서 이 설정 값을 가져오는
get_cfg_var() 함수를 사용할 것이다.
session_close() 함수는 전형적인 관리자 함수와 마찬가지로, session_open()으로 초기화된 사용중인 자원을 닫는다. 보는 바와 같이 이 함수에 대한 입력 변수는 없다. 이 함수는 세션을 없애는 것은 아니라는 점을 기억하자. 세션을 없애는 것은 이 장의 나중에 소개할 session_destory() 함수의 몫이다.
이 함수는 저장 매체에서 세션 데이터를 읽어 온다. 입력 값인 $sessionID는 특정 클라이언트에 대한 저장된 데이터를 구분하는 세션 ID를 가리킨다.
session_write($sessionID, $value)
|
이 함수는 저장 매체에 세션 데이터를 기록한다. 입력 값인 $sessionID은 변수명이고 $value는 세션 데이터를 의미한다.
이 함수는 스크립트에서 가장 나중에 불러 오는 함수로, 세션과 관련된 모든 변수를 없앤다. 입력 값인 $SID는 현재 열려 있는 세션의 세션 ID를 가리킨다.
session_garbage_collect($lifetime)
|
이 함수는 만료된 모든 세션을 효과적으로 삭제한다. 입력 값인 $lifetime은 php.ini에 있는 session.gc_maxlifetime 세션 설정 지시자를 가리킨다.
일단 함수가 정의되면 PHP 세션 관리 로직과 연결한다. 이 작업은 PHP의 이미 정의된 session_set_save_handler() 함수에 이들 이름을 전달함으로써 수행된다. 예를 들어, 커스텀 함수 이름을 위에 나온 것으로 가정하면 다음과 같은 커스텀 관리자를 정의할 수 있다.
session_set_save_handler("session_open", "session_close",
"session_read", "session_write",
"session_destroy", "session_garbage_collect");
|
함수명은 사용자가 마음대로 지정할 수 있다. 여기에서 중요한 것은 다음과 같다.
- 이 함수는 정확한 숫자와 변수의 형식을 입력으로 전달한다.
- session_set_save_handeler() 함수에 함수명이 열기, 닫기, 읽기, 쓰기, 없애기, 그리고 가비지 컬렉션이라는 정확한 순서로 정의되어 있다.
MySQL 세션 저장 기능
지금까지 PHP의 사용자 정의 세션 기능에서 지시한 요구사항을 정의했다. 이 정보는 세션 데이터를 다루고자 하는 매체에 적용될 수 있다. 이 장에서는 각광 받고 있는
MySQL 데이터베이스 서버로 이러한 작업을 수행하는 것을 보여줄 것이다.
함수를 작성하기에 앞서 데이터베이스 테이블을 만들어야 한다. 리스트 1에 필자가 만든 테이블이 있다. 세션 테이블의 활용 정도에 따라 데이터베이스를 좀더 명확하게 만들고 싶을 수도 있겠지만, 자세한 것은 사용자의 몫이다.
리스트1: MySQL 세션 저장 테이블
mysql>CREATE TABLE SessionsTable (
->SID char(32) NOT NULL,
->expiration INT NOT NULL,
->value TEXT NOT NULL,
->PRIMARY KEY(SID) );
|
리스트 2는 MysQL 관리 함수를 보여준다. 앞장에서 소개한 것과 같은 순서로 이들 함수를 정의했다. 함수의 문법과 그에 대한 주석은 여러분 각자가 공부하길 바란다.
리스트 2: MySQL 세션 저장 라이브러리
(<code>mysql_sessions.inc</code>)</p>
<?
// Session Table
$sess_table = "SessionsTable";
// Retrieve the session maximum lifetime (found in php.ini)
$lifetime = get_cfg_var("session.gc_maxlifetime");
//=============
// function: mysql_session_open()
// purpose: 서버와 지속적인 연결을 만들고 데이터베이스를 선택한다.
//=============
mysql_session_open($session_path, $session_name) {
mysql_pconnect("localhost", "myusername", "mysecretpassword")
or die("Can"t connect to MySQL server! ");
mysql_select_db("sessions_database")
or die("Can"t select MySQL sessions database");
} // end mysql_session_open()
//=============
// function: mysql_session_close()
// purpose: 서버 연결이 지속적이기 때문에 실제로 아무 일도 하지 않는다.
// 이 특별한 처리에서는 아무 일도 하지 않지만, 정의하기로 한다.
//=============
mysql_session_close() {
return 1;
} // end mysql_session_close()
//=============
// function: mysql_session_select()
// purpose: 데이터베이스에서 세션 정보를 읽어 온다.
//=============
mysql_session_select($SID) {
GLOBAL $sess_db;
GLOBAL $sess_table;
$query = "SELECT value FROM $sess_table
WHERE SID = "$SID" AND
expiration > ". time();
$result = mysql_query($query);
} // end mysql_session_select()
//=============
// function: mysql_session_write()
// purpose: 이 함수는 세션 데이터를 기록한다. SID가 이미 있으면, 데이터를 갱신한다.
//=============
mysql_session_write($SID, $value) {
GLOBAL $sess_db;
GLOBAL $sess_table;
GLOBAL $lifetime;
$expiration = time() + $lifetime;
$query = "INSERT INTO $sess_table
VALUES("$SID", "$expiration", "$value")";
$result = mysql_query($query, $sess_db);
if (! $result) :
$query = "UPDATE $sess_table SET
expiration = "$expiration",
value = "$value" WHERE
SID = "$SID" AND expiration >". time();
$result = mysql_query($query, $sess_db);
endif;
} // end mysql_session_write()
//=============
// function: mysql_session_destroy()
// purpose: 입력 받은 SID에 대한 한 줄의 세션 정보를 삭제한다.
//=============
mysql_session_destroy($sessionID) {
GLOBAL $sess_table;
$query = "DELETE FROM $sess_table
WHERE SID = "$sessionID"";
$result = mysql_query($query);
} // end mysql_session_destroy()
//=============
// function: mysql_session_garbage_collect()
// purpose: 만료된 모든 세션을 삭제한다.
//=============
mysql_session_garbage_collect($lifetime) {
GLOBAL $sess_table;
$query = "DELETE FROM $sess_table
WHERE sess_expiration < ".time() - $lifetime;
$result = mysql_query($query);
return mysql_affected_rows($result);
} // end mysql_session_garbage_collect()
?>
|
일단 이들 함수를 정의했으면 다른 스크립트의 라이브러리를 포함하고 MySQL 함수와 PHP의 세션 관리 기능을 연결해 주는
session_set_save_handler() 함수를 호출할 수 있다. 리스트 3은 이 함수가 어떻게 MySQL 함수와 결합해서 사용되는가를 보여준다.
리스트 3: session_set_save_handler()로 MySQL 함수 결합
<?
INCLUDE("mysql_sessions.inc");
session_set_save_handler("mysql_session_open", "mysql_session_close",
"mysql_session_select", "mysql_session_write",
"mysql_session_destroy",
"mysql_session_garbage_collect");
session_start();
// 여기부터는 지난 기사와 마찬가지로 세션을 사용할 수 있다.
?>
|
결론
이것으로 이번 주의 기사를 마감하고 세션 추적의 2회에 걸친 연재를 결론지을까 한다. 세션 추적- 1부에서는 사용자를 투명하게 추적하는 것을 가능하게 해줌으로써, 세션이 어떻게 인터넷 응용에 무한한 부가가치를 제공하는가를 보여주었다. 이번 기사에서는 1부에서 습득한 것을 바탕으로 자신만의 세션 인터페이스를 쉽게 제작하고, PHP가 지원하는 모든 매체로 데이터를 관리할 수 있다는 것을 보여 주었다.
W. J. 길모어(W.J. Gilmore)는 1997년부터 PHP 애플리케이션을 개발하고 있으며 가장 있기 있는 웹 개발 사이트에 글을 게재하고 있다. 2001년 1월에 출판된 "A Programmer"s Introduction to PHP 4.0"이라는 책을 저작한 바 있으며, Apress의 웹과 오픈 소스 기술의 부편집장을 맡고 있다.
이상훈님은 한빛 리포터 1기로 활동 중이며, IDE Korea라는 컨설팅 + 개발 업체에서 인터넷 개발 쪽을 맡고 있습니다.