Geolocalizzazione IP in PHP con GeoLite2 Guida passo passo

Passo dopo passo per implementare la geolocalizzazione IP in PHP con il database gratuito GeoLite2

Guida per configurare il NAS su Fritz!Box e collegarlo a una Smart TV

Dai vita alla tua app con la geolocalizzazione: Usa GeoLite2 e PHP per tracciare gli IP

Geolite2 è una libreria gratuita di MaxMind che fornisce database di geolocalizzazione per indirizzi IP. Questi database possono essere utilizzati per ottenere informazioni come il paese, la città, la latitudine e la longitudine degli utenti in base al loro indirizzo IP. Iniziamo con una guida passo passo per utilizzare GeoLite2 nel tuo progetto PHP.

Premesse: Cosa devi sapere per seguire questa guida

Questa guida ti mostrerà come utilizzare il database GeoLite2 di MaxMind per ottenere informazioni di geolocalizzazione a partire da un indirizzo IP in un'applicazione PHP. Prima di procedere, ci sono alcune nozioni di base che dovresti conoscere per ottenere il massimo da questa guida.

1. Conoscenza di base di PHP

Questa guida presuppone che tu abbia una conoscenza di base di PHP. Dovresti essere a tuo agio nel lavorare con il linguaggio, inclusi concetti come:

  • Dichiarazione di variabili
  • Funzioni e inclusione di file
  • Gestione degli errori (ad esempio, uso di try-catch)

Se non sei ancora familiare con PHP, potresti voler ripassare alcuni concetti fondamentali prima di procedere.

2. Familiarità con Composer

Comi fai i seo e i tag per i socialmposer è uno strumento di gestione delle dipendenze in PHP. Dovresti sapere come:

  • Installare e configurare Composer in un progetto PHP
  • Aggiungere librerie tramite Composer (usando il comando composer require)

Se non hai ancora utilizzato Composer, ti consiglio di consultare la documentazione ufficiale per una panoramica rapida.

3. Conoscenza di come funziona la geolocalizzazione IP

Anche se non è obbligatorio, avere una comprensione di base di come funziona la geolocalizzazione degli IP ti aiuterà a comprendere meglio l'applicazione di questa guida. La geolocalizzazione IP è un processo che mappa gli indirizzi IP agli utenti o dispositivi in base alla loro posizione fisica, come il paese, la città e le coordinate GPS.

4. Accesso e utilizzo di un database GeoLite2

In questa guida utilizzeremo i database GeoLite2 di MaxMind. Devi sapere come scaricare e configurare il database appropriato:

  • GeoLite2 City per ottenere informazioni dettagliate fino alla città
  • GeoLite2 Country per ottenere solo informazioni sul paese

Se non hai ancora un database GeoLite2, dovrai crearti un account su MaxMind e scaricare il file appropriato.

5. Ambiente di sviluppo PHP

Assicurati di avere un ambiente di sviluppo PHP configurato correttamente. Dovresti avere:

  • Una versione di PHP almeno 7.4 (consigliata la versione 8.0 o superiore)
  • Accesso alla riga di comando per installare Composer e le dipendenze
  • Un server locale o remoto dove poter eseguire i tuoi script PHP

6. Utilizzare la riga di comando su Linux

Per seguire questa guida, dovrai usare la riga di comando di Linux per eseguire alcune operazioni. Ecco alcuni comandi di base che ti potrebbero essere utili:

A premesse fatte cominciamo

La prima soluzone che non prevede l'utilizzo di composer, ma per i miei gusti risulta essere poco pratica. Iniziamo con il recuperare i file da su MaxMind i file che ci interessano sono

GeoLite2 ASN: CSV Format

una volta scaricato ed estratto lavoreremo su

  • GeoIP2-City-Blocks-IPv4.csv
  • GeoIP2-City-Blocks-IPv6.csv
  • GeoIP2-City-Locations-en.csv
<>il campo network del database usa la notazione CIDR. Sfortunatamente MySQL non offre alcuna capacità di lavorare con dati in quel formato, quindi dovremo prima convertire le reti in qualcos'altro che potremo interrogare facilmente in seguito. Hanno scelto di rappresentare le reti come una coppia di indirizzi IP che sono rispettivamente il primo e l'ultimo indirizzo nella rete. Convertiremo questo campo in modo che entrambi questi indirizzi IP siano rappresentati come numeri esadecimali. Possiamo usare lo strumento di conversione del database per convertire questo campo in numeri esadecimali. Una volta scaricato il programma e installato nella stessa directory in cui hai estratto i file CSV, puoi eseguirlo. Per installarlo procedi da terminale
sudo dpkg -i geoip2-csv-converter_1.4.1_linux_amd64.deb

