Open-source project
maxmind/GeoIP2-php avatar
maxmind/GeoIP2-php

GeoIP2-php: MaxMind's PHP Reader for MMDB Databases and Web Services

PHP API for GeoIP2 webservice client and database reader

2,493 stars286 forksPHPApache-2.0

At a glance

What is it?
GeoIP2-php is the official PHP client for MaxMind's GeoIP2 and GeoLite databases and web services. It is a thin, typed wrapper around MMDB lookups, and its main constraints are the accuracy limits of IP geolocation itself and the licence terms attached to the data files.
Who is it for?
Adopt GeoIP2-php if you are running PHP and need country, city, or connection-type data from a MaxMind MMDB file or web service, and you accept that locations are approximate. Do not adopt it if you need household-level precision, or if you cannot take on the licence terms of the data file you plan to ship.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What GeoIP2-php Is For, and Who Should Reach for It

The package answers one question: given an IP address, what does MaxMind's data say about it. The README describes it as an API for the GeoIP and GeoLite web services and databases. That is the whole scope. It is not a geolocation engine, not a data source, and not a caching layer. It reads a file you already have, or calls a service you already have credentials for.

The audience is PHP applications that need to branch on an IP. Fraud screening, regional content rules, currency defaults, log enrichment, and rate limiting by country are the usual shapes. The README is explicit that the output should not be used to identify a particular address or household, and that locations are often near the center of the population. That sentence is the most important one in the document, and it is easy to skim past.

If your requirement is "which city is this user in, to the block," this library will not meet it, and no other library will either, because the underlying data does not contain that resolution. If your requirement is "which country and roughly which metro area," it is a reasonable fit.

How the Reader Object and MMDB Lookups Actually Work

The mechanism is a memory-mapped binary search over an MMDB file. You construct a Reader with the path to the database as the first constructor argument, and the README states the object should be reused across lookups. That instruction matters: constructing a Reader per request reopens and revalidates the file each time, which is wasted work in a long-running process.

From the Reader you call a method named after the database you loaded. The README shows city(), anonymousIp(), anonymousPlus(), connectionType(), domain(), and enterprise(). Each returns a model class, and the model contains nested containers: country, mostSpecificSubdivision, city, postal, location, traits. The traits container carries the network, which is the CIDR block the record matched, not the IP you passed in. That distinction is easy to miss when you are printing results.

Two failure modes are documented. If the record is not found, a \GeoIp2\Exception\AddressNotFoundException is thrown. If the database is invalid or corrupt, a \MaxMind\Db\InvalidDatabaseException is thrown. Both are exceptions, not sentinel return values, so an unguarded lookup in a loop will terminate on the first private or unroutable address it encounters. Private ranges are not in the public database, which is the most common source of surprise here.

Installing GeoIP2-php with Composer and Running a First Lookup

The README recommends Composer and gives the download step for the installer. Run this in the root of your project, and you should end up with composer.phar in that directory.

bash
curl -sS https://getcomposer.org/installer | php

Then require the package. The README pins the constraint at ^3.4.0, which matches the v3.4.0 release. After this you should see composer.json, composer.lock, and a vendor directory.

bash
php composer.phar require geoip2/geoip2:^3.4.0

Require the autoloader from your code before using any class.

php
require 'vendor/autoload.php';

The first real use is opening a City database and reading a record. The path here is the one the README uses; substitute wherever your mmdb file actually lives.

php
<?php
require_once 'vendor/autoload.php';
use GeoIp2\Database\Reader;

$cityDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');
$record = $cityDbReader->city('128.101.101.101');

print($record->country->isoCode . "\n"); // 'US'
print($record->city->name . "\n"); // 'Minneapolis'
print($record->traits->network . "\n"); // '128.101.101.101/32'

You should see US, Minneapolis, and the matched network. If instead you get an AddressNotFoundException, the address is not in the file. If you get an InvalidDatabaseException, the file is corrupt or you pointed the Reader at the wrong database type.

There is also a phar archive published on the releases page, which the README offers as an alternative to Composer. It requires the PHP Phar extension, and web-service requests through the phar require the cURL extension. Without cURL the README says you will see an error like Call to undefined function MaxMind\WebService\curl_version().

The Optional C Extension and What It Does Not Speed Up

The MaxMind DB API has an optional C extension that the README says can dramatically increase the performance of lookups in GeoIP or GeoLite databases. The word dramatically is MaxMind's, not a measured figure, and the README does not publish a number. Installation instructions live with that other API, not here.

