Geolokalizacja

Z tego artykułu dowiesz się jak działa geolokalizacja oraz co zrobić aby dodać jej obsługę bez instalowania rozszerzenia dla PHP.

Spis treści

^ Wprowadzenie

Obsługa geolokalizacji jest nowością wprowadzoną w eStats 4.9. Domyślnie używa bazy danych za pośrednictwem rozszerzenia dla PHP pod nazwą geoip. Jednak nawet jeśli nie posiadasz i nie możesz doinstalować tego rozszerzenia na swoim serwerze, to nic straconego, w dalszej części artykułu opisana jest alternatywna metoda dodania obsługi geolokalizacji.

^ Budowa

Biblioteka lib/geoip.php wykorzystuje funkcję geoip_record_by_name () w celu pobrania danych dla podanego adresu IP.

Biblioteka ta deklaruje poniższy zestaw funkcji:

  • e_geo_info_available () - zwraca logiczną prawdę, gdy geolokalizacja jest dostępna, w przeciwnym wypadku zwraca fałsz;
  • e_geo_init () - inicjalizuje działanie modułu (jednorazowe wczytywanie danych pomocniczych);
  • e_geo_info (STRING adres_ip) - zwraca tablicę danych geolokalizacyjnych dla podanego adresu IP lub 0city - miasto, region - identyfikator regionu, country - identyfikator kraju, continent - identyfikator kontynentu, latitude oraz longitude - szerokość i długość geograficzną położenia;
  • e_coordinates (FLOAT szerokość_geograficzna, FLOAT długość_geograficzna) - zwraca obrobiony ciąg tekstowy z reprezentacją podanych współrzędnych;

^ Alternatywa

W przypadku braku rozszerzenia na serwerze można posiłkować się wygenerowaną bazą SQLite, o podanej strukturze:

1
2
CREATE TABLE "blocks" ("ipstart" INTEGER, "ipend" INTEGER, "location" INTEGER, PRIMARY KEY ("ipstart", "ipend", "location"));
CREATE TABLE "locations" ("location" INTEGER PRIMARY KEY, "city" TEXT, "region" TEXT, "country_code" TEXT, "latitude" FLOAT, "longitude" FLOAT);

Gdy dostępna jest baza, a nie istnieje funkcja geoip_record_by_name (), to jest definiowana przez bibliotekę.

Bazę danych można wygenerować z użyciem skryptu napisanego w Pythonie. Potrzebne są do tego celu pliki CDV ze strony GeoLite City (GeoLiteCity-Blocks.csv oraz GeoLiteCity-Location.csv) oraz oczywiście interpreter tego języka. Skrypt należy uruchomić wewnątrz katalogu, do którego wypakowaliśmy wyżej wymienione pliki. Po wygenerowaniu bazy należy przenieść plik wynikowy (geoip.sqlite) do katalogu danych (domyślnie data/) i nazwać go geoip_$DBID.sqlite, gdzie $DBID ma wartość, którą możemy znaleźć w pliku conf/config.php. Wygenerowanie bazy danych o rozmiarze 267 MB z 97 MB danych wejściowych zajęło skryptowi 7 minut.

Kod skryptu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python
import csv, sqlite
print 'A Python script for converting MaxMind free geoip CSV files (named GeoLiteCity-Blocks.csv and GeoLiteCity-Location.csv, from http://www.maxmind.com/app/geolitecity) from current directory into SQLite2 database for eStats >= 4.9.'
print '(c) 2007 Emdek, license: GPL.'
print ''
print 'Enter 1 to start converting or 0 to exit:'
Option = raw_input()
if int(Option)==0:
    print 'Aborting...'
    exit()
Exists = 1
try:
    File = open('geoip.sqlite')
    File.close()
except:
    Exists = 0
Connection = sqlite.connect('geoip.sqlite')
Cursor = Connection.cursor()
if Exists==0:
    Cursor.execute('CREATE TABLE "blocks" ("ipstart" INTEGER, "ipend" INTEGER, "location" INTEGER, PRIMARY KEY ("ipstart", "ipend", "location")); CREATE TABLE "locations" ("location" INTEGER PRIMARY KEY, "city" TEXT, "region" TEXT, "country_code" TEXT, "latitude" FLOAT, "longitude" FLOAT);')
    print 'Database tables created...'
else:
    print 'Using existing database...'
try:
    File = open('GeoLiteCity-Blocks.csv', 'rb')
except:
    print 'Can not open file "GeoLiteCity-Blocks.csv"!';
    exit()
CSVFile = csv.reader(File)
i = 0
for CSVLine in CSVFile:
    i += 1
    if i < 3:
        continue
    try:
        Cursor.execute('INSERT INTO "blocks" VALUES (%d, %d, %d)', (int(CSVLine[0]), int(CSVLine[1]), int(CSVLine[2])))
    except:
        print 'An error occured during insertion of row into database!'
print i,' rows inserted into table "blocks"...'
File.close()
try:
    File = open('GeoLiteCity-Location.csv', 'rb')
except:
    print 'Can not open file "GeoLiteCity-Location.csv"!';
    exit()
CSVFile = csv.reader(File)
i = 0
for CSVLine in CSVFile:
    i += 1
    if i < 3:
        continue
    try:
        Cursor.execute('INSERT INTO "locations" VALUES (%d, %s, %s, %s, %f, %f)', (int(CSVLine[0]), str(CSVLine[3]), str(CSVLine[2]), str(CSVLine[1]), float(CSVLine[5]), float(CSVLine[6])))
    except:
        print 'An error occured during insertion of row into database!'
print i,' rows inserted into table "locations"...'
File.close()
try:
    Connection.commit()
    print 'Database saved successful.'
except:
    print 'An error occured during saving database file!'
print ''
print 'Copy generated file (geoip.sqlite) into Your $DataDir directory as geoip_$DBID.sqlite.'
Ostatnia modyfikacja: 2008-02-18 15:00:11 CET

Dobry polityk musi umieć przepowiedzieć, co będzie się działo jutro, za tydzień, czy za rok i musi umieć wytłumaczyć, dlaczego nie zaszło to, co przepowiedział.

Winston Leonard Spencer Churchill