در پست قبلی درباره بانک اطلاعاتی و جداول لازم برای نرم افزار Hit Counter مطالبی خواندید . در این پست درباره پیاده سازی Hit Counter در فاز اول مطالبی خواهید خواند . این مرحله مربوط است به نحوه ساخت یک User Control که در تمامی صفحه ها باید قرار گیرد . در فاز اول به غیر از شناسایی کلمات کلیدی در موتورهای جستجو تمامی بخش های دیگر پیاده سازی می شود .
در این پست جداول مورد نیاز ذکر شدند . کمی تغییرات برای ادامه کار لازم است ، اول IP ها به جای Char می بایست numeric شوند یا یک فیلد جدید برای مقدار عددی IP ها ایجاد شود . تغییر دوم جدول کشورهاست که می بایست مقدار حداقل و حداکثر عددی IP برای کشورهای مختلف را در خود جای دهد . بانک اطلاعاتی IP و کشورها را می توان از اینجا دریافت کرد . البته هم اکنون از همین بانک اطلاعاتی روی سایت حامد بنایی استفاده می شود ولی محدوده IP برای ایران ناقص است . یک مقدار Uknown هم به رکوردهای این بانک اطلاعاتی اضافه کردم و ID اش را در برنامه برای مقدارهای نامشخص قرار دادم .
یک فایل LINQ to SQL با نام HitCounterDB به پروژه اضافه و جداول را به آن اضافه کردم .