Se ricevi errori relativi alle dipendenze mancanti, risolvili con:

                                                
sudo apt-get install -f
                                                
                                            

🔹 Verifica dell'installazione

Per verificare che il tool sia stato installato correttamente, esegui:

                                                
geoip2-csv-converter --version
                                                
                                            

🔹 Utilizzo di GeoIP2 CSV Converter

Per vedere tutte le opzioni disponibili, usa il comando:

                                                
geoip2-csv-converter --help
                                                
                                            

Ora hai tutto pronto per lavorare con GeoIP2 CSV Converter su Linux! 🚀

▶ Conversione di un database GeoLite2 in CSV

Esegui il seguente comando per convertire i file

GeoIP2-City-Blocks-IPv4.csv

E

GeoIP2-City-Blocks-IPv6.csv

in file Hex.CSV:

                                                
geoip2-csv-converter -block-file GeoIP2-City-Blocks-IPv4.csv -include-hex-range -output-file GeoIP2-City-Blocks-IPv4-Hex.csv
                                                
                                            
                                                
geoip2-csv-converter -block-file GeoIP2-City-Blocks-IPv6.csv -include-hex-range -output-file GeoIP2-City-Blocks-IPv6-Hex.csv
                                                
                                            

Ora possiamo creare una tabella chiamata geoip2_networkper contenere i dati appena convertiti. Rappresenteremo gli indirizzi IP usando il tipo varbinary(16), che sarà abbastanza grande da rappresentare indirizzi IPv6 a 128 bit (16 byte).

h2>1️⃣ Accedere a MySQL o MariaDB

Apri il terminale e accedi a MySQL:

                                                
mysql -u root -p
                                                
                                            

Nota: Sostituisci root con il tuo username MySQL se necessario. Ti verrà chiesta la password.

2️⃣ Creare un database (se non esiste)

Se non hai già un database per gestire i dati di GeoIP, creane uno:

                                                
CREATE DATABASE geoip2;
                                                
                                            

Usa il database appena creato:

                                                
USE geoip2;
                                                
                                            

3️⃣ Creare la tabella geoip2_network

Ora crea la tabella con:

                                                
CREATE TABLE geoip2_network (
network_start VARBINARY(16) NOT NULL,
network_end VARBINARY(16) NOT NULL,
geoname_id INT,
registered_country_geoname_id INT,
represented_country_geoname_id INT,
is_anonymous_proxy BOOLEAN DEFAULT FALSE,
is_satellite_provider BOOLEAN DEFAULT FALSE,
postal_code VARCHAR(20),
latitude DECIMAL(9,6),
longitude DECIMAL(9,6),
accuracy_radius INT,
is_anycast BOOLEAN DEFAULT FALSE,
INDEX idx_network_start (network_start),
INDEX idx_network_end (network_end)
);
                                                
                                            

✅ Conferma della Creazione

Se la creazione è andata a buon fine, MySQL restituirà:

                                                
Query OK, 0 rows affected
                                                
                                            

Caricamento e Ottimizzazione Dati GeoIP2

📌 Caricamento dei dati nella tabella geoip2_network

Ora possiamo importare i dati dalle tabelle GeoIP2-City-Blocks-IPv4.csv e GeoIP2-City-Blocks-IPv6.csv.

🔹 Importare i dati IPv6

                                                
LOAD DATA INFILE '/var/lib/mysql-files/GeoIP2-City-Blocks-IPv6-Hex.csv'
INTO TABLE geoip2_network
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS
(@network_start, @network_end, @geoname_id, @registered_country_geoname_id, @represented_country_geoname_id,
 @is_anonymous_proxy, @is_satellite_provider, @postal_code, @latitude, @longitude, @accuracy_radius, @is_anycast)
SET network_start = UNHEX(@network_start),
    network_end = UNHEX(@network_end),
    geoname_id = NULLIF(@geoname_id, ''),
    registered_country_geoname_id = NULLIF(@registered_country_geoname_id, ''),
    represented_country_geoname_id = NULLIF(@represented_country_geoname_id, ''),
    is_anonymous_proxy = NULLIF(@is_anonymous_proxy, ''),
    is_satellite_provider = NULLIF(@is_satellite_provider, ''),
    postal_code = NULLIF(@postal_code, ''),
    latitude = NULLIF(@latitude, ''),
    longitude = NULLIF(@longitude, ''),
    accuracy_radius = NULLIF(@accuracy_radius, ''),
    is_anycast = NULLIF(@is_anycast, '');       
                                            

