mysql_fetch_object 객체 활용하기

글쓴이:우수한

mysql_fetch_object로 쿼리를 던지면, 그 결과 오브젝트(객체)를 받아오게 됩니다.
이것이 어떻게 프로그래밍을 간편하게 만들어주는지 살펴보도록 하겠습니다.

—– [1단계: 기초] —–

자, 다음과 같은 테이블이 있다고 합시다.
CREATE TABLE users (
id varchar(10) not null,
name varchar(10) not null,
addr varchar(30) not null,
phone varchar(14) not null,
PRIMARY KEY (id)
);
INSERT INTO users VALUES (“test”, “아무개”, “서울”, “02-123-4567”);

여기서는 편의상 DB 클래스를 사용하겠습니다. (하지만 DB클래스가 중요한 것은 아닙니다.)
DB->fetch()라는 함수는 mysql_fetch_object()를 뜻한다는 것만 아시면 됩니다.

$DB->query(“SELECT id, name, addr, phone FROM users WHERE id=’test’ “);
$user = $DB->fetch();
위와 같은 코드를 실행하면, 그 결과 $user->id 에는 “test”, $user->name 에는 “아무개” 등의 값이 들어있는 것을 확인하실 수 있습니다.

자, 그럼 위의 기능을 함수로 만들어보겠습니다.
function load_user($id) {
$SQL = ” SELECT * FROM users WHERE id=’$id’ “;
$DB =& DB::getInstance();
$DB->query($SQL);
return $DB->fetch();
}
이제 회원정보를 읽어올때 $user = load_user(“test”); 라고 하면 끝입니다.
회원정보를 변경할 수 있는 폼을 출력할때

디비로 세션관리 및 중복로그인 방지

sugar01
http://prospect.new21.net

회원테이블에 테스트용으로 아이디 ‘test’ 비밀번호 ‘test’ 인 데이터를 하나 넣었습니다.
###########회원 테이블###########
CREATE TABLE sugar_member (
num int(4) unsigned NOT NULL auto_increment,
id char(20) NOT NULL default ”,
passwd char(20) NOT NULL default ”,
PRIMARY KEY (num)
) TYPE=MyISAM;

INSERT INTO sugar_member VALUES(”,’test’,password(‘test’));

##########세션 관리 테이블###################
CREATE TABLE sugar_session4 (
uid varchar(32) NOT NULL default ‘0’,
sess_key varchar(32) NOT NULL default ”, //세션키
last_log int(11) unsigned NOT NULL default ‘0’,
last_ip varchar(15) NOT NULL default ”,
sess_value text NOT NULL, //세션값, 로그인 하게되면 저장되는 정보
attack int(2) NOT NULL default ‘0’, //로그인후 다른 아이피에서 로그인 하려 하면 증가
KEY sess_key (sess_key)
) TYPE=MyISAM;

#######config.php#########
$localhost=localhost;
$user_name=””; //디비 사용이름
$db_passwd=””; //디비 패스워드
$db_name=””; //디비 이름

$connect=mysql_connect(“$localhost”,”$user_name”,”$db_passwd”) or die(“SQL server에 연결할수 없습니다.”);
mysql_select_db(“$db_name”,$connect);
?>
#########sess_test.php#################

include “config.php”;

session_cache_limiter(”);
session_set_save_handler(“sess_open”, “sess_close”, “sess_read”, “sess_write”, “sess_destroy”, “sess_gc”);
session_start();
//echo”_SESSION[sess_id] = $_SESSION[sess_id]
“;
$time=time();
//echo”time= $time
“;

function sess_open($save_path, $session_name) {
//echo”sess_open save_path = $save_path session_name= $session_name

“;
return 1;
}

function sess_read($key) {
//echo”sess_read key = $key

“;
$query=mysql_query(“SELECT sess_value FROM sugar_session4 WHERE sess_key = ‘$key’ AND last_log > ‘”.(time()-get_cfg_var(“session.gc_maxlifetime”)).”‘ “) or die(mysql_error());
$row=mysql_fetch_array($query);
return $row[0];
}

