이번 기사에서는 global.asa를 이용해서, 사이트에 접속해 들어온 사용자들의 접속정보를 데이터베이스에 저장하는 방법을 알아보고, 차후 그 데이터를 통해  간략하게(?) 접속통계를 내어 보도록 하겠습니다.

2회.  접속자 정보 기록

참고 : 이번 기사부터 진행될 테스트는 NT 4 (IIS 4), MS SQL 7, IE 5 기준으로 작성되었음을 밝힙니다. 기타 다른 데이터베이스나 브라우저로도 같은 결과를 보실 수는 있습니다만 상황에 따라 약간의 소스수정이 필요할 수도 있습니다.

이전 기사에서 우리는 지루하리만치 Global.asa에 대해서 다루었습니다. 조금은 따분하였을지도 모르지만 그 고행(?)의 길을 묵묵히 참고 오신 분이라면 이번 기사에서 여러분들은 상대적으로 쉽게 원하는 결과를 이끌어 낼 수가 있을 것 같네요. 그렇겠지요? 우리가 이번 기사에서 하고자 하는 것은 크게는 3가지입니다.

1. 사용자의 접속정보 얻어내기
2. ASP에서의 데이터베이스 연동
3. Global.asa를 통해서 데이터베이스에 사용자 정보를 저장

위 내용들을 기반으로 저장된 데이터를 분석하여 사이트의 접속 통계를 내는 것은 다음 번 기사에서 다루어질 것이구요. 이번 기사에서는 그 접속통계를 위한 데이터를 수집하는 과정을 다루어 보려고 합니다. 즉, 다음 그림과 같이 일별, 시간별, 요일별 접속 통계를 비주얼하게 보기 위한 일종의 준비 단계랍니다. 디자인이 썰렁하다구요? T.T

 

1. 사용자의 접속정보 알아내기.

ASP 에서는 클라이언트가 서버로 보내오는 여러 데이터들을 가져오는 객체로 Request라는 객체가 존재합니다. 그리고, 그 객체의 메소드 중에 ServerVariables라는 메소드가 있는데 이 메소드는 환경변수(environment variables) 값들을 가져오는 메소드이지요. 서버에 지정된 환경변수들로 ALL_HTTP, REMOTE_ADDR, HTTP_REFERER, HTTP_USER_AGENT 등등이 있는데 이러한 변수의 값들을 Request.ServerVariables("환경변수")의 형식으로 얻어올 수가 있는 것입니다. 자세한 이야기는 곧 다루어 질 것이지만 간략히 이야기하면 서버측에서는 현재 접속한 사용자의 IP 주소를 알아내기 위해서는
Request.ServerVariables("REMOTE_ADDR")를 요청하면 되는 것입니다. 이해하기 쉽게 간략한 예를 하나 들어보도록 하지요.

다음과 같은 ASP 페이지를 만들고 그 결과를 브라우저를 통해서 보도록 하겠습니다. 기쁜 마음으로 같이 해 보아요~~

<HTML>
<BODY>
<font face="돋움" size="2"><P>&nbsp;</P><center>
<h2>현재 사용자님은</h2>
<p>&nbsp;</P>
사용하시는 IP는 <%=Request.ServerVariables("REMOTE_ADDR")%> 이시구요.<p>
브라우저와 OS는 <%=Request.ServerVariables("HTTP_USER_AGENT")%> 이십니다.
</center></font>
</BODY>
</HTML>

결과화면

REMOTE_ADDR 라는 환경변수의 값으로 그 사용자의 IP인 210.127.210.12 를 얻어왔고, 그 사용자의 브라우저, OS등은 HTTP_USER_AGENT 라는 변수의 값으로 얻어올 수가 있었습니다. 기억해야 할 것은 서버측에서는 클라이언트의 정보를 제한적으로 가져올 수가 있다는 것입니다. 모든 클라이언트의 정보를 가져올 수는 없어요. 예를 들어 클라이언트 기기의 하드웨어 정보나 시스템 사양등은 얻어올 방법이 없죠. 제공되는 환경변수의 값만을 얻어올 수가 있다는 것을 주의하세요. 간혹, 사용자의 VGA 카드가 무엇인지 그 것을 알아내고 싶다는 식의 질문을 받는데요. 그것은 ASP로는 어렵습니다. 그리고,  Request.ServerVariables 메소드를 통해서 가져올 수 있는 값들은 클라이언트 측의 값들만이 아니구요 서버측의 정보도 가져올 수가 있어요.