The important boundary: the extension has no effect on web-service lookups. If you are calling the web service rather than reading a local file, the C extension buys you nothing, and your latency is dominated by the network round trip. That is a real architectural fork. Local MMDB reads are fast and offline; web-service calls are slower but always current and do not require you to ship a data file. Choose based on which of those two properties you need, because the C extension only helps one side of it.

Where GeoIP2-php Is the Wrong Tool

The README's own warning is the first limitation, and it is not boilerplate. IP geolocation is inherently imprecise, locations are often near the center of the population, and the data should not be used to identify a particular address or household. Any feature that depends on street-level or household-level accuracy, such as confirming a billing address or enforcing a physical boundary, is built on data that cannot support it.

The second limitation is the database method coupling. The method you call has to match the database file you opened. Calling city() on an Anonymous IP database is a mismatch, and the library will not paper over it with partial results. In practice this means your configuration has to carry both the file path and the record type, and a deployment that swaps one file for another without updating the call site fails at lookup time rather than at startup.

The third is licence, not code. The library is Apache-2.0, but the data files are not. The README does not reproduce the database licence terms, and they differ between GeoIP and GeoLite products. If you plan to redistribute an mmdb file inside a container image or a shipped product, the licence of that file is the thing to read, and this repository does not answer it.

Alternatives and the Difference in Approach

The most direct alternative is calling the GeoIP2 web service directly over HTTP with your own client, skipping this package. The difference is that you lose the typed model classes and the automatic exception mapping for not-found and corrupt-database cases, and you take on parsing the response shape yourself. GeoIP2-php exists to remove that work, and it also covers the database path, which a raw HTTP client does not.

A second alternative is a different language binding against the same MMDB format, such as the Python or Go readers. Those read the same files and return the same conceptual records. The difference is operational, not semantic: if your stack is PHP, adding another runtime just to read an mmdb file adds a service boundary, a deploy target, and a failure mode. The data is identical; only the process hosting the lookup changes.

A third path is a hosted geolocation API from a different vendor that returns its own schema. That removes the file management problem entirely, but it also removes the offline property and puts a third party in the request path. The trade is control and latency against operational simplicity.

Maintenance, Upgrade Cost, and Licence Boundaries

The repository is not archived, and the last push was on 2026-09-28. Recent releases are v3.4.0 on 2026-07-16, v3.3.0 on 2025-11-20, and v3.2.0 on 2025-05-05. That cadence suggests the v3 line is stable rather than churning, which is what you want from a library that sits in a request path.

Upgrade cost is mostly the Composer constraint. The README's example pins ^3.4.0, so moving within the v3 series is a version bump plus a test run. The repository carries a CHANGELOG.md, which is where breaking changes between minor versions would be recorded, and that is the file to read before bumping. The presence of phpstan.neon and a php-cs-fixer config in the tree indicates static analysis and style checks run against the source, which raises confidence that the public API surface is deliberate.

On licensing: the package itself is Apache-2.0. The databases and web services are separate products with their own terms, and this repository does not state them. That is a question for MaxMind's product documentation, not for this codebase, and it is worth resolving before you bake an mmdb file into a distributed artifact.

Editorial conclusion

Adopt GeoIP2-php if you are running PHP and need country, city, or connection-type data from a MaxMind MMDB file or web service, and you accept that locations are approximate. Do not adopt it if you need household-level precision, or if you cannot take on the licence terms of the data file you plan to ship. Before writing code, confirm which MMDB file you actually have, because the method name on the Reader has to match the database type, and a mismatched file throws rather than returning partial data.

Frequently asked questions

What is GeoIP2-php and how does it work?

It is MaxMind's PHP API for the GeoIP and GeoLite web services and databases. For database lookups you construct a \GeoIp2\Database\Reader with the path to an mmdb file, then call the method matching that database, such as city() or country().

Is using GeoIP2-php legal?

The package is Apache-2.0, but the databases and web services are separate products with their own terms, and the README does not state them. Resolve the data licence with MaxMind before redistributing an mmdb file.

What is the difference between GeoIP2-php and GPS?

GeoIP2-php maps an IP address to an approximate location derived from MaxMind's data, not from a device reporting its own position. The README warns that locations are often near the center of the population and should not be used to identify a particular address or household.

Which GeoIP database should I load with GeoIP2-php?

It depends on the fields you need, and the method you call must match the file. The README shows city(), anonymousIp(), anonymousPlus(), connectionType(), domain(), and enterprise() as separate methods for separate databases, and a mismatched file throws an InvalidDatabaseException.

Official sources

  1. License: Apache-2.0
  2. maxmind/GeoIP2-php on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/maxmind-geoip2-php.svg)](https://hysenlabs.com/projects/maxmind-geoip2-php)