답변 4개 / 댓글 3개
그누보드5에서 기본 제공되는 현재 접속자(Connect) 기능은 웹사이트에 접근하는 모든 IP와 브라우저(User-Agent) 정보를 기록하기 때문에, 구글·네이버·다음 등 검색엔진의 크롤링 봇(Robot)까지 모두 접속자로 집계되어 숫자가 부풀려지곤 합니다.
실제 방문객과 유사하게 로봇을 제외한 사람만 접속자 수로 표현하고 싶다면, 접속 기록을 남기는 소스 코드에서 검색엔진 봇들의 User-Agent를 판별하여 제외하도록 수정해야 합니다.
그누보드5 순정 기준으로 아래와 같이 소스를 수정하시면 됩니다.
🛠 소스 수정 방법
그누보드 핵심 파일 중 접속자를 기록하는 visit_insert.inc.php 파일을 수정해야 합니다.
-
수정할 파일 경로:
/bbs/visit_insert.inc.php
1. 기존 코드 찾기
파일 내에서 대략 20~30라인쯤에 위치한 아래 코드를 찾습니다.
PHP
// s9y, 가자아이-로그인 등에서 다음 코드를 사용하지 않음
$vi_agent = _baddslashes($_SERVER['HTTP_USER_AGENT']);
2. 코드를 아래와 같이 변경하기
기존 코드 아래에 로봇(Bot/Crawler) 키워드를 체크하여 접속 기록을 건너뛰는 코드를 추가합니다.
PHP
$vi_agent = _baddslashes($_SERVER['HTTP_USER_AGENT']);
// --- 로봇 제외 코드 추가 시작 ---
$is_robot = false;
$robots = array(
'bot', 'crawl', 'spider', 'slurp', 'yahoo', 'naver', 'daum',
'yandex', 'bing', 'facebook', 'twitter', 'bytespider', 'gpt'
);
foreach($robots as $robot) {
if(stripos($vi_agent, $robot) !== false) {
$is_robot = true;
break;
}
}
// 로봇인 경우 현재 접속자(login) 및 방문자 기록을 하지 않고 파일 실행을 종료합니다.
if($is_robot) {
return;
}
// --- 로봇 제외 코드 추가 끝 ---
💡 참고 및 주의사항
-
동시접속자 수 반영 시간: 위 코드를 적용하더라도 기존에 이미 잡혀있던 로봇 접속 데이터가 그누보드 설정상 '현재 접속자 유지시간(기본 10~15분)' 동안은 남아있을 수 있습니다. 적용 후 약 10~15분이 지나면 점차 숫자가 줄어들어 실제 사람에 가까운 데이터만 남게 됩니다.
-
방문자 분석 영향: 이 방법은
g5_visit테이블과g5_login테이블 모두에 로봇 기록이 쌓이지 않도록 차단합니다. 따라서 관리자 페이지의 '방문자 분석' 메뉴에서도 로봇 데이터가 제외되어 깔끔한 통계를 보실 수 있습니다. -
업데이트 시 주의: 추후 그누보드 버전을 패치(업데이트)할 때
bbs/visit_insert.inc.php파일이 덮어써 지면 이 코드가 사라질 수 있으므로 백업해두시거나 기억해 두시는 것이 좋습니다.
라고 GEMINI 가 답변해 주네요,
<?php
/**
* bot_guard.php — 봇 차단 + 요청 제한(Rate Limit) 통합
*
* 사용법: common.php에서 cloudflare.check.php 다음에 include
* include_once(G5_PATH.'/cloudflare.check.php'); // ① IP 보정 먼저
* include_once(G5_PATH.'/bot_guard.php'); // ② 그 다음 차단
*
* 처리 순서: 화이트리스트 통과 → 빈UA/봇 차단 → Rate Limit
*/
// ─────────────────────────────────────────────
// 설정
// ─────────────────────────────────────────────
$GUARD = [
// 차단할 봇 (preg 패턴 일부로 사용, | 로 구분)
'bad_bots' => 'AhrefsBot|SemrushBot|MJ12bot|DotBot|BLEXBot|PetalBot|'
. 'Bytespider|GPTBot|CCBot|ClaudeBot|DataForSeoBot|'
. 'serpstatbot|ZoominfoBot|MegaIndex|SeznamBot|'
. 'Amazonbot|ImagesiftBot|Barkrowler',
// 빈 User-Agent 차단 여부
'block_empty_ua' => true,
// Rate Limit (window초 동안 limit회 초과 시 429)
'rate_limit' => 120,
'rate_window' => 60,
// Rate Limit / 차단 예외 IP (관리자·내부망 등)
'allow_ips' => [
// '123.45.67.89',
],
// Rate Limit 저장 디렉토리 (빈 값이면 sys_get_temp_dir)
'store_dir' => '',
];
// ─────────────────────────────────────────────
// 본체
// ─────────────────────────────────────────────
(function (array $cfg) {
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; // CF 핸들러가 보정한 실제 IP
// 1) IP 화이트리스트 → 전체 통과
if (in_array($ip, $cfg['allow_ips'], true)) {
return;
}
// 2) 빈 User-Agent 차단
if ($cfg['block_empty_ua'] && $ua === '') {
bot_guard_deny(403);
}
// 3) 봇 차단
if ($ua !== '' && preg_match('/('.$cfg['bad_bots'].')/i', $ua)) {
bot_guard_deny(403);
}
// 4) Rate Limit
$dir = $cfg['store_dir'] !== '' ? $cfg['store_dir'] : sys_get_temp_dir();
$file = rtrim($dir, '/\\') . '/rl_' . md5($ip);
$now = time();
$limit = (int) $cfg['rate_limit'];
$window = (int) $cfg['rate_window'];
$fp = @fopen($file, 'c+');
if ($fp === false) {
return; // 저장소 문제 시 가용성 우선 — 통과
}
flock($fp, LOCK_EX); // 동시성 보호
$raw = stream_get_contents($fp);
$data = $raw ? json_decode($raw, true) : null;
if (!is_array($data) || !isset($data['c'], $data['t'])) {
$data = ['c' => 0, 't' => $now];
}
// 윈도우 만료 시 초기화
if ($now - $data['t'] > $window) {
$data = ['c' => 0, 't' => $now];
}
$data['c']++;
$over = $data['c'] > $limit;
// 기록
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, json_encode($data));
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
if ($over) {
$retry = $window - ($now - $data['t']);
header('Retry-After: ' . max(1, $retry));
bot_guard_deny(429);
}
})($GUARD);
// ─────────────────────────────────────────────
// 헬퍼
// ─────────────────────────────────────────────
function bot_guard_deny(int $code): void
{
$texts = [403 => 'Forbidden', 429 => 'Too Many Requests'];
http_response_code($code);
header('Content-Type: text/plain; charset=utf-8');
exit($texts[$code] ?? 'Forbidden');
}
?>
참고 하세요.
답변을 작성하려면 로그인이 필요합니다.
알려주신 곳으로 가봐서 찾아봤는데 위 문구를 찾을수가 없습니다.
$remote_addr =
mysql_real_escape_string($_SERVER['REMOTE_ADDR']);
$referer = mysql_real_escape_string($_SERVER['HTTP_REFERER']);
$user_agent = mysql_real_escape_string
($_SERVER['HTTP_USER_AGENT']);
$sql = " insert $g4[visit_table] ( vi_id, vi_ip, vi_date, vi_time, vi_referer, vi_agent ) values ( '$vi_id', '$remote_addr', '$g4[time_ymd]',
'$g4[time_his]', '$referer', '$user_agent' ) ";
//$sql = " insert $g4[visit_table] ( vi_id, vi_ip, vi_date, vi_time, vi_referer, vi_agent ) values ( '$vi_id', '$_SERVER
[REMOTE_ADDR]', '$g4[time_ymd]', '$g4[time_his]', '$_SERVER[HTTP_REFERER]', '$_SERVER[HTTP_USER_AGENT]' ) ";
$result = sql_query($sql, FALSE);
// 정상으로 INSERT
되었다면 방문자 합계에 반영
if ($result) {
$sql = " insert $g4[visit_sum_table] ( vs_count, vs_date) values ( 1, '$g4[time_ymd]' ) ";
$result = sql_query($sql,
FALSE);