GeoInfo

Location data for ProcessWire - By IP (local database), or coordinates (OpenStreetMap)

ProcessWire - GeoInfo


Location data for ProcessWire:

  • By IP address from a local database: country, region, city, coordinates, continent. No visitor data leaves your server.
  • By coordinates from OpenStreetMap Nominatim: nearest place, region, country and distance. Results are cached.
$geoInfo = $modules->get('GeoInfo');

echo $geoInfo->ip()?->countryCode;                    // "DE"
echo $geoInfo->place(52.52, 13.405)?->place;          // "Berlin"

The IP database is the free DB-IP City Lite database, which the module downloads and updates every month. You can also use MaxMind GeoLite2 City or any other compatible MMDB file.

Contents


Requirements


  • PHP 8.1 or later with the zlib extension (to unpack the downloaded database)
  • ProcessWire 3.0.200 or later
  • About 125 MB of disk space for the IP database. During an update, up to 300 MB are needed temporarily.
  • Outgoing HTTPS connections to download.db-ip.com (database downloads) and nominatim.openstreetmap.org (place())
  • LazyCron (core module) for automatic monthly updates. This is optional.

Installation


All dependencies are included in the vendor/ directory, so Composer is not required.

  1. Place the folder in site/modules/ so that the module file is located at site/modules/GeoInfo/GeoInfo.module.php.
  2. In the admin, go to Modules > Refresh.
  3. Find GeoInfo in the list and click Install.
  4. In the module settings, check Download now and click Submit. The module then downloads the current DB-IP City Lite database to site/assets/GeoInfo/ (about 60 MB compressed).

place() works right after installation. ip() returns null until the database has been downloaded.

Usage


Location by IP address

$geoInfo = $modules->get('GeoInfo');

$geo = $geoInfo->ip();                 // current visitor
$geo = $geoInfo->ip('203.0.113.42');   // specific IPv4 or IPv6 address

if($geo) {
	echo $geo->countryCode;  // "DE"
	echo $geo->city;         // "Berlin"
}

ip() returns a WireData object, or null in these cases:

  • the IP address is invalid
  • the IP address is private or reserved, e.g. 192.168.x.x or 127.0.0.1 (keep this in mind on local development setups)
  • the IP address is not in the database
  • no database is available

Lookups run against the local file, take well under a millisecond, and are cached for the rest of the request.