🔹 Importare i dati IPv4

                                                
LOAD DATA INFILE '/var/lib/mysql-files/GeoIP2-City-Blocks-IPv4-Hex.csv'
INTO TABLE geoip2_network
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS
(@network_start, @network_end, @geoname_id, @registered_country_geoname_id, @represented_country_geoname_id,
 @is_anonymous_proxy, @is_satellite_provider, @postal_code, @latitude, @longitude, @accuracy_radius, @is_anycast)
SET network_start = UNHEX(@network_start),
    network_end = UNHEX(@network_end),
    geoname_id = NULLIF(@geoname_id, ''),
    registered_country_geoname_id = NULLIF(@registered_country_geoname_id, ''),
    represented_country_geoname_id = NULLIF(@represented_country_geoname_id, ''),
    is_anonymous_proxy = NULLIF(@is_anonymous_proxy, ''),
    is_satellite_provider = NULLIF(@is_satellite_provider, ''),
    postal_code = NULLIF(@postal_code, ''),
    latitude = NULLIF(@latitude, ''),
    longitude = NULLIF(@longitude, ''),
    accuracy_radius = NULLIF(@accuracy_radius, ''),
    is_anycast = NULLIF(@is_anycast, '');       
                                            

📊 Verificare i dati con una query

Ora che i dati sono caricati, possiamo eseguire una query per verificare la presenza di un IP specifico:

                                                
SELECT geoname_id, registered_country_geoname_id, represented_country_geoname_id,
postal_code, latitude, longitude, accuracy_radius
FROM geoip2_network
WHERE
  LENGTH(INET6_ATON('214.0.0.0')) = LENGTH(network_start)
  AND INET6_ATON('214.0.0.0') BETWEEN network_start AND network_end
LIMIT 1;                                        
                                            

🔹 Risultato della query

                                                
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
| geoname_id | registered_country_geoname_id | represented_country_geoname_id | postal_code | latitude | longitude | accuracy_radius |
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
|    6252001 |                       6252001 |                           NULL | NULL        |   37.751 |   -97.822 |            1000 |
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
1 row in set (0.03 sec)                         
                                            

⚡ Migliorare le prestazioni della query

Per velocizzare la ricerca possiamo ordinare la tabella:

                                                
SELECT geoname_id, registered_country_geoname_id, represented_country_geoname_id,
postal_code, latitude, longitude, accuracy_radius
FROM geoip2_network
WHERE
LENGTH(INET6_ATON('214.0.0.0')) = LENGTH(network_start)
AND INET6_ATON('214.0.0.0') BETWEEN network_start AND network_end
ORDER BY network_end
LIMIT 1;                                        
                                            

🔹 Miglioramento delle prestazioni

Se il database non trova l’indirizzo IP, la query potrebbe essere lenta. Per ottimizzare la ricerca, possiamo dividerla in due parti:

                                                
SELECT geoname_id, registered_country_geoname_id, represented_country_geoname_id,
postal_code, latitude, longitude, accuracy_radius
FROM (
  SELECT *
  FROM geoip2_network
  WHERE
    LENGTH(INET6_ATON('214.0.0.0')) = LENGTH(network_start)
    AND INET6_ATON('214.0.0.0') >= network_start
  ORDER BY network_start DESC
  LIMIT 1
) net
WHERE INET6_ATON('214.0.0.0') <= network_end;
                                                
                                            

🔹 Risultato della query ottimizzata

                                                
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
| geoname_id | registered_country_geoname_id | represented_country_geoname_id | postal_code | latitude | longitude | accuracy_radius |
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
|    6252001 |                       6252001 |                           NULL | NULL        |   37.751 |   -97.822 |            1000 |
+------------+-------------------------------+--------------------------------+-------------+----------+-----------+-----------------+
1 row in set (0.00 sec)                          
                                            

Questa tecnica migliora la velocità della ricerca nel database indipendentemente dalla presenza dell'IP.

Facoltativo: Creare una Tabella per i Dati sulle Posizioni

Se postal_code, latitude, longitude e accuracy_radius sono tutto ciò che ci interessa, la nostra applicazione sarebbe già in grado di interrogare i dati necessari. Tuttavia, i database GeoIP2 forniscono informazioni aggiuntive sulla posizione. Il campo geoname_id nella nostra tabella di rete può essere utilizzato per ottenere informazioni aggiuntive sui dati di geolocalizzazione dai file delle località scaricati in precedenza.

📌 Schema della Tabella delle Posizioni

