21'C 흐림
서울 강남구
중복로그인 방지 원리
1. $g5['visit_table'] 에 mb_id,mb_name 필드를 추가한다.
(접속시 회원정보 저장함)
2. 관리자모드에 접속자 보기에 아이디.이름을 출력시킨다. (참고용이며 안해도 무방)
3. 접속정보 저장시 mb_id ,mb_name 추가
4. 갱신할때 mb_id ,mb_name update
5. extend 에서 동일한 id 를 파악해서 동일한 다른 ip 의 접속 시간을 비교해서 늦게 접속한경우 경고후 로그아웃 처리한다.
소스
---------------------------------------------
/bbs/visit_insert.inc.php
---------------------------------------------
<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
// 컴퓨터의 아이피와 쿠키에 저장된 아이피가 다르다면 테이블에 반영함
if (get_cookie('ck_visit_ip') != $_SERVER['REMOTE_ADDR'])
{
set_cookie('ck_visit_ip', $_SERVER['REMOTE_ADDR'], 86400); // 하루동안 저장
$tmp_row = sql_fetch(" select max(vi_id) as max_vi_id from {$g5['visit_table']} ");
$vi_id = $tmp_row['max_vi_id'] + 1;
// $_SERVER 배열변수 값의 변조를 이용한 SQL Injection 공격을 막는 코드입니다. 110810
$remote_addr = escape_trim($_SERVER['REMOTE_ADDR']);
$referer = "";
if (isset($_SERVER['HTTP_REFERER']))
$referer = escape_trim(clean_xss_tags($_SERVER['HTTP_REFERER']));
$user_agent = escape_trim(clean_xss_tags($_SERVER['HTTP_USER_AGENT']));
$vi_browser = '';
$vi_os = '';
$vi_device = '';
if(version_compare(phpversion(), '5.3.0', '>=') && defined('G5_BROWSCAP_USE') && G5_BROWSCAP_USE) {
include_once(G5_BBS_PATH.'/visit_browscap.inc.php');
}
$sql = " insert {$g5['visit_table']} (mb_id,mb_name, vi_id, vi_ip, vi_date, vi_time, vi_referer, vi_agent, vi_browser, vi_os, vi_device ) values (
'{$member['mb_id']}',
'{$member['mb_name']}',
'{$vi_id}', '{$remote_addr}', '".G5_TIME_YMD."', '".G5_TIME_HIS."', '{$referer}', '{$user_agent}', '{$vi_browser}', '{$vi_os}', '{$vi_device}' ) ";
$result = sql_query($sql, FALSE);
// 정상으로 INSERT 되었다면 방문자 합계에 반영
if ($result) {
$sql = " insert {$g5['visit_sum_table']} ( vs_count, vs_date) values ( 1, '".G5_TIME_YMD."' ) ";
$result = sql_query($sql, FALSE);
// DUPLICATE 오류가 발생한다면 이미 날짜별 행이 생성되었으므로 UPDATE 실행
if (!$result) {
$sql = " update {$g5['visit_sum_table']} set vs_count = vs_count + 1 where vs_date = '".G5_TIME_YMD."' ";
$result = sql_query($sql);
}
// INSERT, UPDATE 된건이 있다면 기본환경설정 테이블에 저장
// 방문객 접속시마다 따로 쿼리를 하지 않기 위함 (엄청난 쿼리를 줄임 ^^)
// 오늘
$sql = " select vs_count as cnt from {$g5['visit_sum_table']} where vs_date = '".G5_TIME_YMD."' ";
$row = sql_fetch($sql);
$vi_today = $row['cnt'];
// 어제
$sql = " select vs_count as cnt from {$g5['visit_sum_table']} where vs_date = DATE_SUB('".G5_TIME_YMD."', INTERVAL 1 DAY) ";
$row = sql_fetch($sql);
$vi_yesterday = $row['cnt'];
// 최대
$sql = " select max(vs_count) as cnt from {$g5['visit_sum_table']} ";
$row = sql_fetch($sql);
$vi_max = $row['cnt'];
// 전체
$sql = " select sum(vs_count) as total from {$g5['visit_sum_table']} ";
$row = sql_fetch($sql);
$vi_sum = $row['total'];
$visit = '오늘:'.$vi_today.',어제:'.$vi_yesterday.',최대:'.$vi_max.',전체:'.$vi_sum;
// 기본설정 테이블에 방문자수를 기록한 후
// 방문자수 테이블을 읽지 않고 출력한다.
// 쿼리의 수를 상당부분 줄임
sql_query(" update {$g5['config_table']} set cf_visit = '{$visit}' ");
}
}
$remote_addr = escape_trim($_SERVER['REMOTE_ADDR']);
$sql = " update {$g5['visit_table']} set
mb_id='{$member['mb_id']}'
,mb_name='{$member['mb_name']}'
where vi_ip='{$remote_addr}'";
sql_query($sql);
//echo $sql;exit;
?>
---------------------------------------------
/extend/ar_limit.php
---------------------------------------------
<?php
//중복 로그인 방지
if ($member['mb_id'] && $member['mb_level']<8) {
$remote_addr = escape_trim($_SERVER['REMOTE_ADDR']);
//내 IP
$sql="select * from {$g5['visit_table']} where mb_id='{$member['mb_id']}' and vi_ip='{$remote_addr}'";
$tmp=sql_fetch($sql);
//다른사람 IP
$sql2="select * from {$g5['visit_table']} where mb_id='{$member['mb_id']}' and vi_ip!='{$remote_addr}'";
$tmp2=sql_fetch($sql2);
if ($tmp2 && $tmp && $tmp['vi_time']>=$tmp2['vi_time'] ) {
session_unset(); // 모든 세션변수를 언레지스터 시켜줌
session_destroy(); // 세션해제함
alert('이미 로그인되어 있는 아이디 입니다.');
if ($member['mb_id']) {
alert($member['mb_id'].' 님은 승인 대기 중입니다.',"/bbs/login.php");
}
goto_url("/bbs/login.php");
}
}
?>
---------------------------------------------
/adm/visit_search.php
---------------------------------------------
<?php
$sub_menu = '200810';
include_once('./_common.php');
include_once(G5_PATH.'/lib/visit.lib.php');
auth_check($auth[$sub_menu], 'r');
$g5['title'] = '접속자검색';
include_once('./admin.head.php');
include_once(G5_PLUGIN_PATH.'/jquery-ui/datepicker.php');
$colspan = 6;
$listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'">처음</a>'; //페이지 처음으로 (초기화용도)
?>
<div class="local_sch local_sch01">
<form name="fvisit" method="get" onsubmit="return fvisit_submit(this);">
<?php echo $listall?>
<label for="sch_sort" class="sound_only">검색분류</label>
<select name="sfl" id="sch_sort" class="search_sort">
<option value="vi_ip"<?php echo get_selected($sfl, 'vi_ip'); ?>>IP</option>
<option value="vi_referer"<?php echo get_selected($sfl, 'vi_referer'); ?>>접속경로</option>
<option value="vi_date"<?php echo get_selected($sfl, 'vi_date'); ?>>날짜</option>
</select>
<label for="sch_word" class="sound_only">검색어</label>
<input type="text" name="stx" size="20" value="<?php echo stripslashes($stx); ?>" id="sch_word" class="frm_input">
<input type="submit" value="검색" class="btn_submit">
</form>
</div>
<div class="tbl_wrap tbl_head01">
<table>
<thead>
<tr>
<th scope="col">IP</th>
<th scope="col">mb_id</th>
<th scope="col">mb_name</th>
<th scope="col">접속 경로</th>
<th scope="col">브라우저</th>
<th scope="col">OS</th>
<th scope="col">접속기기</th>
<th scope="col">일시</th>
</tr>
</thead>
<tbody>
<?php
$sql_common = " from {$g5['visit_table']} ";
if ($sfl) {
if($sfl=='vi_ip' || $sfl=='vi_date'){
$sql_search = " where $sfl like '$stx%' ";
}else{
$sql_search = " where $sfl like '%$stx%' ";
}
}
$sql = " select count(*) as cnt
{$sql_common}
{$sql_search} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
$rows = $config['cf_page_rows'];
$total_page = ceil($total_count / $rows); // 전체 페이지 계산
if ($page < 1) $page = 1; // 페이지가 없으면 첫 페이지 (1 페이지)
$from_record = ($page - 1) * $rows; // 시작 열을 구함
$sql = " select *
{$sql_common}
{$sql_search}
order by vi_id desc
limit {$from_record}, {$rows} ";
$result = sql_query($sql);
for ($i=0; $row=sql_fetch_array($result); $i++) {
var_dump($row);
$brow = $row['vi_browser'];
if(!$brow)
$brow = get_brow($row['vi_agent']);
$os = $row['vi_os'];
if(!$os)
$os = get_os($row['vi_agent']);
$device = $row['vi_device'];
$link = "";
$referer = "";
$title = "";
if ($row['vi_referer']) {
$referer = get_text(cut_str($row['vi_referer'], 255, ""));
$referer = urldecode($referer);
if (!is_utf8($referer)) {
$referer = iconv('euc-kr', 'utf-8', $referer);
}
$title = str_replace(array("<", ">"), array("<", ">"), $referer);
$link = '<a href="'.$row['vi_referer'].'" target="_blank" title="'.$title.'">';
}
if ($is_admin == 'super')
$ip = $row['vi_ip'];
else
$ip = preg_replace("/([0-9]+).([0-9]+).([0-9]+).([0-9]+)/", G5_IP_DISPLAY, $row['vi_ip']);
$bg = 'bg'.($i%2);
?>
<tr class="<?php echo $bg; ?>">
<td class="td_id"><a href="<?php echo $_SERVER['SCRIPT_NAME']; ?>?sfl=vi_ip&stx=<?php echo $ip; ?>"><?php echo $ip; ?></a></td>
<td class="td_id"><a href="<?php echo $_SERVER['SCRIPT_NAME']; ?>?sfl=vi_ip&stx=<?php echo $ip; ?>"><?php echo $row['mb_id']; ?></a></td>
<td class="td_id"><a href="<?php echo $_SERVER['SCRIPT_NAME']; ?>?sfl=vi_ip&stx=<?php echo $ip; ?>"><?php echo $row['mb_name']; ?></a></td>
<td class="td_left"><?php echo $link.$title; ?><?php echo $link ? '</a>' : ''; ?></td>
<td class="td_idsmall td_category1"><?php echo $brow; ?></td>
<td class="td_idsmall td_category3"><?php echo $os; ?></td>
<td class="td_idsmall td_category2"><?php echo $device; ?></td>
<td class="td_datetime"><a href="<?php echo $_SERVER['SCRIPT_NAME']; ?>?sfl=vi_date&stx=<?php echo $row['vi_date']; ?>"><?php echo $row['vi_date']; ?></a> <?php echo $row['vi_time']; ?></td>
</tr>
<?php } ?>
<?php if ($i == 0) echo '<tr><td colspan="'.$colspan.'" class="empty_table">자료가 없습니다.</td></tr>'; ?>
</tbody>
</table>
</div>
<?php
$pagelist = get_paging($config['cf_write_pages'], $page, $total_page, $_SERVER['SCRIPT_NAME'].'?'.$qstr.'&domain='.$domain.'&page=');
if ($pagelist) {
echo $pagelist;
}
?>
<script>
$(function(){
$("#sch_sort").change(function(){ // select #sch_sort의 옵션이 바뀔때
if($(this).val()=="vi_date"){ // 해당 value 값이 vi_date이면
$("#sch_word").datepicker({ changeMonth: true, changeYear: true, dateFormat: "yy-mm-dd", showButtonPanel: true, yearRange: "c-99:c+99", maxDate: "+0d" }); // datepicker 실행
}else{ // 아니라면
$("#sch_word").datepicker("destroy"); // datepicker 미실행
}
});
if($("#sch_sort option:selected").val()=="vi_date"){ // select #sch_sort 의 옵션중 selected 된것의 값이 vi_date라면
$("#sch_word").datepicker({ changeMonth: true, changeYear: true, dateFormat: "yy-mm-dd", showButtonPanel: true, yearRange: "c-99:c+99", maxDate: "+0d" }); // datepicker 실행
}
});
function fvisit_submit(f)
{
return true;
}
</script>
<?php
include_once('./admin.tail.php');
?>