使用 Classic ASP 检查地理位置数据库

Check geolocation database using Classic ASP

我有一个用于确定国家/地区的 IP 地址范围数据库,但需要一个用 Classic ASP 编写的函数来找到用户 IP 地址适合的范围.

例如数据库行如下:

102.23.25.0   |  102.24.0.0   |  US

如果 IP 地址是 102.23.25.203,我该如何找到匹配项?

这似乎比 VB 更像是一个数据库问题。像下面这样的查询应该可以做到。

select locationName 
from IPLocationTable
where @inputIP >= IPStartRange
  and @inputIP <= IPEndRange

您使用标准 ADO 数据访问发出此查询,例如

sql = "put select statement here"
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.ConnectionTimeout = TIMEOUT
Conn.Open CONNECTIONSTRING
Set rs = Server.CreateObject("ADODB.Recordset")
set rs.ActiveConnection = Conn
rs.Open sql,,adOpenForwardOnly,adLockReadOnly,adCmdText
set countryName =  rs("locationName")
rs.close
conn.close

这里有一个测试来说明我的意思。请注意,您必须稍微修改 IP 以添加前导零。

CREATE TABLE IPLocationTable(
    [StartIP] [varchar](50) NULL,
    [EndIP] [varchar](50) NULL,
    [Location] [varchar](50) NULL
) ON [PRIMARY]
go
insert IPLocationTable(StartIP, EndIP, Location) values ('192.168.001.001', '192.168.001.255', 'Location1')
insert IPLocationTable(StartIP, EndIP, Location) values ('192.168.002.001', '192.168.002.255', 'Location2')
insert IPLocationTable(StartIP, EndIP, Location) values ('192.168.003.001', '192.168.004.255', 'Location3')
insert IPLocationTable(StartIP, EndIP, Location) values ('192.168.005.001', '192.168.006.255', 'Location4')
insert IPLocationTable(StartIP, EndIP, Location) values ('195.168.001.001', '196.168.001.255', 'Location5')
insert IPLocationTable(StartIP, EndIP, Location) values ('197.169.001.001', '198.169.001.255', 'Location6')
go

declare @myIP varchar(20)

set @myIP = '192.168.001.150'
select location from IPLocationTable where @myIP >= StartIP and @myIP <= endIP

set @myIP = '192.168.002.150'
select location from IPLocationTable where @myIP >= StartIP and @myIP <= endIP

set @myIP = '196.168.001.150'
select location from IPLocationTable where @myIP >= StartIP and @myIP <= endIP

您可以使用Request.ServerVariables("REMOTE_ADDR")获取用户的IP地址,然后简单地测试地址段...

Function TestIp(testAddr, loIp, hiIp)
    Dim host, rLo, rHi, fail, i
    host = Split(testAddr, ".")
    fail = False
    rLo = Split(loIp, ".")
    rHi = Split(hiIp, ".")
    For i = 0 To 3
        'If one of the host values falls outside the range then it's all over...
        fail = CInt(host(i))<CInt(rLo(i)) Or CInt(host(i))>CInt(rHi(i))
        If fail Then Exit For
    Next 'i
    TestIp = fail
End If

SQL版本

我们知道一个事实,即每个 IP 都可以分成四个。执行此操作的命令是 CHARINDEX and SUBSTRING 的组合。只需将测试值分解为四个并对低值和高值执行相同的操作,然后针对各自的高值和低值测试每个字节。

这是一个函数,我花了几分钟才写出来,就是为了做到这一点:

/*
    getIpQuad
        Returns the required quad of an IP address.
    Usage:
        SET @q2 = getIpQuad('127.0.0.1', 2)
    Parameters:
        @ip (STRING) - The IP address
        @quad (TINYINT) - The quad to retrieve (zero based)
*/
CREATE FUNCTION [dbo].[getIpQuad] 
    (@ip AS VARCHAR(15), 
     @quad AS TINYINT)

RETURNS TINYINT AS
BEGIN

    DECLARE @i AS TINYINT
    DECLARE @s AS TINYINT
    DECLARE @e AS TINYINT
    DECLARE @v AS VARCHAR(3)

    SET @s = 0
    SET @e = 0
    SET @i = 0

    WHILE @i<=@quad
    BEGIN
        SET @e = CHARINDEX('.', @ip, @s+1)
        IF  @e = 0 AND @s>1 SET @e = LEN(@ip)
        SET @v = SUBSTRING(@ip, @s+1, @e-@s)
        SET @s = @e
        SET @i = @i + 1
    END

    RETURN (CAST(@v AS TINYINT))
END 

注意:我没有包括任何边界检查,它依赖于你知道你在做什么的事实。

我使用 MaxMind CSV 数据库将其导入 MS-SQL。然后写了一个简单的经典ASP例程来获取国家代码。

strCheckIPnumber = Request.ServerVariables("REMOTE_ADDR")

if strCheckIPnumber <> "" then
    strGeoArray = Split(strCheckIPnumber, ".")
    For i=0 to UBound(strGeoArray)
    Next            
    strGeo1 = strGeoArray(0)
    strGeo2 = strGeoArray(1)
    strGeo3 = strGeoArray(2)            
    strGeo4 = strGeoArray(3)

    strGeoNumber = strGeo1 * 16777216 + strGeo2 * 65536 + strGeo3 * 256 + strGeo4

    'response.write"GeoNumber = " & strGeoNumber & "<br>"

    SQLGeo = "SELECT Country FROM GeoLocation Where GeoLocation.StartNum <= '" & strGeoNumber & "' and GeoLocation.EndNum >= '" & strGeoNumber & "' "
    Set rsGeo = dbConnection.Execute(SQLGeo)    
    if NOT rsGeo.EOF then       
        strGeoCountry = rsGeo("Country").value
    end if
    rsGeo.Close
    Set rsGeo = Nothing

    response.write"GeoCountry = " & strGeoCountry & "<br>"

end if