MDL-86348 libraries: Upgrade GeoIP2 and Maxmind DB Reader
- GeoIP2 PHP API 3.2.0 - MaxMind DB Reader API 1.12.1
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.2.0 (2025-05-05)
|
||||
------------------
|
||||
|
||||
* Support for the GeoIP Anonymous Plus database has been added. To do a
|
||||
lookup in this database, use the `anonymousPlus` method on
|
||||
`GeoIP2\Database\Reader`.
|
||||
* `metroCode` on `GeoIp2\Record\Location` has been deprecated. The code
|
||||
values are no longer being maintained.
|
||||
|
||||
3.1.0 (2024-11-15)
|
||||
------------------
|
||||
|
||||
@@ -15,7 +24,7 @@ CHANGELOG
|
||||
* IMPORTANT: PHP 8.1 or greater is now required.
|
||||
* BREAKING: Read-only properties are now used for the model and record
|
||||
classes rather than magic methods. This significantly improves performance.
|
||||
* BREAKING: The `raw` property on model classess and the `record` property on
|
||||
* BREAKING: The `raw` property on model classes and the `record` property on
|
||||
record classes have been removed.
|
||||
* BREAKING: On `GeoIp2\Record\Traits`, the deprecated `isAnonymousProxy` and
|
||||
`isSatelliteProvider` properties have been removed.
|
||||
|
||||
@@ -162,6 +162,28 @@ print($record->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### Anonymous Plus Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$anonymousDbReader = new Reader('/usr/local/share/GeoIP/GeoIP-Anonymous-Plus.mmdb');
|
||||
|
||||
$record = $anonymousDbReader->anonymousIp('203.0.113.0');
|
||||
|
||||
print($record->anonymizerConfidence . "\n"); // 30
|
||||
print($record->networkLastSeen . "\n"); // '2025-04-14'
|
||||
print($record->providerName . "\n"); // 'FooBar VPN'
|
||||
|
||||
print($record->ipAddress . "\n"); // '203.0.113.0'
|
||||
print($record->network . "\n"); // '203.0.113.0/32'
|
||||
|
||||
```
|
||||
|
||||
### Connection-Type Example ###
|
||||
|
||||
```php
|
||||
@@ -443,6 +465,6 @@ The GeoIP2 PHP API uses [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## Copyright and License ##
|
||||
|
||||
This software is Copyright (c) 2013-2024 by MaxMind, Inc.
|
||||
This software is Copyright (c) 2013-2025 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"maxmind-db/reader": "^1.12.0",
|
||||
"maxmind-db/reader": "^1.12.1",
|
||||
"maxmind/web-service-common": "~0.10",
|
||||
"php": ">=8.1",
|
||||
"ext-json": "*"
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace GeoIp2\Database;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
use GeoIp2\Model\AnonymousIp;
|
||||
use GeoIp2\Model\AnonymousPlus;
|
||||
use GeoIp2\Model\Asn;
|
||||
use GeoIp2\Model\City;
|
||||
use GeoIp2\Model\ConnectionType;
|
||||
@@ -44,14 +45,8 @@ use MaxMind\Db\Reader\Metadata;
|
||||
*/
|
||||
class Reader implements ProviderInterface
|
||||
{
|
||||
private DbReader $dbReader;
|
||||
|
||||
private string $dbType;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private array $locales;
|
||||
private readonly DbReader $dbReader;
|
||||
private readonly string $dbType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -64,11 +59,11 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function __construct(
|
||||
string $filename,
|
||||
array $locales = ['en']
|
||||
/** @var array<string> */
|
||||
public readonly array $locales = ['en']
|
||||
) {
|
||||
$this->dbReader = new DbReader($filename);
|
||||
$this->dbType = $this->dbReader->metadata()->databaseType;
|
||||
$this->locales = $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +73,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function city(string $ipAddress): City
|
||||
{
|
||||
@@ -91,6 +87,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function country(string $ipAddress): Country
|
||||
{
|
||||
@@ -104,6 +101,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function anonymousIp(string $ipAddress): AnonymousIp
|
||||
{
|
||||
@@ -114,6 +112,24 @@ class Reader implements ProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoIP Anonymous Plus model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function anonymousPlus(string $ipAddress): AnonymousPlus
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
AnonymousPlus::class,
|
||||
'GeoIP-Anonymous-Plus',
|
||||
$ipAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a GeoLite2 ASN model.
|
||||
*
|
||||
@@ -121,6 +137,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function asn(string $ipAddress): Asn
|
||||
{
|
||||
@@ -138,6 +155,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function connectionType(string $ipAddress): ConnectionType
|
||||
{
|
||||
@@ -155,6 +173,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function domain(string $ipAddress): Domain
|
||||
{
|
||||
@@ -172,6 +191,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function enterprise(string $ipAddress): Enterprise
|
||||
{
|
||||
@@ -185,6 +205,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @throws AddressNotFoundException if the address is not in the database
|
||||
* @throws InvalidDatabaseException if the database is corrupt or invalid
|
||||
* @throws \BadMethodCallException if this database type is not supported
|
||||
*/
|
||||
public function isp(string $ipAddress): Isp
|
||||
{
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP Anonymous Plus model.
|
||||
*/
|
||||
class AnonymousPlus extends AnonymousIp
|
||||
{
|
||||
/**
|
||||
* @var int|null a score ranging from 1 to 99 that is our percent
|
||||
* confidence that the network is currently part of
|
||||
* an actively used VPN service
|
||||
*/
|
||||
public readonly ?int $anonymizerConfidence;
|
||||
|
||||
/**
|
||||
* @var string|null The last day that the network was sighted in our
|
||||
* analysis of anonymized networks. This is in the ISO
|
||||
* 8601 date format, e.g., "2025-04-21".
|
||||
*/
|
||||
public readonly ?string $networkLastSeen;
|
||||
|
||||
/**
|
||||
* @var string|null The name of the VPN provider (e.g., NordVPN,
|
||||
* SurfShark, etc.) associated with the network.
|
||||
*/
|
||||
public readonly ?string $providerName;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param array<string, mixed> $raw
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->anonymizerConfidence = $raw['anonymizer_confidence'] ?? null;
|
||||
$this->networkLastSeen = $raw['network_last_seen'] ?? null;
|
||||
$this->providerName = $raw['provider_name'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = parent::jsonSerialize();
|
||||
|
||||
if ($this->anonymizerConfidence !== null) {
|
||||
$js['anonymizer_confidence'] = $this->anonymizerConfidence;
|
||||
}
|
||||
|
||||
if ($this->networkLastSeen !== null) {
|
||||
$js['network_last_seen'] = $this->networkLastSeen;
|
||||
}
|
||||
|
||||
if ($this->providerName !== null) {
|
||||
$js['provider_name'] = $this->providerName;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,8 @@ class Asn implements \JsonSerializable
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
$this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null;
|
||||
$this->autonomousSystemOrganization =
|
||||
$raw['autonomous_system_organization'] ?? null;
|
||||
$this->autonomousSystemOrganization
|
||||
= $raw['autonomous_system_organization'] ?? null;
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
|
||||
@@ -43,18 +43,18 @@ class City extends Country
|
||||
public readonly Postal $postal;
|
||||
|
||||
/**
|
||||
* @var array<\GeoIp2\Record\Subdivision> An array of \GeoIp2\Record\Subdivision
|
||||
* objects representing the country
|
||||
* subdivisions for the requested IP
|
||||
* address. The number and type of
|
||||
* subdivisions varies by country,
|
||||
* but a subdivision is typically a
|
||||
* state, province, county, etc.
|
||||
* Subdivisions are ordered from most
|
||||
* general (largest) to most specific
|
||||
* (smallest). If the response did
|
||||
* not contain any subdivisions, this
|
||||
* method returns an empty array.
|
||||
* @var array<Subdivision> An array of \GeoIp2\Record\Subdivision
|
||||
* objects representing the country
|
||||
* subdivisions for the requested IP
|
||||
* address. The number and type of
|
||||
* subdivisions varies by country,
|
||||
* but a subdivision is typically a
|
||||
* state, province, county, etc.
|
||||
* Subdivisions are ordered from most
|
||||
* general (largest) to most specific
|
||||
* (smallest). If the response did
|
||||
* not contain any subdivisions, this
|
||||
* method returns an empty array.
|
||||
*/
|
||||
public readonly array $subdivisions;
|
||||
|
||||
@@ -74,22 +74,22 @@ class City extends Country
|
||||
|
||||
if (!isset($raw['subdivisions'])) {
|
||||
$this->subdivisions = [];
|
||||
$this->mostSpecificSubdivision =
|
||||
new Subdivision([], $locales);
|
||||
$this->mostSpecificSubdivision
|
||||
= new Subdivision([], $locales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$subdivisions = [];
|
||||
foreach ($raw['subdivisions'] as $sub) {
|
||||
$subdivisions[] =
|
||||
new Subdivision($sub, $locales)
|
||||
$subdivisions[]
|
||||
= new Subdivision($sub, $locales)
|
||||
;
|
||||
}
|
||||
|
||||
// Not using end as we don't want to modify internal pointer.
|
||||
$this->mostSpecificSubdivision =
|
||||
$subdivisions[\count($subdivisions) - 1];
|
||||
$this->mostSpecificSubdivision
|
||||
= $subdivisions[\count($subdivisions) - 1];
|
||||
$this->subdivisions = $subdivisions;
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ class City extends Country
|
||||
$js['location'] = $location;
|
||||
}
|
||||
|
||||
$postal =
|
||||
$this->postal->jsonSerialize();
|
||||
$postal
|
||||
= $this->postal->jsonSerialize();
|
||||
if (!empty($postal)) {
|
||||
$js['postal'] = $postal;
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ class Isp implements \JsonSerializable
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
$this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null;
|
||||
$this->autonomousSystemOrganization =
|
||||
$raw['autonomous_system_organization'] ?? null;
|
||||
$this->autonomousSystemOrganization
|
||||
= $raw['autonomous_system_organization'] ?? null;
|
||||
$this->isp = $raw['isp'] ?? null;
|
||||
$this->mobileCountryCode = $raw['mobile_country_code'] ?? null;
|
||||
$this->mobileNetworkCode = $raw['mobile_network_code'] ?? null;
|
||||
|
||||
@@ -43,10 +43,10 @@ class Location implements \JsonSerializable
|
||||
public readonly ?float $longitude;
|
||||
|
||||
/**
|
||||
* @var int|null The metro code of the location if the location
|
||||
* is in the US. MaxMind returns the same metro codes as the
|
||||
* Google AdWords API. See
|
||||
* https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions.
|
||||
* @var int|null the metro code is a no-longer-maintained code for targeting
|
||||
* advertisements in Google
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public readonly ?int $metroCode;
|
||||
|
||||
|
||||
@@ -51,14 +51,10 @@ use MaxMind\WebService\Client as WsClient;
|
||||
*/
|
||||
class Client implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private array $locales;
|
||||
private WsClient $client;
|
||||
private readonly WsClient $client;
|
||||
private static string $basePath = '/geoip/v2.1';
|
||||
|
||||
public const VERSION = 'v3.1.0';
|
||||
public const VERSION = 'v3.2.0';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -86,11 +82,10 @@ class Client implements ProviderInterface
|
||||
public function __construct(
|
||||
int $accountId,
|
||||
string $licenseKey,
|
||||
array $locales = ['en'],
|
||||
/** @var list<string> */
|
||||
public readonly array $locales = ['en'], // Promoted and readonly
|
||||
array $options = []
|
||||
) {
|
||||
$this->locales = $locales;
|
||||
|
||||
// This is for backwards compatibility. Do not remove except for a
|
||||
// major version bump.
|
||||
// @phpstan-ignore-next-line
|
||||
@@ -98,9 +93,7 @@ class Client implements ProviderInterface
|
||||
$options = ['host' => $options];
|
||||
}
|
||||
|
||||
if (!isset($options['host'])) {
|
||||
$options['host'] = 'geoip.maxmind.com';
|
||||
}
|
||||
$options['host'] ??= 'geoip.maxmind.com';
|
||||
|
||||
$options['userAgent'] = $this->userAgent();
|
||||
|
||||
@@ -139,7 +132,6 @@ class Client implements ProviderInterface
|
||||
*/
|
||||
public function city(string $ipAddress = 'me'): City
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->responseFor('city', City::class, $ipAddress);
|
||||
}
|
||||
|
||||
@@ -201,11 +193,29 @@ class Client implements ProviderInterface
|
||||
*/
|
||||
public function insights(string $ipAddress = 'me'): Insights
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->responseFor('insights', Insights::class, $ipAddress);
|
||||
}
|
||||
|
||||
private function responseFor(string $endpoint, string $class, string $ipAddress): Country
|
||||
/**
|
||||
* Generic helper method to call an endpoint and return the corresponding model.
|
||||
*
|
||||
* @template TModel of City|Country|Insights
|
||||
*
|
||||
* @param 'city'|'country'|'insights' $endpoint the endpoint name
|
||||
* @param class-string<TModel> $class The specific model class string (e.g., City::class)
|
||||
* @param string $ipAddress the IP address or 'me'
|
||||
*
|
||||
* @throws AddressNotFoundException
|
||||
* @throws AuthenticationException
|
||||
* @throws OutOfQueriesException
|
||||
* @throws InvalidRequestException
|
||||
* @throws HttpException
|
||||
* @throws GeoIp2Exception
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return TModel the corresponding model object, matching the passed class string
|
||||
*/
|
||||
private function responseFor(string $endpoint, string $class, string $ipAddress): City|Country|Insights
|
||||
{
|
||||
if ($ipAddress !== 'me' && !filter_var($ipAddress, \FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
1.12.1 (2025-05-05)
|
||||
-------------------
|
||||
|
||||
* The C extension now checks that the database metadata lookup was
|
||||
successful.
|
||||
|
||||
1.12.0 (2024-11-14)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -180,6 +180,6 @@ The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## Copyright and License ##
|
||||
|
||||
This software is Copyright (c) 2014-2024 by MaxMind, Inc.
|
||||
This software is Copyright (c) 2014-2025 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
||||
|
||||
@@ -356,8 +356,8 @@ class Reader
|
||||
}
|
||||
|
||||
throw new InvalidDatabaseException(
|
||||
"Error opening database file ($filename). " .
|
||||
'Is this a valid MaxMind DB file?'
|
||||
"Error opening database file ($filename). "
|
||||
. 'Is this a valid MaxMind DB file?'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,10 +106,10 @@ class Metadata
|
||||
);
|
||||
}
|
||||
|
||||
$this->binaryFormatMajorVersion =
|
||||
$metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion =
|
||||
$metadata['binary_format_minor_version'];
|
||||
$this->binaryFormatMajorVersion
|
||||
= $metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion
|
||||
= $metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
|
||||
@@ -416,7 +416,7 @@ All rights reserved.</copyright>
|
||||
<location>maxmind/GeoIp2</location>
|
||||
<name>GeoIP2 PHP API</name>
|
||||
<description>Library for processing of GeoIP data files.</description>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.0</version>
|
||||
<license>Apache</license>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
<repository>https://github.com/maxmind/GeoIP2-php</repository>
|
||||
@@ -428,7 +428,7 @@ All rights reserved.</copyright>
|
||||
<location>maxmind/MaxMind</location>
|
||||
<name>MaxMind DB Reader API</name>
|
||||
<description>PHP API for reading MaxMind DB files.</description>
|
||||
<version>1.12.0</version>
|
||||
<version>1.12.1</version>
|
||||
<license>Apache</license>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
<repository>https://github.com/maxmind/MaxMind-DB-Reader-php/</repository>
|
||||
|
||||
Reference in New Issue
Block a user