PropertyDescriptionExample
ipThe IP address that was looked up8.8.8.8
cityCityMountain View
regionRegion / stateCalifornia
regionCodeRegion code (GeoLite2 only)CA
postalCodePostal code (GeoLite2 only)94043
countryCodeISO 3166-1 alpha-2 country codeUS
countryNameCountry nameUnited States
inEUCountry is a member of the European Unionfalse
continentCodeContinent codeNA
continentNameContinent nameNorth America
latitudeLatitude (approximate)37.422
longitudeLongitude (approximate)-122.085
timezoneTime zone (GeoLite2 only)America/Los_Angeles
sourceDatabase typeDBIP-City-Lite
creditAttribution text of the databaseIP Geolocation by DB-IP (https://db-ip.com)

The names of cities, regions, countries and continents use the language set in the module settings. If a name is not available in that language, the English name is used. In DB-IP City Lite, only country and continent names are translated. City and region names are always in English.

Place by coordinates

$place = $modules->get('GeoInfo')->place(40.712784, -74.005941);

if($place) {
	echo $place->place;               // "New York"
	echo $place->countryCode;         // "US"
	echo $place->distanceKilometers;  // 5.31
}

// names in a specific language
$place = $modules->get('GeoInfo')->place(48.8566, 2.3522, 'de'); // "Paris", "Frankreich"

Latitude and longitude can be passed as floats or numeric strings. place() returns null in these cases:

  • the coordinates are invalid
  • the coordinates are outside of any place, e.g. on the open sea
  • Nominatim cannot be reached

Results are cached for 30 days (WireCache), so repeated lookups of the same coordinates don't send another request. This includes coordinates for which nothing was found. Failed requests are not cached.

Nominatim returns the nearest administrative area, which is often a district. place contains the city, town or village of that area, while latitude, longitude and the distance refer to the area itself. In the example above, the area is Manhattan, so the distance is measured to the center of Manhattan.

PropertyDescriptionExample
placeNearest city, town or villageNew York
displayNameFull name of the area foundManhattan, New York County, New York, United States
regionRegion / stateNew York
regionCodeISO 3166-2 region codeUS-NY
postalCodePostal code, if available
countryCodeISO 3166-1 alpha-2 country codeUS
countryNameCountry nameUnited States
latitudeLatitude of the area found40.7579554
longitudeLongitude of the area found-73.9855319
distanceKilometersDistance between the given coordinates and the area found5.31
distanceMilesThe same in miles3.3
creditAttribution text© OpenStreetMap contributors (…)

Nominatim usage policy: the public Nominatim server allows at most one request per second and does not allow bulk geocoding. Single lookups for page views are fine thanks to the cache. For heavy use, see the Nominatim usage policy and consider running your own Nominatim server.

Settings


Go to Modules > Configure > GeoInfo.

SettingDescriptionDefault
StatusShows the database in use, its type, build date and size.
Custom database filePath to your own MMDB file of the type "City". Relative paths start at the ProcessWire root directory. Leave blank to use the managed DB-IP database.blank
Update automaticallyDownloads the new DB-IP City Lite database once a month via LazyCron.on
Download nowDownloads the current DB-IP City Lite database when you save the settings.
LanguageISO code for place names in the results of ip() and place(), e.g. en or de.en
Trust proxy headersTakes the visitor IP from the X-Forwarded-For / Client-IP header. Only enable this behind a reverse proxy or load balancer, otherwise visitors can fake their IP address.off
Log errorsWrites errors to the log geoinfo.on

DB-IP publishes a new database at the beginning of each month. With automatic updates enabled, LazyCron checks once a day whether the current month is installed and downloads it if not. The download runs at the end of a regular page request and usually takes a few seconds.

If you prefer a real cron job, disable Update automatically and call the update yourself, e.g. once a day:

$modules->get('GeoInfo')->updateDatabase();

Using MaxMind GeoLite2


GeoLite2 City is often more accurate and also provides region codes, postal codes and time zones. It requires a free MaxMind account.

  1. Download GeoLite2-City.mmdb from your MaxMind account. To keep it updated, use MaxMind's geoipupdate tool.
  2. Place the file on your server outside the web root, e.g. in /var/lib/GeoIP/GeoLite2-City.mmdb (a default directory of geoipupdate). The GeoLite2 license does not allow redistribution. A file in site/assets/ could be downloaded by anyone.
  3. Enter the absolute path under Custom database file in the module settings.

The module does not update custom database files.

Attribution


Both data sources require attribution on pages that show their data:

  • DB-IP City Lite is licensed under CC BY 4.0. Add a link such as <a href="https://db-ip.com">IP Geolocation by DB-IP</a>.
  • OpenStreetMap data is licensed under the ODbL. Credit "© OpenStreetMap contributors".

The credit property of each result contains the matching text.

Privacy


  • ip() looks up IP addresses in a local file. No visitor data is sent to third parties.
  • place() sends the coordinates to the OpenStreetMap Foundation (Nominatim). If these are a visitor's coordinates, e.g. from the browser's Geolocation API, mention this in your privacy policy.

Upgrading from 1.x


Version 1.x used the geoPlugin web service. geoPlugin is no longer available for free, so version 1.x no longer works.

The old methods $page->GeoInfoIP() and $page->GeoInfoLatLong() still work. They return objects with the old geoplugin_* property names, so existing templates keep working. Please note the following differences:

  • geoplugin_areaCode, geoplugin_dmaCode and the geoplugin_currency* fields are always null.
  • New fields: geoplugin_inEU, geoplugin_continentName and geoplugin_timezone.
  • GeoInfoIP() returns geoplugin_status 404 and empty fields if no result is available (private IP address, IP address not in the database, no database).
  • The result is no longer stored in the session. Each IP address now gets its own result.
  • The visitor IP is taken from REMOTE_ADDR by default. Enable Trust proxy headers if you need the old behavior.
  • GeoInfoLatLong() now also accepts whole numbers such as 52 and returns the place from OpenStreetMap. Place names and distances can differ slightly from geoPlugin.

The old methods are deprecated. For new code, use $modules->get('GeoInfo')->ip() and ->place().

To upgrade:

  1. Make sure the server runs PHP 8.1 or later.
  2. Delete the old file site/modules/GeoInfo/GeoInfo.module and copy the new files into the folder.
  3. Go to Modules > Refresh. ProcessWire updates the module to version 2.0.0.
  4. Download the database in the module settings (see Installation).

Logs


Setup > Logs > geoinfo contains database updates and, with Log errors enabled, failed downloads, unreadable database files and failed Nominatim requests.

Translations


All texts in the admin are translatable with ProcessWire's language support. The source language is English.

To import the included German translation:

  1. Go to Modules > Site (or Modules > Configure) and open GeoInfo.
  2. In the module information, the row Languages lists de. Click install translations.
  3. For each language that should use German, select de under Import into ... and submit.

For other languages, go to Setup > Languages, edit the language, click Find Files to Translate and select site/modules/GeoInfo/GeoInfo.module.php.

Place names in lookup results are not affected by this. They follow the Language setting of the module, see Settings.

Updating dependencies


The PHP library maxmind-db/reader is included in vendor/. To update it, run composer update in the module directory.

License


MIT

Included third-party code:

More modules by pmichaelis

  • GeoInfo

    Location data for ProcessWire - By IP (local database), or coordinates (OpenStreetMap)
  • Wrap Table

    Wrap a container div around markup tables.

All modules by pmichaelis

Install and use modules at your own risk. Always have a site and database backup before installing new modules.