Chiameremo questa tabella geoip2_location:

                                                
CREATE TABLE geoip2_location (
  geoname_id INT NOT NULL,
  locale_code TEXT NOT NULL,
  continent_code TEXT,
  continent_name TEXT,
  country_iso_code TEXT,
  country_name TEXT,
  subdivision_1_iso_code TEXT,
  subdivision_1_name TEXT,
  subdivision_2_iso_code TEXT,
  subdivision_2_name TEXT,
  city_name TEXT,
  metro_code INT,
  time_zone TEXT,
  is_in_european_union BOOL,
  PRIMARY KEY (geoname_id, locale_code(5))
);                                              
                                            

📂 Caricamento dei Dati nella Tabella delle Posizioni

Ora popoleremo la tabella con i dati dal file GeoIP2-City-Locations-en.csv:

                                                
LOAD DATA INFILE '/var/lib/mysql-files/GeoIP2-City-Locations-en.csv'
INTO TABLE geoip2_location
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS
(geoname_id, locale_code, continent_code, continent_name,
 @country_iso_code, @country_name, @subdivision_1_iso_code, @subdivision_1_name,
 @subdivision_2_iso_code, @subdivision_2_name, @city_name, @metro_code, @time_zone,
 is_in_european_union)
SET country_iso_code = NULLIF(@country_iso_code, ''),
    country_name = NULLIF(@country_name, ''),
    subdivision_1_iso_code = NULLIF(@subdivision_1_iso_code, ''),
    subdivision_1_name = NULLIF(@subdivision_1_name, ''),
    subdivision_2_iso_code = NULLIF(@subdivision_2_iso_code, ''),
    subdivision_2_name = NULLIF(@subdivision_2_name, ''),
    city_name = NULLIF(@city_name, ''),
    metro_code = NULLIF(@metro_code, ''),
    time_zone = NULLIF(@time_zone, '');
                                                
                                            

🔎 Consultare le Tabelle

Ora possiamo usare la nostra tabella geoip2_location per risolvere i geoname_ids dalla nostra tabella geoip2_network:

                                                
SELECT latitude, longitude, accuracy_radius, continent_name, country_name, subdivision_1_name, city_name
FROM (
  SELECT *
  FROM geoip2_network
  WHERE
    LENGTH(INET6_ATON('214.0.0.0')) = LENGTH(network_start)
    AND INET6_ATON('214.0.0.0') >= network_start
  ORDER BY network_start DESC
  LIMIT 1
) net
LEFT JOIN geoip2_location location ON (
  net.geoname_id = location.geoname_id AND location.locale_code = 'en'
)
WHERE INET6_ATON('214.0.0.0') <= network_end;
                                                
                                            

🌍 Unire Informazioni Aggiuntive

Possiamo includere ulteriori informazioni sulla posizione dei paesi registrati e rappresentati:

                                                
SELECT latitude, longitude, accuracy_radius,
       location.continent_name AS location_continent_name,
       location.country_name AS location_country_name,
       location.subdivision_1_name AS location_subdivision_1_name,
       location.city_name AS location_city_name,
       registered_country.continent_name AS registered_country_continent_name,
       registered_country.country_name AS registered_country_country_name,
       represented_country.continent_name AS represented_country_continent_name,
       represented_country.country_name AS represented_country_country_name
FROM (
  SELECT *
  FROM geoip2_network
  WHERE
    LENGTH(INET6_ATON('214.0.0.0')) = LENGTH(network_start)
    AND INET6_ATON('214.0.0.0') >= network_start
  ORDER BY network_start DESC
  LIMIT 1
) net
LEFT JOIN geoip2_location location ON (
  net.geoname_id = location.geoname_id AND location.locale_code = 'en'
)
LEFT JOIN geoip2_location registered_country ON (
  net.registered_country_geoname_id = registered_country.geoname_id
  AND registered_country.locale_code = 'en'
)
LEFT JOIN geoip2_location represented_country ON (
  net.represented_country_geoname_id = represented_country.geoname_id
  AND represented_country.locale_code = 'en'
)
WHERE INET6_ATON('214.0.0.0') <= network_end;
                                                
                                            

Conclusione

Abbiamo importato e interrogato i dati GeoIP2 nel nostro database MySQL, ottimizzando le query per migliori prestazioni.

🔜 Prossima guida: Metodo più semplice utilizzando Composer

Nel prossimo articolo, vedremo un metodo più rapido e meno complesso per gestire i dati GeoIP utilizzando Composer.

Lascia il tuo Feedback


PIACE: 0

NON PIACE: 0