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

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
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 MariaDBApri 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