참고 : HTTP_USER_AGENT로 얻어오는 정보

HTTP_USER_AGENT를 통해 얻어지는 정보로 다음과 같은 것들도 있을 수가 있습니다.   참고만 하시라고 몇가지 예를 든 것이예요. 참고입니다. 참고. 참고..

WebZIP/3.0 (http://www.spidersoft.com)  :
     spidersoft.com 의 WebZIP Offline Browser로 사이트의 문서들을 모두 긁어(?)가는 경우

Teleport Pro/1.28 :
     마찬가지로 Teleport를 통해서 사이트의 문서들을 모두 긁어(?)가는 경우

Mozilla/4.61 [ko] (X11; I; Linux 2.2.12-20kr i686)  : Linux에서 접근했을 경우

Mozilla/4.6 (Macintosh; I; PPC) : Mac에서 접근했을 경우

이 시점에서 여러분은 분명 필자가 그러했던 것처럼(?)  "그렇다면 과연 어떤 정보들을 가져올 수가 있을까? 제공되는 환경변수들에는 어떤 것들이 있는가?"  궁금해 할 것입니다. 궁금하시죠?. MSDN 사이트에 가면 그 정보들을 볼 수 있지만 다음 소스로도 환경 변수들과 그에 매치(match)되는 값들을 볼 수가 있을 것입니다.  그런 면에서 다음 소스는 상당히 유용한 소스일 것입니다.

<HTML>
<BODY>
<center><h2>ServerVariable All</h2></center>
<TABLE border="1">
<TR><TD><center>Key</center></TD>
<TD><center>Value</center></TD></TR>
<% For Each key in Request.ServerVariables %>
<TR>
<TD><center><font face="돋움" size="2"><% = key%></font></center></TD>
<TD><font face="돋움" size="2">
<% if Request.ServerVariables(key) = "" Then
   Response.Write "&nbsp" else    Response.Write Request.ServerVariables(key)
end if %>
</font></TD></TR>
<% Next %>
</TABLE>
</BODY>
</HTML>

이 소스의 결과로 웹 서버에서 제공되는 환경 변수들이 보여지며, 그에 대응하는 값들이 또한, 출력되어지게 됩니다. 지정되어지지 않은 값들은 공백으로
나타나게 될 것이구요. 다음 그림처럼 말입니다. 저도 환경변수들을 다 외우지는 못하기에 기억이 안 날때는 이 소스를 실행시켜서 필요한 것을 찾아보고는 한답니다.

위의 소스 중에서 여러분이 조금은 관심을 가져야 할 구문이 있다면 컬렉션에서 사용하는 For문인데요. 이것이 상당히 유용한 구문인데,  기존의 for문에 비해 훨씬 유용합니다. 단지 이 for문은 컬렉션의 경우에만 사용이 가능하지요. 그렇다면 컬렉션이란 무엇인가요? 컬렉션은 배열과 비슷한 구조를 가지고 있는 녀석으로서, 각 요소와 키 값을 이용해 값을 저장할 수 있는 데이터구조를 의미하며, 배열보다는 여러모로 훨씬 강력한 기능을 가진답니다.  키 값을 알고 있다면 컬렉션에 데이터를 넣거나 가져올 수가 있는 것이지요.  컬렉션이라는 표현이 조금은 어렵게 느껴진다면 업그레이드된 배열 비슷한 표현이라고
생각해도 큰 무리는 없을 것 같아요.

   For Each 변수 in 컬렉션
      컬렉션(변수)
   Next

   For Eachkey in Request.ServerVariables
       '... Request.ServerVariables(key)..
   Next

변수의 이름은 여러분이 구미에 맞게 지정하면 되지요. 그러면 변수를 통해서 컬렉션에 존재하는 각각의 키를 알파벳 순서대로 불러와 그에 대응하는 값을 가져오게 됩니다. Request.ServerVariables 와 관련된 좀 더 자세한 내용들은 다음 사이트(MSDN사이트)에서 확인할 수가 있을 겁니다. ( MSDN : http://msdn.microsoft.com/library/psdk/iisref/vbob5vsj.htm ) 우리가 접속통계를 내기 위해 필요한 환경변수들에 대해서는 잠시 후 조금은 더 알아보게 될 것이니 느긋하게 읽어나가시면 될 것입니다. 프로그래머에게 조급함은 결코 피해셔야할 적입니다.

참고 : 이번 기사부터 진행될 테스트는 NT 4 (IIS 4), MS SQL 7, IE 5 기준으로 작성되었음을 밝힙니다.

 

2. ASP에서 데이터베이스를 연동하기

ASP 페이지로 데이터베이스에서 뽑아낸 어떤 데이터를 가져오거나,  데이터베이스에 어떤 데이터를 저장하기 위해서는 ADO(ActiveX Data Object) 객체를 사용합니다.  IIS 자체에서 제공이 되어지는 멋진 객체이지요. ASP 페이지에서는 일반적으로 ADO를 사용해서 데이터베이스와의 연동을 하게 되는데 이것은 상당히 편리하며 안정적입니다.  세부적으로는 데이터베이스와의 연동을 위해서 ADO의 특별한 3 가지의 객체를 사용할 수 있게끔 제공하고 있는데요.

그들은 각각 Connection Object( ProgID: ADODB.Connection ), Recordset Object( ProgID: ADODB.Recordset ), Command Object( ProgID: ADODB.Command ) 입니다. 이 들을 사용하여 데이터베이스를 연결하고, 우리가 원하는 결과를 얻어낼 수가 있게 되는 것이지요.

Connection 객체 원격지에 존재하는 데이터에 대한 Access를 위해 사용
Execute 메소드를 통한 질의 가능
RecordSet 객체 SQL 질의 결과 리턴되는 데이터를 Access하기 위해 제공
Command 객체 SQL 질의 실행, 레코드를 추출, 데이터의 직접 조작을 위해 사용
동시에 여러 작업의 결과 데이터가 필요할 경우에만 효과적



ASP 페이지에서 데이터베이스를 연결, 사용하기 위한 목적으로는 Connection 개체가 제공되어 집니다. Connection 개체는 특정 데이터베이스와 연결을 할 수 있게 해 주는 객체이며, 리턴 결과 레코드가 없는 간단한 쿼리를 수행할 수 있습니다. 물론, 리턴 결과가 있는 SELECT 쿼리를 수행할 수도 있지만 그럴 경우 레코드셋 객체를 필요로 합니다.

레코드셋 객체? 이 친구는 하는 역할이 무엇일까요?  데이터베이스 서버에서 사용자가 필요한 데이터를 추출하기 위해서 SELECT 쿼리를 던지게 되면, 분명 그 쿼리에 따른 결과 레코드가 있을 것인데요. 그렇다면 그 결과 레코드를 어디에 저장할까요? 다시 말해서, 데이터베이스에 존재하는 수많은 데이터 중에서 우리가 추출하기를 원하는 데이터를 ASP 페이지로 가져온다면, 일단 그 데이터들을 담아놓을 곳이 필요할텐데요.  바로, 이 부분을 담당하는 것이 RecordSet 객체라는 것입니다. 무척이나 중요한 역할을 하는 객체이지요. 정리하면 ADO의 RecordSet 객체가 담당하는 것은 바로 쿼리 결과로 추출된 데이터를 보관하는 역할이랍니다. 그리고, Command 객체가 존재하는데요.

이 객체는 SQL 서버의 스토어드 프로시져를 사용할 경우 등에 사용되는 객체입니다. 여기서 이 객체들을 다루는 방법까지 소개하기엔 너무나도 그 분량이 크기에 자세한 내용들은 여러분이 가지고 있는 ASP 서적이나 MSDN 사이트로 넘기고자 해요. 저의 마음이야 그 이야기를 여기서 자세히 풀어주고 싶지만  이미 이 기사를 읽고 접근하시는 독자들은 이미 그 정도의 객체는 다룰 줄 안다고 가정하기에 기분좋게 넘기고자 합니다. 하지만, 속으로는 진정으로 여러분들에게 양해를 구할 따름입니다. 양해. 양해... (각각의 객체들은 표를 통해서 다시 한번 확인해 주세요)

여기서는 간략하게 Connection객체와 RecordSet 객체를 짚어보고 넘어가려 합니다. 데이터베이스와의 연결을 담당한다고 말씀드린 Connection객체는 다음과 같이 그 인스턴스를 만들어서 ASP 페이지에서 사용할 수가 있게 됩니다.

Set Dbcon = Server.CreateObject("ADODB.Connection")

Server.CreateObject 라는 것은 무엇일까요? 이것은 ASP에서 사용이 가능한 객체의 인스턴스(Instance)를 만들어주는 역할을 하는 Server 객체의 메소드입니다. 즉, 다시 말해서 ASP 페이지에서 자체적으로 특별히 제공되어지는 Connection등과 같은 객체들을 사용하기 위해서는 그들의 인스턴스를 만들어서 사용해야 하는데, 그렇게 하게끔 해주는 역할을 하는 메소드가 Server.CreateObject 라는 것이지요.

단지 어떤 객체가 제공되어진다고 해서 그것을 그냥 사용할 수는 없습니다. 주어지는 객체는 일종의 설계도이고, 인스턴스는 그 설계도를 돋움으로 만들어진 물체(오브젝트)이기에, 우리는 제공되는 객체를 사용하기 위해서는 그 객체의 인스턴스를 만들어야 하는 것이지요. 그 역할(객체의 인스턴스의 생성)을 해주는 것이 Server개체의 CreateObject라는 메소드인 것입니다. 괄호 안에 사용하고자 하는 개체의 아이디를 적어줌으로써 우리가 지정한 객체의 인스턴스를  생성할 수 있는 것이지요.

그리고, 이 객체들은 ASP 자체에서 제공이 되어지는 것도 있지만, 여러분이 스스로 제작한  것 일 수도 있고, 또한 돈을 주고 이러한 컴포넌트 객체를 구입해서 사용할 수도 있어요. (국내의 유명한 컴퍼넌트 업체로는 아이메카가 있답니다. http://asp.imeca.co.kr )

또한, ASP 페이지에서 컴포넌트 객체들을 가져다가 사용하기 위해서는 반드시 Set 연산자를 사용해서 지정해주어야 합니다. 변수의 선언은 필요없지만(해주는 것을 추천합니다) Set 연산자로 반드시 세팅은 해 주어야만 해요. 안 그러면 얄미운 에러가 여러분을 반길 겁니다. 즉, ASP 페이지에서 Server.CreateObject로 객체의 인스턴스를 만들 경우는 Set 연산자롤 통해서 세팅을 해주어야만 한다는 것입니다.

Connection 객체의 가장 중요한 메소드는 Open 메소드입니다. 이 Open메소드를 통해서 우리가 ODBC로 세팅한 데이터베이스로의 접근이 가능해지기 때문이지요. 윈도우즈 환경에서 데이터베이스를 연동할 경우는 주로 ODBC를 사용하는데요. ODBC를 세팅하는 방법은 이미 많은 서적들에서 빠지지 않고 제공되어져 있는 부분이고,  필자의 사이트에도 강좌로 보실 수가 있어요. ODBC 세팅이 궁금하신 분들은 참고하세요~.

ODBC란?

Open Database Conectivity 의 약자로 MS사의 데이터베이스를 비롯해서, Oracle, 사이베이스등의 상이한 데이터베이스에서 구축된 데이터들을   MS 윈도우즈 환경에서 상호간에 나누어 쓸 수 있도록 해주는 데이터베이스의   데이터 공유를 위한 규격이예요. 그래서, ODBC를 사용하면 데이터베이스의 종류가 무엇이던지 간에 그 데이터들을 Windows에서 불러다가 마음대로   사용할 수가 있는 것이지요.


Connection 객체의 Open 메소드의 사용방법은 다음과 같습니다.

Set Dbcon = Server.CreateObject("ADODB.Connection")
Dbcon.Open("DSN=DSN이름;UID=계정아이디;PWD=비밀번호;")

위의 코드에서 DSN이름 이라고 되어져 있는 부분에 여러분이 세팅한 ODBC의 DSN 이름을 적어주면 되구요, UID와 PWD 각각에는 데이터베이스에 로긴할 수 있는 계정아이디와 비밀번호를 적어주면 됩니다. 이것만으로 데이터베이스와의 연결은 된 것이지요.

또한, 자주 사용하는 Connection 객체의 메소드로는 Execute 메소드가 있는데요. 주로 데이터를 삽입, 수정할 경우 사용하는데, 다음과 같이 사용합니다.

Dbcon.Execute "Insert into (name, mail) value ('taeyo','taeyo@fifi.co.kr')"

혹은 다음과 같이 사용하는데요, 개인적으로는 다음 방법을 더 추천해요.

strSQL = "Insert into (name, mail) value ('taeyo','taeyo@fifi.co.kr')"
Dbcon.Execute strSQL

최신 ODBC 드라이버를 다운로드 받는 곳은??

간단하게 MS 사이트에 가셔서 다운로드 센터로 가시면 되지요. 그리고, 다음과 같이 Microsoft Data Access Components를 찾으시면 됩니다. 그리고, 푸서리 사이트의   자료실에서도 최신버전을 쉽게 구하실 수 있어요. (Http://dongari.puseori.co.kr)

다음으로 RecordSet 객체에 대해서 알아볼까요? 이 객체가 담당하는 것은 쿼리결과로 추출된 데이터를 보관하는 역할이예요. RecordSet 객체를 사용하기 위해서도 Connection 객체의 경우와 마찬가지로 객체의 인스턴스 변수를 만들어야 합니다. 아래가 바로 그 예를 나타내는 코드이지요.

Set Rs = Server.CreateObject("ADODB.RecordSet")

이번 예의 경우 그 인스턴스 변수의 이름을 Rs라고 주었지만, 이 부분은 여러분이 원하는 이름을 마음대로 사용해도 상관은 없어요. 그리고, RecordSet 객체도 Connection 객체와 비슷하게도 Open 이라는 메소드를 가지고 있어요. 이름은 같으나 그 기능은 전혀 틀리며, 레코드 셋 객체의 가장 대표적인(?) 메소드랍니다. 이 Open 메소드는 여러 개의 인자를
가지지만, 일반적으로 우리는 2개의 인자를 지정하게 되고, 나머지는 기본값을 사용하고는 하는 편이에요. 다음과 같이 말이지요.

Set Rs = Server.CreateObject("ADODB.RecordSet")
Rs.Open "Select * from MyFriend" , DBcon

이 RecordSet 객체를 사용하기 위해서는 그 이전에 Connection 객체가 존재해야만 해요. 데이터베이스 연결이 없으면 쿼리를 던질 수도 없고, 그 내용을 수행할 수도 없으니 말입니다. (하지만, 반드시 그런 것은 아닙니다. 명시적인 커넥션 객체 없이도 레코드 셋 객체에서 직접 수행할 방법은 있는데요. 사실은 그러한 경우도 백그라운드에서 커넥션 객체는 자동으로 만들어지는 것이니 커넥션 객체는 반드시 존재해야 한다고 말씀드리는 것이랍니다.)

Open 메소드의 첫 번째 인자는 위에서 보이듯이 우리가 추출하고자하는 내용, 즉 쿼리입니다. 그리고, 두 번째 인자는 데이터베이스 커넥션 객체이구요.  레코드셋 객체를 사용하기 위해서는 최소한 이 두가지 설정은 해주어야만 합니다.
물론, 그 외에도 몇 몇 인자를 뒤에 추가로 지정할 수가 있지요. 위에서 생략된 3번째 인자는 레코드 셋의 커서타입을 지정하는 것이고, 4번째 인자는 그 Lock 타입을 지정하는 것입니다. 지정을 하지 않으면 디폴트 세팅으로 저절로 잡히게 됩니다.

여러분은 RecordSet 객체의 Open 메소드를 사용할 경우 첫 번째 인자로 쿼리, 두 번째 인자로 커넥션 객체를 사용한다는 것을 알았습니다. 그러나, 위에서의 예처럼 첫 번째 인자로 쿼리 문장을 다 넣어주는 것은 사실상 여러모로 불편합니다. 만일 쿼리가 길다면 소스를 분석하기가 어렵기 때문이지요. 해서 일반적으로는 쿼리로 사용할 문자열을 미리 어떤 변수에 넣고, 그 변수를 가져다가 이용하는 다음과 같은 방법을 사용하고는 한답니다. 위의 예의 경우 다음과 같이 사용하는 것이 좋을 것이예요.

Set Rs = Server.CreateObject("ADODB.RecordSet")
SQL = "Select * from MyFriend"
Rs.Open SQL, DBcon

위의 Open메소드를 수행하게 되면 그 쿼리의 결과가 Rs라는 객체내에 저장되어지게 됩니다. 그리고, Move, MoveFirst, MoveLast, MovePrevious, MoveNext 등의 RecordSet 객체의 메소드를 사용해서 결과 레코드들 사이를 이동하며 필요한 레코드를 가져올 수가 있습니다. 그리고, 레코드를 지정하게 되면 Rs.Fields("컬럼이름") 이라는 코드로써 우리가 지정한 레코드에서의 필요한 컬럼의 값을 가져올 수가 있게 되지요.

다음의 예는 Connection객체와 RecordSet 객체를 사용해서 데이터베이스로부터 쿼리에 맞는 데이터를 가져와서 보여주는 아주 간단한 예제 소스와 그 결과 ASP 페이지입니다.

   <% 
   Set Dbcon = Server.CreateObject("ADODB.Connection") 
   Dbcon.Open "Friend" 
   Set Rs = Server.CreateObject("ADODB.RecordSet") 
   SQL = "Select * from MyFriend where m_id='taeyo'" 
   Rs.Open SQL, DBcon 
   %> 
   <HTML> 
   <HEAD><title>ASP & DB</title> 
   </HEAD><BODY> 
   <h2>쿼리결과로 가져와진 데이터입니다.</h2><p> 
   이름은 <%=Rs.Fields("m_name")%><p> 
   나이는 <%=Rs.Fields("m_age")%><p> 
   성별은 <%=Rs.Fields("m_sex")%><p> 
   가입일은 <%=Rs.Fields("m_joinday")%><p> 
   </BODY></HTML> 
   <% 
   Rs.close 
   Dbcon.close 
   Set Rs = nothing 
   Set Dbcon = nothing 
   %>


3. Global.asa를 통해서 데이터베이스에 사용자의 정보를 저장하기

이제 위의 두 가지 지식을 돋움으로 여러분의 사이트에 접속하는 사용자들의 접속통계를 내기 위한 준비를 해 보도록 하겠습니다. 위에서 우리가 배운 지식은 이번 기사와 다음 기사에 걸쳐 사용하게 될 것이니 꼭 기억해 두시기를 바래요.
잘 이해가 안 가서 너무나도 짜증만 밀려오신다면 그대로도 좋습니다.

사실 가볍게 이해할 수 있는 것들은 아니니까요. 차근히 편하게 생각하세요. 억지로 외울라고 노력하지는 마세요. 서서히 여러분들의 머리 속에서 정리가 되어질 것이니까요. 모든 것은 시간이 해결 해 준답니다. 여러분이 애정(?)을 가져주기만 한다면요. 그러니, 부담을 가지시지는 마세요.

자. 이제 우리에게 필요한 것은 사용할 데이터베이스를 만들고, 테이블을 구성하는 것입니다. 여기서는 MS SQL 7.0 서버를 사용할 것이지만, 사정이 여의치 않다면 MDB로도 가능할 것입니다. MS Access도 훌룡한 데이터베이스이니 말이지요. 하지만, 동시 접속이 많은 경우 MS Access(97 기준)는 조금은 불리한 편이니 실제로 운영하실 경우는 데이터베이스 서버를 준비하시는 것이 여러모로 좋을 것 같습니다.

이 기사는 MS SQL 7 과 IIS 4, IE 5 기준으로 진행나가고 있다는 것을 기억하세요. 기타 다른 데이터베이스나 브라우저로도 같은 결과를 보실 수는 있습니다만 상황에 따라 약간의 소스수정이 필요할 수도 있습니다.

데이터베이스를 하나 생성하셨다면 다음과 같이 테이블을 구성하도록 하세요. 테이블의 구성이 불만족스러울 수도 있겠네요. (필요없어 보이는 컬럼이 있다고 생각하실 수도 있어요)  일단은(?) 여러분을 위한 배려이니 그 부분에 대해서는 너무 꼬집어주지는 않으셨으면 합니다. 왜 그렇게 구성을 했는지는 금방 이야기를 드릴 예정입니다.

   CREATE TABLE [dbo].[Statistic] (  
   [stat_code] [int] IDENTITY (1, 1) NOT NULL Primary Key,
   [user_ip] [varchar] (15) NOT NULL,
   [user_agent] [varchar] (50) NOT NULL,
   [refer_page] [varchar] (100) NULL,
   [log_time] [datetime] NOT NULL,
   [s_mon] [tinyint] NULL,
   [s_day] [tinyint] NULL,
   [s_hour] [tinyint] NULL
   )

인덱스의 경우는 필자는 s_mon에 clustered index를, s_day에는 nonclustered index를 주었으며, 프라이머리 키는 stat_code에 주었습니다. 물론, 이 방법이 효율적이라고 장담드리기는 어렵지만, 약 10만 건의 데이터를 가지고 테스트를 했었을 때, 나름대로는 빠른 결과를 얻을 수가 있었어요. 참고로 필자가 데이터베이스에는 내공이 높지 못한 관계로 조금은 위의 설정이 뭔가 부족할 수도 있다는 것을 인정하고자 합니다.

내공이 뛰어나신 분은 자신의 사이트에 접속통계를 걸고자 하실 경우, 이 연재기사를 마치고 스스로 적절하게 튜닝을 하시기 바랍니다. (제 사이트는 위의 설정대로 운영중입니다.)

테이블에 정해진 컬럼들에 각각 저장할 내용은 접속한 사용자의 IP주소(user_ip컬럼)와 사용자의 브라우저와 OS등의 Agent 정보(user_agent), 참조해서 접속한 페이지(refer_page), 접속시간(log_time)과 월(s_mon), 일(s_day), 시(s_hour) 입니다. 사실상 위에서 s_mon, s_day, s_hour 컬럼은 필요없는 컬럼일 수도 있어요. log_time에서 모두를 뽑아낼 수 있기 때문이지요. 그렇기는 하지만, 굳이 컬럼을 추가로 지정한 것은 여러분이 보면서 이해하시기 쉽게 하기 위함이고, log_time에서 각각의 월, 일, 시 값을 뽑아내서 그룹핑을 하는 것보다는 각각의 컬럼으로 그룹핑하는 것이 조금은 속도도 나아보여서 였습니다.

모아진 데이터를 가지고, 적절히 통계를 만들어 내는 것은 다음 기사에서 다룰 것이지만, 미리 조금 준비하는 마음으로 이야기를 해 보았습니다. 이제 이 구성된 테이블에 데이터를 어떠한 식으로 넣을 것인지를 알아보도록 합시다. 접속하는 사용자들마다 그들 각각의 접속시간과 그 시간, agent등을 저장하고자 하지만, 그 시점을 언제로 잡아야 할 것인가가 문제이겠지요? 어떤 ASP 페이지에서 그 사용자의 정보들을 데이터베이스에 저장할까요?

사이트의 메인 페이지에 접근했을 때? 그것도 좋은 대답입니다. 그러나, 사용자가 메인 페이지로 접근하지 않고, 특정 페이지로 직접 접근할 경우는 어떻게 할까요? 그럴 경우는 그의 데이터는 수집될 수가 없을 것입니다. 그래요. 메인 페이지는 부적절합니다. 그렇다면? 뻔히 그 위치가 Global.asa이어야 하는 것을 알고있는데, 이야기를 괜히 한번 돌려보는 것이라 생각하세요? 그렇습니다. 그런 것입니다. ^-^


모든 사용자들이 사이트에 접속하는 순간, 단 한사람도 빼놓지 않고, 정보를 수집하고자 할 경우 가장 그 처리를 하기에 적절한 장소는 Global.asa 입니다.  그리고, 그 안의 이벤트중에 Session_OnStart 이벤트가 가장 적절할 것이구요.

만일, Global.asa가 무엇이고, 왜 그곳이 최적의 장소인지 모르겠는 분이 있다면 지난 4월호 기사를 읽어보시기 바래요. 그리고, 그림 6을 참조하시기 바래요.

데이터베이스를 만드셨다면, 그 데이터베이스의 ODBC 세팅을 해주셔야 하겠지요? 여러분 스스로 하실 수 있을 것입니다. 그렇죠? DSN이름은 같이 통일하도록 할까요? DSN이름은 그림 7처럼 Statistics 으로 주시기 바랍니다.  자. 그럼 그 소스를 살펴보도록 할까요??

 

<SCRIPT LANGUAGE="VBScript" RUNAT="Server"> 
Sub Session_OnStart
   On Error Resume Next
   Set Dbcon = Server.CreateObject("ADODB.Connection")
   Dbcon.open("DSN=Statistics;UID=계정아이디;PWD=비밀번호;")
   sql = "INSERT INTO Statistic (user_ip, user_agent, refer_page,"
   sql = sql & " log_time, s_mon, s_day, s_hour) values "
   sql = sql & "('" & request("REMOTE_ADDR") & "',"
   sql = sql & "'" & request("HTTP_USER_AGENT") & "',"
   sql = sql & "'" & refer & "',"
   sql = sql & "getdate(),"
   sql = sql & month(date) & ","
   sql = sql & day(date) & ","
   sql = sql & hour(time) & ")"
   dbcon.execute sql
   dbcon.close
   Set dbcon = nothing
End Sub
</SCRIPT>

사용자들의 접속정보를 저장하는 내용의 Global.asa 안의 코드를 살펴보면, 4가지 이벤트중에서 오직 Session_OnStart 이벤트 만을 정의하고 있음을 볼 수 있습니다. 나머지 3개의 이벤트는 왜 기입하지 않았을까요? 그것은 MS에서 제공한 문서에 나와있는 충고를 따르고 있기 때문인데요. Global.asa에서는 꼭 필요한 이벤트 함수가 아니면 코딩을 하지 않는 것이 유리하다고 하네요.

해서 Global.asa에서는 우리가 필요한 이벤트인 Session_OnStart만을 정의하고 있는 것입니다. 모든 사용자들이 사이트의 ASP 페이지로 접근하는 순간, 누구도 예외없이 거쳐 지나가야 하는 Session_OnStart 이벤트!! 사용자들의 접속정보를 얻기 위한 최고의 장소이겠지요??

이 Session_OnStart 이벤트에서는 Statistic 이라는 테이블에 사용자들의 정보를 각각 기입하고 있습니다. 그림 8은 바로 그렇게 데이터베이스에 저장된 데이터들을 보여주고 있습니다.


많은 초보분들이 ASP에서 쿼리를 작성하면서 곤혹스러워 하시는데요. 예를 들면, 위의 소스에서 다음과 같은 부분을 이해하지 못해서 난감해 하시고는 합니다.

sql = "INSERT INTO Statistic (user_ip, user_agent, refer_page,"
sql = sql & " log_time, s_mon, s_day, s_hour) values "
.......

ASP 에서는 문자열의 결합을 위해서 & 라는 기호를 사용합니다.  이 기호는 두 개의 문자열을 합하는 기능을 가지는데,
예를 들면 "그레이트한 " & "태오" 의 결과는 "그레이트한 태오"가 되는 것이지요. 그리고, 문자열은 "로 시작하여 "로 끝나는 것을 문자열로 인정하게 되구요. 이것은 문자열을 변수에 지정할 경우에도 마찬가지입니다. 예를 들면,

str1 = "그레이트한 "
str2 = "태오"
str = str1 & str2

일 때, str의 결과는 "그레이트한 태오"가 되는 것이지요.  '(작은따옴표)도 a, b, c와 같은 하나의 문자입니다.
"로 인해서 ' 도 어떤 쓰임새가 있는 것이 아닌가 착각하시는데, 문자열 결합내에서의 '는 하나의 문자일뿐입니다. 예를 들면,

str1 = "나의 이름은 '태오' "
str2 = " 라고들 하지요"

일 때 두 문자열(str1, str2)을 합지면 그것은 "나의 이름은 '태오' 라고들 하지요" 가 되는 것이지요. 이렇게 이해하시면 문자열의 결합은 그다지 어려운 일이 아닐 겁니다. 해서, 위의 원래의 소스에서의 Insert SQL 구문은 예를 들면  다음과 같이 만들어진다는 것입니다.

INSERT INTO Statistic2 (user_ip, user_agent, refer_page, log_time, s_mon, s_day, s_hour) VALUES
('211.58.20.61','Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)','http://www.taeyo.com/',getdate(),4,10,23)

참고로, 문자열을 테이블에 Insert 하실 경우는 반드시 문자열 앞, 뒤로 ' 를 붙여야 한다는 것은 알고 계시지요? 그렇기에, 문자열 결합 시에 눈에 거슬리게(?) ' 가 섞여있었던 것이었습니다.

자. 이제 여러분은 데이터를 수집하는 것만이 남아있습니다.  모든 준비가 되어졌으니, 이제는 충분한 데이터만이 필요한 것이지요. 필자는 충분한 데이터를 수집해서(설마 몇 천건의 데이터를 제가 직접 입력할 것이라고 생각하시는 것은 아니시지요?) 다음 기사에서 여러분을 만나뵙도록 하겠습니다. 그래야 통계를 낼 경우에 조금은 아름다운(?) 결과를 같이 볼 수가 있을테니까요.

'asp' 카테고리의 다른 글

NIC에서 인터넷 도메인 정보 얻어오기  (0) 2007.05.02
접속자 정보 기록  (0) 2007.05.02
Global.asa와 사이트 카운터  (0) 2007.05.02
구조화된 Stored Procedure 사용법  (0) 2007.05.02
ActiveX Data Object 2.5 and over  (0) 2007.05.02

+ Recent posts