function sess_write($key, $value) {
//echo”sess_write key = $key value=$value

“;
$query=mysql_query(“SELECT * FROM sugar_session4 WHERE sess_key=’$key’AND sess_value IS NOT NULL”) or die(mysql_error());
$time=time();
$check=mysql_num_rows($query);
//echo”check = $check
“;
if(mysql_num_rows($query)==0) //새로 로그인 하려는 경우
{
if($value!=””)
{
$uid=$GLOBALS[‘sess_id’];
//로그아웃 하지 않고 창을 닫아서 사이트를 나가고 다시 로그인 하려는 경우
$query=mysql_query(“SELECT sess_value from sugar_session4 WHERE uid=’$uid’ AND last_ip='”.$_SERVER[“REMOTE_ADDR”].”‘”) or die(mysql_error());

if(mysql_num_rows($query))
{
mysql_query(“UPDATE sugar_session4 SET sess_key=’$key’,last_log='”.time().”‘, last_ip='”.$_SERVER[“REMOTE_ADDR”].”‘, sess_value=’$value’ WHERE uid=’$uid'”) or die(mysql_error());
echo”“;
}

else //로그아웃 하고 나가서 다시 로그인 하려는 경우
{
//다른 아이피로 접근 하려는 경우
$query=mysql_query(“SELECT sess_value FROM sugar_session4 WHERE uid=’$uid’ AND last_ip!='”.$_SERVER[“REMOTE_ADDR”].”‘”) or die (mysql_error());
if(mysql_num_rows($query))
{
$query=mysql_query(“UPDATE sugar_session4 SET attack=attack+1 WHERE uid=’$uid’ AND last_ip!='”.$_SERVER[“REMOTE_ADDR”].”‘”) or die (mysql_error());

echo(“
“);

}
else //순수히 새로 로그인 하려는 경우
{
$query=”INSERT INTO sugar_session4 VALUES(‘$uid’,’$key’,’$time’,'”.$_SERVER[“REMOTE_ADDR”].”‘,’$value’,”)”;

mysql_query($query) or die(mysql_error());
echo”“;
}
}
}

}

else// 계속 로그인 해져있는상태
{
$query=mysql_query(“SELECT attack FROM sugar_session4 WHERE sess_key=’$key'”);
$row=mysql_fetch_array($query);
if($row[attack]!=0) echo” $row[attack] 번 다른곳에서 접속 시도가 있었습니다
“;
mysql_query(“UPDATE sugar_session4 SET last_log='”.time().”‘, last_ip='”.$_SERVER[“REMOTE_ADDR”].”‘, sess_value=’$value’ WHERE sess_key=’$key’ “) or die(mysql_error());

}

return true;
}

function sess_close() {
return 1;
}

function sess_destroy($key) {
//echo”sess_destroy key=$key

“;
$query=mysql_query(“DELETE FROM sugar_session4 WHERE sess_key=’$key'”) or die(mysql_error());
}

function sess_gc($lifetime) {
//echo”sess_gc lifetim=$lifetime
“;
mysql_query(“DELETE FROM sugar_session4 WHERE last_log<".time()) or die(mysql_error());
return true;
}

?>

###################login.php###############
include”sess_test.php”;
echo(“



“);

if($_SESSION[sess_id]!=””)
{
echo(“

$_SESSION[sess_id] 님 로그인
로그아웃

“);
}
else
{
echo(“


Id 

Password 

“);
}//else end

if($mode==ok)
{

$sql=mysql_query(“select password(‘$passwd’)”);
$conv_passwd=mysql_result($sql,0,0);

$sql=mysql_query(“select * from sugar_member where id=’$id’&&passwd=’$conv_passwd'”) or die(mysql_error());
$e_check=mysql_num_rows($sql);
$row=mysql_fetch_array($sql);
if($e_check==”)
{
echo(“



“);
}
else
{
$sess_id=”$row[id]”;
session_register(sess_id);
//echo”로그인 에서 의 HTTP_SESSION_VARS[sess_id] = $HTTP_SESSION_VARS[sess_id]
“;
}

}
########logout.php#########
include”sess_test.php”;
session_destroy();

echo”“;
?>

세션을 DB로 관리하기 + 쪽지 확인하기

[1] 대개의 경우, 회원 로그인에 세션을 사용합니다. 즉 회원으로 로그인하지 않으면 세션을 사용할 일이 없는 경우가 많습니다. 따라서 여기서는 회원 전용 세션만 관리하도록 하겠습니다.

[2] 세션 테이블을 만들어서, 여기에 매번 insert, delete를 하는 것은 비록 테이블 크기가 작다고 하더라도 제법 부하를 줍니다. 따라서 여기서는 delete를 쓰지 않고 update만 사용하도록 하겠습니다. 회원이 몇만명이라고 할지라도 이게 더 나은 것 같더군요.

세션 테이블을 다음과 같이 만듭니다. 회원목록 테이블과 똑같은 rows를 갖게 되겠죠.
CREATE TABLE `user_sessions` (
`uid` int(10) unsigned NOT NULL default ‘0’, /* 회원ID */
`sess_key` varchar(32) NOT NULL default ”, /* 세션키 */
`last_log` int(11) unsigned NOT NULL default ‘0’, /* 세션을 기록하는 시간 */
`last_ip` varchar(15) NOT NULL default ”, /* 꼭 필요하지는 않지만, 추후 필요성을 느끼게 될 것임 😉 */
`sess_value` text NOT NULL, /* 세션값 */
PRIMARY KEY (`uid`),
KEY `sess_key` (`sess_key`)
) TYPE=MyISAM;

세션을 처리하는 스크립트는 다음과 같습니다.
(편의상 DB 클래스를 사용했습니다만, 뭐하는건지는 다 아시겠죠? –;;)

session_set_save_handler(“sess_open”, “sess_close”, “sess_read”, “sess_write”, “sess_destroy”, “sess_gc”);
session_start();

function sess_open($save_path, $session_name) {
return 1;
}

function sess_read($key) {
$DB =& DB::getInstance();
$DB->query(“SELECT sess_value FROM user_sessions WHERE sess_key = ‘$key’ AND last_log > ‘”.(time()-get_cfg_var(“session.gc_maxlifetime”)).”‘ “);
$row=$DB->get();
return $row[0];
}

function sess_write($key, $value) {
$DB =& DB::getInstance();
$DB->query(“UPDATE user_sessions SET last_log='”.time().”‘, last_ip='”.$_SERVER[“REMOTE_ADDR”].”‘, sess_value=’$value’ WHERE sess_key=’$key’ “);
return ”;
}

function sess_close() {
return 1;
}

function sess_destroy($key) {
$DB =& DB::getInstance();
$DB->query(“UPDATE user_sessions SET sess_key=”, last_log='”.time().”‘, last_ip='”.$_SERVER[“REMOTE_ADDR”].”‘ WHERE sess_key=’$key’ “);
}

function sess_gc($lifetime) {
return 1;
}

[3] 회원 로그인하는 부분에서 sess_key 값을 할당합니다. 그 다음부터 그 회원은 세션 테이블에서 데이타를 읽고 쓸 수 있습니다.
비회원인 경우는 session_start()를 하더라도 세션키값만 주어질 뿐, 여러가지 $_SESSION값을 사용할 수 없습니다. (물론 쿠키값을 이용해 비회원의 경우는 아예 session_start()를 실행하지 않는 방법도 있죠. ^^;;)

[4] 이렇게 함으로써 굳이 가비지 콜렉션(update 혹은 delete)을 하지 않아도 됩니다. 또 회원의 마지막 접속시간이 최신으로 유지됩니다.

[5] 회원의 중복 로그인이 방지됩니다. 다만, 같은 위치에서 다른 세션을 다시 시작하는 경우인지, 이미 로그인된 상태인지 등의 예외적 상황을 처리하기 위해 로그인을 처리하는 부분을 보강해야겠죠. 😉

——————————
자, 이쯤에서 한가지 욕심을 내어볼까요? 이른바, 쪽지 기능을 추가해보겠습니다. (실시간 쪽지 기능 아닙니다. –;;)
제로보드인가? 쪽지를 받으면 “딩동, 새로운 메시지가 도착했습니다” 하는 소리가 나쟎아요.
받은 쪽지 테이블을 따로 만들면, 매번 해당 테이블을 읽어야 하지 않습니까. 뭐 굳이 2번 작업을 하냐, 세션을 시작하면서 자동적으로 그 데이타를 읽어오자 하는거지요.

`user_sessions` 테이블에 chk_msg 라는 필드를 하나 추가합니다.
ALTER TABLE `user_sessions` ADD `chk_msg` TINYINT(2) UNSIGNED NOT NULL AFTER `last_ip` ;
다른 회원이 쪽지를 보낼때, chk_msg 값을 하나씩 증가시키고, 쪽지를 확인하면 chk_msg 값을 0로 update하려는 것입니다.

sess_read 함수를 변형시켜서, chk_msg 필드값을 읽어오도록 합니다.
function sess_read($key) {
$DB =& DB::getInstance();
$DB->query(“SELECT uid, chk_msg, sess_value FROM user_sessions WHERE sess_key = ‘$key’ AND last_log > ‘”.(time()-get_cfg_var(“session.gc_maxlifetime”)).”‘ “);
$row=$DB->get();
$GLOBALS[“USER”][“id”]=$row[0];
$GLOBALS[“USER”][“chk_msg”]=$row[1];
return $row[2];
}

여기서는 $USER라는 변수에 회원ID, 받은쪽지 갯수를 저장하도록 했습니다. 즉 회원ID를 알기 위해 $_SESSION[“id”]를 쓰지 않고 $USER[“id”]를 쓸 수 있다는 거지요. 받은 쪽지 갯수는 $USER[“chk_msg”]에 들어가니까 매번 이 값을 검사해서 “딩동~ 메시지가 도착했습니다” 라고 알려주면 됩니다.

“뭐야, 난데없이 $USER 라는 글로벌 오브젝트라니…. 난 이런거 싫어” 하시는 분.
여기서 $USER와 같은 변수를 할당하지 않고, $_SESSION을 사용해도 됩니다. $USER[“chk_msg”]=”1″ 대신에 $_SESSION[“chk_msg”] = “1” 이라고 써도 된다는 겁니다. 세션함수 안에서 $_SESSION을 사용한다니, 황당한 트릭이죠? 번거롭게 세션값($row[2])을 직접 파싱할 필요가 없습니다.
다만, 이것은 맨처음 1번만 적용됩니다. 다음번에 $_SESSION[“chk_msg”] = “2” 라고 하더라도, 이미 세션 데이타 안에 “chk_msg”값이 1로 들어있기 때문에, 결과는 “1”로 나옵니다. 따라서 $_SESSON[“chk_msg”] 값을 확인해서 “딩동~” 하는 메시지를 보여주거나 말거나 한 후에, 매번 unset($_SESSION[“chk_msg”])를 해줘야하겠죠?

——————————

재미있으셨나요?
“한번 더 생각하고 DB를 만들자”는 취지에서 한번 써봤고, 나름대로 효율적이라고 생각하는데… 장담은 못하겠네요. 오류나 정정사항은 리플 부탁드립니다.

한솔교육 판촉장비 지원시스템

한솔교육의 교사를 대상으로 하는 판촉장비 지원시스템 홈페이지.
외부에 직접 노출되지 않고 한솔교육의 교사용웹에 로그인하여 이동할 수 있다.
특이사항은 배송장 부분. 일별 또는 지정일별로 각 지점주소를 기준으로 같은 지점소속
직원이 주문한 상품을 동일한 박스에 담을 수 있도록 배송장 출력됨.
배송장 부분때문에 카트부분부터 DB까지 모두 수정.
일괄주문 페이지 : 각 조직의 총무가 각 교사의 신청을 대행하도록 일괄주문 페이지 제작.

요즘 수박의 머릿속엔…

각종 태그와 php문법어들이 난무하고 있다.
아이고 머리야….
언제쯤 프로그램 실무에서 손을 떼게될까?
수정하는거야 그리 큰 에너지가 안드는데 새로 작성하는 것은
무지 많은 에너지를 소비… 이젠 머리도 잘 안돌아가고… 흑흑
로직이 생각이 잘 안나… 어떡하지..
머리야~~