برای جستجو در این بانک اطلاعاتی IP باید به عدد تبدیل شود . برای تبدیل IPبه عدد ، اگر یک IP را به شکل a.b.c.d در نظر بگیریم با استفاده از فرمول زیر می توان مقدار عددی آن IP را بدست آورد .
V=a*256 ^ 3+b*256 ^ 2+c*256 ^ 1+d
من توسط این تابع مقدار عددی هر IP را در نرم افزار محاسبه کرده ام .
Private Function GetValueOfIP(ByVal strIP As String) As Long
Dim oct1, oct2, oct3, oct4 As Int64
Dim s() As String = strIP.Split(".")
If s.Length <> 4 Then Return 0
oct1 = Val(s(0)) * 256 ^ 3
oct2 = Val(s(1)) * 256 ^ 2
oct3 = Val(s(2)) * 256 ^ 1
oct4 = Val(s(3))
Return oct1 + oct2 + oct3 + oct4
End Function
بعضی موقع مثل localhost خودم IP را به شکل :::1 تشخیص می داد ، در این حالت که IP غلط است مقدار 0 توسط تابع فوق بازگردانده می شود .
برای پیدا کردن نوع سیستم عامل از Request.UserAgent و تابع زیر استفاده کرده ام .
Private Function GetOSName(ByVal UserAgentData As String) As String
If InStr(UserAgentData, "Windows NT 6.0") > 0 Then
Return "Windows Vista"
End If
If InStr(UserAgentData, "Windows NT 5.2") > 0 Then
Return "Windows Server 2003"
End If
If InStr(UserAgentData, "Windows NT 5.1") > 0 Then
Return "Windows XP"
End If
If InStr(UserAgentData, "Windows NT 5.01") > 0 Then
Return "Windows 2000 SP1"
End If
If InStr(UserAgentData, "Windows NT 5.0") > 0 Then
Return "Windows 2000"
End If
If InStr(UserAgentData, "Windows NT 4.0") > 0 Then
Return "Microsoft Windows NT 4.0"
End If
If InStr(UserAgentData, "Windows 98; Win 9x 4.90") > 0 Then
Return "Windows Millennium Edition"
End If
If InStr(UserAgentData, "Windows 98") > 0 Then
Return "Windows 98"
End If
If InStr(UserAgentData, "Windows 95") > 0 Then
Return "Windows 95"
End If
If InStr(UserAgentData, "Windows CE") > 0 Then
Return "Windows CE"
End If
If InStr(UserAgentData, "Macintosh") > 0 Then
Return "Macintosh"
End If
If InStr(UserAgentData, "Linux ") > 0 Then
Return "Linux "
End If
Return "Unknown"
End Function
البته باید حالت های دیگر را در نظر گرفت .
در رویداد load در User Control ، کد زیر را برای ثبت بازدید ، بازدید کننده و دیگر مشخصات نوشتم .
Dim db As New HitCounterDBDataContext
Dim intPageID As Integer
Dim p = (From ps In db.Pages Where ps.URL = Request.Path.ToLower Select ps).SingleOrDefault
If Not p Is Nothing Then
intPageID = p.ID
p.Hits += 1
db.SubmitChanges()
Else
Dim newPage As New Page With {.URL = Request.Path.ToLower, .Hits = 1}
db.Pages.InsertOnSubmit(newPage)
db.SubmitChanges()
intPageID = newPage.ID
End If
Dim strIPAddress As String = HttpContext.Current.Request.UserHostAddress.ToLower
Dim intIP As Int64 = GetValueOfIP(strIPAddress)
Dim intVisitorID As Integer
Dim visitorss = (From v In db.Visitors Where v.IP = intIP And v.DateTime.Date = Now.Date Select v).SingleOrDefault
If visitorss Is Nothing Then
Dim intCounterID = (From cc In db.ip_to_countries Where cc.BeginingIP <= intIP And cc.EndingIP >= intIP Select cc.ID).SingleOrDefault
If intCounterID = 0 Then
intCounterID = 65262
End If
Dim newVis As New Visitor With {.CountryID = intCounterID, .DateTime = Now, .Hits = 1, .IP = intIP}
db.Visitors.InsertOnSubmit(newVis)
db.SubmitChanges()
intVisitorID = newVis.ID
Else
visitorss.Hits += 1
intVisitorID = visitorss.ID
db.SubmitChanges()
End If
Dim intRefID As Integer = -1
If Not Request.UrlReferrer Is Nothing Then
Dim refs = (From re In db.Referrers Where re.DateTime.Date = Now.Date And re.URL = Request.UrlReferrer.Host & Request.UrlReferrer.PathAndQuery _
Select re).SingleOrDefault
If refs Is Nothing Then
Dim rr As New Referrer With {.DateTime = Now, .Domain = Request.UrlReferrer.Host, .Hits = 1, .URL = Request.UrlReferrer.Host & Request.UrlReferrer.PathAndQuery}
db.Referrers.InsertOnSubmit(rr)
db.SubmitChanges()
intRefID = rr.ID
Else
refs.Hits += 1
intRefID = refs.ID
db.SubmitChanges()
End If
End If
Dim h As New Hit With {.BrowserName = Request.Browser.Browser & " " & Request.Browser.Version, _
.DateTime = Now, .OSName = GetOSName(Request.UserAgent), .PageID = intPageID, _
.RefID = intRefID, .VisitorID = intVisitorID, .ScreenSize =
"123123"}
db.Hits.InsertOnSubmit(h)
db.SubmitChanges()
ابتدا می بایست شماره صفحه ای که بازدید از آن انجام شده را در بانک اطلاعاتی پیدا کرد ، اگر ثبت شده بود ID قبلی و اگر ثبت نشده بود ، ثبت شود و IDش نگهداری شود . اگر صفحه جاری ثبت شده بود باید یک عدد به ستون Hit آن افزوده شود .
بعد از پیدا کردن شماره صفحه باید شماره Visitor را پیدا کرد . اگر ویزیتور در بانک اطلاعاتی وجود داشت یک عدد به Hit آن افزوده می شود . به همین شکل اگر بازدید جاری از سایت دیگری می آمد آدرس آن سایت در referrer ذخیره می شود. اگر بازدید از سایت دیگری نبود مقدار -1 برای شماره سایت لینک دهنده ذخیره می شود .
در آخر نیز یک هیت جدید به جدول مربوطه افزوده می شود . با این اطلاعات ذخیره شده هر نوع گزارش از وضعیت سایت قابل استخراج است . تنها یک نکته در این مرحله باقی مانده و آن هم مشخصات مانیتور بازدید کننده است که راهی در سمت سرور برای آن پیدا نکردم .
روش استفاده از code behind برای شمارش بازدید صفحه ها آمار بسیار متفاوتی نسبت به آنهایی که از javascript استفاده می کنند ارائه می کند . در همین سایت حامد بنایی ، نزدیک به 4 برابر بیشتر از آمار webgozar است !
در پست های بعدی ، بهینه سازی ، گزارش ها (نمودار و جدوال )، قفل کردن رکوردها برای به روز رسانی و ... را خواهید خواند .