mirror of
https://github.com/moodle/moodle.git
synced 2025-04-22 08:55:15 +02:00
MDL-80635 libraries: Upgrade GeoIP2 and Maxmind DB Reader
- GeoIP2 PHP API 3.0.0 - MaxMind DB Reader API 1.11.1 Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
This commit is contained in:
parent
f49d120761
commit
ab7a137afa
344
lib/maxmind/GeoIp2/CHANGELOG.md
Normal file
344
lib/maxmind/GeoIp2/CHANGELOG.md
Normal file
@ -0,0 +1,344 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.0.0 (2023-12-04)
|
||||
------------------
|
||||
|
||||
* 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
|
||||
record classes have been removed.
|
||||
* BREAKING: On `GeoIp2\Record\Traits`, the deprecated `isAnonymousProxy` and
|
||||
`isSatelliteProvider` properties have been removed.
|
||||
* BREAKING: The `jsonSerialize` output has changed.
|
||||
* `GeoIp2\WebService\Client` methods now throw an `InvalidArgumentException`
|
||||
if an invalid IP address is passed to them. Previously, they would make
|
||||
a request to the web service and throw a
|
||||
`GeoIp2\Exception\InvalidRequestException`.
|
||||
* The `isAnycast` property was added to `GeoIp2\Record\Traits`. This returns
|
||||
`true` if the IP address belongs to an [anycast
|
||||
network](https://en.wikipedia.org/wiki/Anycast). This is available for the
|
||||
GeoIP2 Country, City Plus, and Insights web services and the GeoIP2 Country,
|
||||
City, and Enterprise databases.
|
||||
|
||||
2.13.0 (2022-08-05)
|
||||
-------------------
|
||||
|
||||
* The model class names are no longer constructed by concatenating strings.
|
||||
This change was made to improve support for tools like PHP-Scoper.
|
||||
Reported by Andrew Mead. GitHub #194.
|
||||
* Box 4.0.1 is now used to generate the `geoip2.phar` file.
|
||||
|
||||
2.12.2 (2021-11-30)
|
||||
-------------------
|
||||
|
||||
* The `geoip2.phar` now works when included from another directory.
|
||||
Reported by Eduardo Ruiz. GitHub #179.
|
||||
|
||||
2.12.1 (2021-11-23)
|
||||
-------------------
|
||||
|
||||
* The `geoip2.phar` included in 2.12.0 would only work in CLI applications.
|
||||
This was due to a change in Box 3.x. The Phar should now work in all
|
||||
applications. This release only affects users of the Phar file.
|
||||
|
||||
2.12.0 (2021-11-18)
|
||||
-------------------
|
||||
|
||||
* Support for mobile country code (MCC) and mobile network codes (MNC) was
|
||||
added for the GeoIP2 ISP and Enterprise databases as well as the GeoIP2
|
||||
City and Insights web services. `$mobileCountryCode` and
|
||||
`$mobileNetworkCode` properties were added to `GeoIp2\Model\Isp`
|
||||
for the GeoIP2 ISP database and `GeoIp2\Record\Traits` for the Enterprise
|
||||
database and the GeoIP2 City and Insights web services. We expect this data
|
||||
to be available by late January, 2022.
|
||||
* `geoip2.phar` is now generated with Box 3.x.
|
||||
|
||||
2.11.0 (2020-10-01)
|
||||
-------------------
|
||||
|
||||
* IMPORTANT: PHP 7.2 or greater is now required.
|
||||
* Added the `isResidentialProxy` property to `GeoIp2\Model\AnonymousIP` and
|
||||
`GeoIp2\Record\Traits`.
|
||||
* Additional type hints have been added.
|
||||
|
||||
2.10.0 (2019-12-12)
|
||||
-------------------
|
||||
|
||||
* PHP 5.6 or greater is now required.
|
||||
* The `network` property was added to `GeoIp2\Record\Traits`,
|
||||
`GeoIp2\Model\AnonymousIp`, `GeoIp2\Model\Asn`,
|
||||
`GeoIp2\Model\ConnectionType`, `Geoip2\Model\Domain`,
|
||||
and `GeoIp2\Model\Isp`. This is a string in CIDR format representing the
|
||||
largest network where all of the properties besides `ipAddress` have the
|
||||
same value.
|
||||
* Updated documentation of anonymizer properties - `isAnonymousVpn`
|
||||
and `isHostingProvider` - to be more descriptive.
|
||||
* The `userCount` property was added to `GeoIp2\Record\Traits`. This is an
|
||||
integer which indicates the estimated number of users sharing the
|
||||
IP/network during the past 24 hours. This output is available from GeoIP2
|
||||
Precision Insights.
|
||||
* The `staticIpScore` property was added to `GeoIp2\Record\Traits`. This is
|
||||
a float which indicates how static or dynamic an IP address is. This
|
||||
output is available from GeoIP2 Precision Insights.
|
||||
|
||||
2.9.0 (2018-04-10)
|
||||
------------------
|
||||
|
||||
* Refer to account IDs using the terminology "account" rather than "user".
|
||||
|
||||
2.8.0 (2018-01-18)
|
||||
------------------
|
||||
|
||||
* The `isInEuropeanUnion` property was added to `GeoIp2\Record\Country`
|
||||
and `GeoIp2\Record\RepresentedCountry`. This property is `true` if the
|
||||
country is a member state of the European Union.
|
||||
|
||||
2.7.0 (2017-10-27)
|
||||
------------------
|
||||
|
||||
* The following new anonymizer properties were added to `GeoIp2\Record\Traits`
|
||||
for use with GeoIP2 Precision Insights: `isAnonymous`, `isAnonymousVpn`,
|
||||
`isHostingProvider`, `isPublicProxy`, and `isTorExitNode`.
|
||||
|
||||
2.6.0 (2017-07-10)
|
||||
-----------------
|
||||
|
||||
* Code clean-up and tidying.
|
||||
* Set minimum required PHP version to 5.4 in `composer.json`. Previously,
|
||||
5.3 would work but was not tested. Now 5.4 is hard minimum version.
|
||||
|
||||
2.5.0 (2017-05-08)
|
||||
------------------
|
||||
|
||||
* Support for PHP 5.3 was dropped.
|
||||
* Added support for GeoLite2 ASN database.
|
||||
|
||||
2.4.5 (2017-01-31)
|
||||
------------------
|
||||
|
||||
* Additional error checking on the data returned from `MaxMind\Db\Reader`
|
||||
was added to help detect corrupt databases. GitHub #83.
|
||||
|
||||
2.4.4 (2016-10-11)
|
||||
------------------
|
||||
|
||||
* `isset()` on `mostSpecificSubdivision` attribute now returns the
|
||||
correct value. Reported by Juan Francisco Giordana. GitHub #81.
|
||||
|
||||
2.4.3 (2016-10-11)
|
||||
------------------
|
||||
|
||||
* `isset()` on `name` attribute now returns the correct value. Reported by
|
||||
Juan Francisco Giordana. GitHub #79.
|
||||
|
||||
2.4.2 (2016-08-17)
|
||||
------------------
|
||||
|
||||
* Updated documentation to clarify what the accuracy radius refers to.
|
||||
* Upgraded `maxmind/web-service-common` to 0.3.0. This version uses
|
||||
`composer/ca-bundle` rather than our own CA bundle. GitHub #75.
|
||||
* Improved PHP documentation generation.
|
||||
|
||||
2.4.1 (2016-06-10)
|
||||
------------------
|
||||
|
||||
* Corrected type annotations in documentation. GitHub #66.
|
||||
* Updated documentation to reflect that the accuracy radius is now included
|
||||
in City.
|
||||
* Upgraded web service client, which supports setting a proxy. GitHub #59.
|
||||
|
||||
2.4.0 (2016-04-15)
|
||||
------------------
|
||||
|
||||
* Added support for the GeoIP2 Enterprise database.
|
||||
|
||||
2.3.3 (2015-09-24)
|
||||
------------------
|
||||
|
||||
* Corrected case on `JsonSerializable` interface. Reported by Axel Etcheverry.
|
||||
GitHub #56.
|
||||
|
||||
2.3.2 (2015-09-23)
|
||||
------------------
|
||||
|
||||
* `JsonSerializable` compatibility interface was moved to `GeoIp2\Compat`
|
||||
rather than the global namespace to prevent autoloading issues. Reported by
|
||||
Tomas Buteler. GitHub #54.
|
||||
* Missing documentation for the `$postal` property was added to the
|
||||
`GeoIp2\Model\City` class. Fix by Roy Sindre Norangshol. GitHub #51.
|
||||
* In the Phar distribution, source files for this module no longer have their
|
||||
documentation stripped, allowing IDE introspection to work properly.
|
||||
Reported by Dominic Black. GitHub #52.
|
||||
|
||||
2.3.1 (2015-06-30)
|
||||
------------------
|
||||
|
||||
* Updated `maxmind/web-service-common` to version with fixes for PHP 5.3 and
|
||||
5.4.
|
||||
|
||||
2.3.0 (2015-06-29)
|
||||
------------------
|
||||
|
||||
* Support for demographics fields `averageIncome` and `populationDensity` in
|
||||
the `Location` record, returned by the Insights endpoint.
|
||||
* The `isAnonymousProxy` and `isSatelliteProvider` properties on
|
||||
`GeoIP2\Record\Traits` have been deprecated. Please use our [GeoIP2
|
||||
Anonymous IP database](https://www.maxmind.com/en/geoip2-anonymous-ip-database)
|
||||
to determine whether an IP address is used by an anonymizing service.
|
||||
|
||||
2.2.0-beta1 (2015-06-09)
|
||||
------------------------
|
||||
|
||||
* Typo fix in documentation.
|
||||
|
||||
2.2.0-alpha2 (2015-06-01)
|
||||
-------------------------
|
||||
|
||||
* `maxmind-ws/web-service-common` was renamed to `maxmind/web-service-common`.
|
||||
|
||||
2.2.0-alpha1 (2015-05-22)
|
||||
-------------------------
|
||||
|
||||
* The library no longer uses Guzzle and instead uses curl directly.
|
||||
* Support for `timeout` and `connectTimout` were added to the `$options` array
|
||||
passed to the `GeoIp2\WebService\Client` constructor. Pull request by Will
|
||||
Bradley. GitHub #36.
|
||||
|
||||
2.1.1 (2014-12-03)
|
||||
------------------
|
||||
|
||||
* The 2.1.0 Phar builds included a shebang line, causing issues when loading
|
||||
it as a library. This has been corrected. GitHub #33.
|
||||
|
||||
2.1.0 (2014-10-29)
|
||||
------------------
|
||||
|
||||
* Update ApiGen dependency to version that isn't broken on case sensitive
|
||||
file systems.
|
||||
* Added support for the GeoIP2 Anonymous IP database. The
|
||||
`GeoIP2\Database\Reader` class now has an `anonymousIp` method which returns
|
||||
a `GeoIP2\Model\AnonymousIp` object.
|
||||
* Boolean attributes like those in the `GeoIP2\Record\Traits` class now return
|
||||
`false` instead of `null` when they were not true.
|
||||
|
||||
2.0.0 (2014-09-22)
|
||||
------------------
|
||||
|
||||
* First production release.
|
||||
|
||||
0.9.0 (2014-09-15)
|
||||
------------------
|
||||
|
||||
* IMPORTANT: The deprecated `omni()` and `cityIspOrg()` methods have been
|
||||
removed from `GeoIp2\WebService\Client`.
|
||||
|
||||
0.8.1 (2014-09-12)
|
||||
------------------
|
||||
|
||||
* The check added to the `GeoIP2\Database\Reader` lookup methods in 0.8.0 did
|
||||
not work with the GeoIP2 City Database Subset by Continent with World
|
||||
Countries. This has been fixed. Fixes GitHub issue #23.
|
||||
|
||||
0.8.0 (2014-09-10)
|
||||
------------------
|
||||
|
||||
* The `GeoIp2\Database\Reader` lookup methods (e.g., `city()`, `isp()`) now
|
||||
throw a `BadMethodCallException` if they are used with a database that
|
||||
does not match the method. In particular, doing a `city()` lookup on a
|
||||
GeoIP2 Country database will result in an exception, and vice versa.
|
||||
* A `metadata()` method has been added to the `GeoIP2\Database\Reader` class.
|
||||
This returns a `MaxMind\Db\Reader\Metadata` class with information about the
|
||||
database.
|
||||
* The name attribute was missing from the RepresentedCountry class.
|
||||
|
||||
0.7.0 (2014-07-22)
|
||||
------------------
|
||||
|
||||
* The web service client API has been updated for the v2.1 release of the web
|
||||
service. In particular, the `cityIspOrg` and `omni` methods on
|
||||
`GeoIp2\WebService\Client` should be considered deprecated. The `city`
|
||||
method now provides all of the data formerly provided by `cityIspOrg`, and
|
||||
the `omni` method has been replaced by the `insights` method.
|
||||
* Support was added for GeoIP2 Connection Type, Domain and ISP databases.
|
||||
|
||||
|
||||
0.6.3 (2014-05-12)
|
||||
------------------
|
||||
|
||||
* With the previous Phar builds, some users received `phar error: invalid url
|
||||
or non-existent phar` errors. The correct alias is now used for the Phar,
|
||||
and this should no longer be an issue.
|
||||
|
||||
0.6.2 (2014-05-08)
|
||||
------------------
|
||||
|
||||
* The Phar build was broken with Guzzle 3.9.0+. This has been fixed.
|
||||
|
||||
0.6.1 (2014-05-01)
|
||||
------------------
|
||||
|
||||
* This API now officially supports HHVM.
|
||||
* The `maxmind-db/reader` dependency was updated to a version that does not
|
||||
require BC Math.
|
||||
* The Composer compatibility autoload rules are now targeted more narrowly.
|
||||
* A `box.json` file is included to build a Phar package.
|
||||
|
||||
0.6.0 (2014-02-19)
|
||||
------------------
|
||||
|
||||
* This API is now licensed under the Apache License, Version 2.0.
|
||||
* Model and record classes now implement `JsonSerializable`.
|
||||
* `isset` now works with model and record classes.
|
||||
|
||||
0.5.0 (2013-10-21)
|
||||
------------------
|
||||
|
||||
* Renamed $languages constructor parameters to $locales for both the Client
|
||||
and Reader classes.
|
||||
* Documentation and code clean-up (Ben Morel).
|
||||
* Added the interface `GeoIp2\ProviderInterface`, which is implemented by both
|
||||
`\GeoIp2\Database\Reader` and `\GeoIp2\WebService\Client`.
|
||||
|
||||
0.4.0 (2013-07-16)
|
||||
------------------
|
||||
|
||||
* This is the first release with the GeoIP2 database reader. Please see the
|
||||
`README.md` file and the `\GeoIp2\Database\Reader` class.
|
||||
* The general exception classes were replaced with specific exception classes
|
||||
representing particular types of errors, such as an authentication error.
|
||||
|
||||
0.3.0 (2013-07-12)
|
||||
------------------
|
||||
|
||||
* In namespaces and class names, "GeoIP2" was renamed to "GeoIp2" to improve
|
||||
consistency.
|
||||
|
||||
0.2.1 (2013-06-10)
|
||||
------------------
|
||||
|
||||
* First official beta release.
|
||||
* Documentation updates and corrections.
|
||||
|
||||
0.2.0 (2013-05-29)
|
||||
------------------
|
||||
|
||||
* `GenericException` was renamed to `GeoIP2Exception`.
|
||||
* We now support more languages. The new languages are de, es, fr, and pt-BR.
|
||||
* The REST API now returns a record with data about your account. There is
|
||||
a new `GeoIP\Records\MaxMind` class for this data.
|
||||
* The `continentCode` attribute on `Continent` was renamed to `code`.
|
||||
* Documentation updates.
|
||||
|
||||
0.1.1 (2013-05-14)
|
||||
------------------
|
||||
|
||||
* Updated Guzzle version requirement.
|
||||
* Fixed Composer example in README.md.
|
||||
|
||||
|
||||
0.1.0 (2013-05-13)
|
||||
------------------
|
||||
|
||||
* Initial release.
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace GeoIp2\Database;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
use GeoIp2\Model\AbstractModel;
|
||||
use GeoIp2\Model\AnonymousIp;
|
||||
use GeoIp2\Model\Asn;
|
||||
use GeoIp2\Model\City;
|
||||
@ -44,20 +43,14 @@ use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
*/
|
||||
class Reader implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var DbReader
|
||||
*/
|
||||
private $dbReader;
|
||||
private DbReader $dbReader;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $dbType;
|
||||
private string $dbType;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private $locales;
|
||||
private array $locales;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -90,7 +83,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function city(string $ipAddress): City
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(City::class, 'City', $ipAddress);
|
||||
}
|
||||
|
||||
@ -106,7 +98,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function country(string $ipAddress): Country
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(Country::class, 'Country', $ipAddress);
|
||||
}
|
||||
|
||||
@ -122,7 +113,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function anonymousIp(string $ipAddress): AnonymousIp
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(
|
||||
AnonymousIp::class,
|
||||
'GeoIP2-Anonymous-IP',
|
||||
@ -142,7 +132,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function asn(string $ipAddress): Asn
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(
|
||||
Asn::class,
|
||||
'GeoLite2-ASN',
|
||||
@ -162,7 +151,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function connectionType(string $ipAddress): ConnectionType
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(
|
||||
ConnectionType::class,
|
||||
'GeoIP2-Connection-Type',
|
||||
@ -182,7 +170,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function domain(string $ipAddress): Domain
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(
|
||||
Domain::class,
|
||||
'GeoIP2-Domain',
|
||||
@ -202,7 +189,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function enterprise(string $ipAddress): Enterprise
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress);
|
||||
}
|
||||
|
||||
@ -218,7 +204,6 @@ class Reader implements ProviderInterface
|
||||
*/
|
||||
public function isp(string $ipAddress): Isp
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(
|
||||
Isp::class,
|
||||
'GeoIP2-ISP',
|
||||
@ -226,7 +211,7 @@ class Reader implements ProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
private function modelFor(string $class, string $type, string $ipAddress): AbstractModel
|
||||
private function modelFor(string $class, string $type, string $ipAddress): object
|
||||
{
|
||||
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
@ -236,7 +221,7 @@ class Reader implements ProviderInterface
|
||||
return new $class($record, $this->locales);
|
||||
}
|
||||
|
||||
private function flatModelFor(string $class, string $type, string $ipAddress): AbstractModel
|
||||
private function flatModelFor(string $class, string $type, string $ipAddress): object
|
||||
{
|
||||
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
@ -248,7 +233,7 @@ class Reader implements ProviderInterface
|
||||
|
||||
private function getRecord(string $class, string $type, string $ipAddress): array
|
||||
{
|
||||
if (strpos($this->dbType, $type) === false) {
|
||||
if (!str_contains($this->dbType, $type)) {
|
||||
$method = lcfirst((new \ReflectionClass($class))->getShortName());
|
||||
|
||||
throw new \BadMethodCallException(
|
||||
|
@ -7,6 +7,5 @@ namespace GeoIp2\Exception;
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AddressNotFoundException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class AddressNotFoundException extends GeoIp2Exception {}
|
||||
|
@ -7,6 +7,5 @@ namespace GeoIp2\Exception;
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AuthenticationException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class AuthenticationException extends GeoIp2Exception {}
|
||||
|
@ -7,6 +7,5 @@ namespace GeoIp2\Exception;
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class GeoIp2Exception extends \Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class GeoIp2Exception extends \Exception {}
|
||||
|
@ -11,10 +11,8 @@ class HttpException extends GeoIp2Exception
|
||||
{
|
||||
/**
|
||||
* The URI queried.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $uri;
|
||||
public string $uri;
|
||||
|
||||
public function __construct(
|
||||
string $message,
|
||||
|
@ -12,10 +12,8 @@ class InvalidRequestException extends HttpException
|
||||
{
|
||||
/**
|
||||
* The code returned by the MaxMind web service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $error;
|
||||
public string $error;
|
||||
|
||||
public function __construct(
|
||||
string $message,
|
||||
|
@ -7,6 +7,5 @@ namespace GeoIp2\Exception;
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class OutOfQueriesException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class OutOfQueriesException extends GeoIp2Exception {}
|
||||
|
202
lib/maxmind/GeoIp2/LICENSE
Normal file
202
lib/maxmind/GeoIp2/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
abstract class AbstractModel implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected $raw;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
$this->raw = $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get(string $field)
|
||||
{
|
||||
if (isset($this->raw[$field])) {
|
||||
return $this->raw[$field];
|
||||
}
|
||||
if (preg_match('/^is_/', $field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr !== 'instance' && property_exists($this, $attr)) {
|
||||
return $this->{$attr};
|
||||
}
|
||||
|
||||
throw new \RuntimeException("Unknown attribute: $attr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
return $attr !== 'instance' && isset($this->{$attr});
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->raw;
|
||||
}
|
||||
}
|
@ -8,84 +8,100 @@ use GeoIp2\Util;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Anonymous IP model.
|
||||
*
|
||||
* @property-read bool $isAnonymous This is true if the IP address belongs to
|
||||
* any sort of anonymous network.
|
||||
* @property-read bool $isAnonymousVpn This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not
|
||||
* register subnets under names associated with them, we will likely only
|
||||
* flag their IP ranges using the isHostingProvider property.
|
||||
* @property-read bool $isHostingProvider This is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property).
|
||||
* @property-read bool $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy.
|
||||
* @property-read bool $isResidentialProxy This is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP.
|
||||
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
|
||||
* exit node.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class AnonymousIp extends AbstractModel
|
||||
class AnonymousIp implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool this is true if the IP address belongs to
|
||||
* any sort of anonymous network
|
||||
*/
|
||||
protected $isAnonymous;
|
||||
public readonly bool $isAnonymous;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not
|
||||
* register subnets under names associated with them, we will likely only
|
||||
* flag their IP ranges using the isHostingProvider property.
|
||||
*/
|
||||
protected $isAnonymousVpn;
|
||||
public readonly bool $isAnonymousVpn;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool this is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property)
|
||||
*/
|
||||
protected $isHostingProvider;
|
||||
public readonly bool $isHostingProvider;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool this is true if the IP address belongs to
|
||||
* a public proxy
|
||||
*/
|
||||
protected $isPublicProxy;
|
||||
public readonly bool $isPublicProxy;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool this is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP
|
||||
*/
|
||||
protected $isResidentialProxy;
|
||||
public readonly bool $isResidentialProxy;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var bool this is true if the IP address is a Tor
|
||||
* exit node
|
||||
*/
|
||||
protected $isTorExitNode;
|
||||
public readonly bool $isTorExitNode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string the IP address that the data in the model is
|
||||
* for
|
||||
*/
|
||||
protected $ipAddress;
|
||||
public readonly string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
protected $network;
|
||||
public readonly string $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->isAnonymous = $this->get('is_anonymous');
|
||||
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
|
||||
$this->isHostingProvider = $this->get('is_hosting_provider');
|
||||
$this->isPublicProxy = $this->get('is_public_proxy');
|
||||
$this->isResidentialProxy = $this->get('is_residential_proxy');
|
||||
$this->isTorExitNode = $this->get('is_tor_exit_node');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->isAnonymous = $raw['is_anonymous'] ?? false;
|
||||
$this->isAnonymousVpn = $raw['is_anonymous_vpn'] ?? false;
|
||||
$this->isHostingProvider = $raw['is_hosting_provider'] ?? false;
|
||||
$this->isPublicProxy = $raw['is_public_proxy'] ?? false;
|
||||
$this->isResidentialProxy = $raw['is_residential_proxy'] ?? false;
|
||||
$this->isTorExitNode = $raw['is_tor_exit_node'] ?? false;
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->isAnonymous !== null) {
|
||||
$js['is_anonymous'] = $this->isAnonymous;
|
||||
}
|
||||
if ($this->isAnonymousVpn !== null) {
|
||||
$js['is_anonymous_vpn'] = $this->isAnonymousVpn;
|
||||
}
|
||||
if ($this->isHostingProvider !== null) {
|
||||
$js['is_hosting_provider'] = $this->isHostingProvider;
|
||||
}
|
||||
if ($this->isPublicProxy !== null) {
|
||||
$js['is_public_proxy'] = $this->isPublicProxy;
|
||||
}
|
||||
if ($this->isResidentialProxy !== null) {
|
||||
$js['is_residential_proxy'] = $this->isResidentialProxy;
|
||||
}
|
||||
if ($this->isTorExitNode !== null) {
|
||||
$js['is_tor_exit_node'] = $this->isTorExitNode;
|
||||
}
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
$js['network'] = $this->network;
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,51 +8,61 @@ use GeoIp2\Util;
|
||||
|
||||
/**
|
||||
* This class provides the GeoLite2 ASN model.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Asn extends AbstractModel
|
||||
class Asn implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
* @var int|null the autonomous system number
|
||||
* associated with the IP address
|
||||
*/
|
||||
protected $autonomousSystemNumber;
|
||||
public readonly ?int $autonomousSystemNumber;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null the organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address
|
||||
*/
|
||||
protected $autonomousSystemOrganization;
|
||||
public readonly ?string $autonomousSystemOrganization;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string the IP address that the data in the model is
|
||||
* for
|
||||
*/
|
||||
protected $ipAddress;
|
||||
public readonly string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
protected $network;
|
||||
public readonly string $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
$this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null;
|
||||
$this->autonomousSystemOrganization =
|
||||
$this->get('autonomous_system_organization');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$raw['autonomous_system_organization'] ?? null;
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
|
||||
if ($this->autonomousSystemNumber !== null) {
|
||||
$js['autonomous_system_number'] = $this->autonomousSystemNumber;
|
||||
}
|
||||
if ($this->autonomousSystemOrganization !== null) {
|
||||
$js['autonomous_system_organization'] = $this->autonomousSystemOrganization;
|
||||
}
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
$js['network'] = $this->network;
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -10,54 +10,45 @@ namespace GeoIp2\Model;
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more
|
||||
* details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\City $city City data for the requested IP
|
||||
* address.
|
||||
* @property-read \GeoIp2\Record\Location $location Location data for the
|
||||
* requested IP address.
|
||||
* @property-read \GeoIp2\Record\Postal $postal Postal data for the
|
||||
* requested IP address.
|
||||
* @property-read array $subdivisions An array \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.
|
||||
* @property-read \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* \GeoIp2\Record\Subdivision object.
|
||||
*/
|
||||
class City extends Country
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\City
|
||||
* @var \GeoIp2\Record\City city data for the requested IP
|
||||
* address
|
||||
*/
|
||||
protected $city;
|
||||
public readonly \GeoIp2\Record\City $city;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\Location
|
||||
* @var \GeoIp2\Record\Location location data for the
|
||||
* requested IP address
|
||||
*/
|
||||
protected $location;
|
||||
public readonly \GeoIp2\Record\Location $location;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\Postal
|
||||
* @var \GeoIp2\Record\Subdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* \GeoIp2\Record\Subdivision object.
|
||||
*/
|
||||
protected $postal;
|
||||
public readonly \GeoIp2\Record\Subdivision $mostSpecificSubdivision;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<\GeoIp2\Record\Subdivision>
|
||||
* @var \GeoIp2\Record\Postal postal data for the
|
||||
* requested IP address
|
||||
*/
|
||||
protected $subdivisions = [];
|
||||
public readonly \GeoIp2\Record\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.
|
||||
*/
|
||||
public readonly array $subdivisions;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
@ -66,58 +57,59 @@ class City extends Country
|
||||
{
|
||||
parent::__construct($raw, $locales);
|
||||
|
||||
$this->city = new \GeoIp2\Record\City($this->get('city'), $locales);
|
||||
$this->location = new \GeoIp2\Record\Location($this->get('location'));
|
||||
$this->postal = new \GeoIp2\Record\Postal($this->get('postal'));
|
||||
$this->city = new \GeoIp2\Record\City($raw['city'] ?? [], $locales);
|
||||
$this->location = new \GeoIp2\Record\Location($raw['location'] ?? []);
|
||||
$this->postal = new \GeoIp2\Record\Postal($raw['postal'] ?? []);
|
||||
|
||||
$this->createSubdivisions($raw, $locales);
|
||||
}
|
||||
|
||||
private function createSubdivisions(array $raw, array $locales): void
|
||||
{
|
||||
if (!isset($raw['subdivisions'])) {
|
||||
$this->subdivisions = [];
|
||||
$this->mostSpecificSubdivision =
|
||||
new \GeoIp2\Record\Subdivision([], $locales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$subdivisions = [];
|
||||
foreach ($raw['subdivisions'] as $sub) {
|
||||
$this->subdivisions[] =
|
||||
$subdivisions[] =
|
||||
new \GeoIp2\Record\Subdivision($sub, $locales)
|
||||
;
|
||||
}
|
||||
|
||||
// Not using end as we don't want to modify internal pointer.
|
||||
$this->mostSpecificSubdivision =
|
||||
$subdivisions[\count($subdivisions) - 1];
|
||||
$this->subdivisions = $subdivisions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
return $this->{$attr}();
|
||||
$js = parent::jsonSerialize();
|
||||
|
||||
$city = $this->city->jsonSerialize();
|
||||
if (!empty($city)) {
|
||||
$js['city'] = $city;
|
||||
}
|
||||
|
||||
return parent::__get($attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
// We always return a mostSpecificSubdivision, even if it is the
|
||||
// empty subdivision
|
||||
return true;
|
||||
$location = $this->location->jsonSerialize();
|
||||
if (!empty($location)) {
|
||||
$js['location'] = $location;
|
||||
}
|
||||
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
$postal =
|
||||
$this->postal->jsonSerialize();
|
||||
if (!empty($postal)) {
|
||||
$js['postal'] = $postal;
|
||||
}
|
||||
|
||||
private function mostSpecificSubdivision(): \GeoIp2\Record\Subdivision
|
||||
{
|
||||
return empty($this->subdivisions) ?
|
||||
new \GeoIp2\Record\Subdivision([], $this->locales) :
|
||||
end($this->subdivisions);
|
||||
$subdivisions = [];
|
||||
foreach ($this->subdivisions as $sub) {
|
||||
$subdivisions[] = $sub->jsonSerialize();
|
||||
}
|
||||
if (!empty($subdivisions)) {
|
||||
$js['subdivisions'] = $subdivisions;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,43 +8,49 @@ use GeoIp2\Util;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Connection-Type model.
|
||||
*
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class ConnectionType extends AbstractModel
|
||||
class ConnectionType implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular", and
|
||||
* "Satellite". Additional values may be added in the future.
|
||||
*/
|
||||
protected $connectionType;
|
||||
public readonly ?string $connectionType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string the IP address that the data in the model is
|
||||
* for
|
||||
*/
|
||||
protected $ipAddress;
|
||||
public readonly string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
protected $network;
|
||||
public readonly string $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->connectionType = $this->get('connection_type');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->connectionType = $raw['connection_type'] ?? null;
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->connectionType !== null) {
|
||||
$js['connection_type'] = $this->connectionType;
|
||||
}
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
$js['network'] = $this->network;
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,89 +8,102 @@ namespace GeoIp2\Model;
|
||||
* Model class for the data returned by GeoIP2 Country web service and database.
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
* @property-read array $raw The raw data from the web service.
|
||||
*/
|
||||
class Country extends AbstractModel
|
||||
class Country implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var \GeoIp2\Record\Continent
|
||||
* @var \GeoIp2\Record\Continent continent data for the
|
||||
* requested IP address
|
||||
*/
|
||||
protected $continent;
|
||||
public readonly \GeoIp2\Record\Continent $continent;
|
||||
|
||||
/**
|
||||
* @var \GeoIp2\Record\Country
|
||||
* @var \GeoIp2\Record\Country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
*/
|
||||
protected $country;
|
||||
public readonly \GeoIp2\Record\Country $country;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
* @var \GeoIp2\Record\MaxMind data related to your MaxMind
|
||||
* account
|
||||
*/
|
||||
protected $locales;
|
||||
public readonly \GeoIp2\Record\MaxMind $maxmind;
|
||||
|
||||
/**
|
||||
* @var \GeoIp2\Record\MaxMind
|
||||
* @var \GeoIp2\Record\Country Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
*/
|
||||
protected $maxmind;
|
||||
public readonly \GeoIp2\Record\Country $registeredCountry;
|
||||
|
||||
/**
|
||||
* @var \GeoIp2\Record\Country
|
||||
* @var \GeoIp2\Record\RepresentedCountry * Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
*/
|
||||
protected $registeredCountry;
|
||||
public readonly \GeoIp2\Record\RepresentedCountry $representedCountry;
|
||||
|
||||
/**
|
||||
* @var \GeoIp2\Record\RepresentedCountry
|
||||
* @var \GeoIp2\Record\Traits data for the traits of the
|
||||
* requested IP address
|
||||
*/
|
||||
protected $representedCountry;
|
||||
|
||||
/**
|
||||
* @var \GeoIp2\Record\Traits
|
||||
*/
|
||||
protected $traits;
|
||||
public readonly \GeoIp2\Record\Traits $traits;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->continent = new \GeoIp2\Record\Continent(
|
||||
$this->get('continent'),
|
||||
$raw['continent'] ?? [],
|
||||
$locales
|
||||
);
|
||||
$this->country = new \GeoIp2\Record\Country(
|
||||
$this->get('country'),
|
||||
$raw['country'] ?? [],
|
||||
$locales
|
||||
);
|
||||
$this->maxmind = new \GeoIp2\Record\MaxMind($this->get('maxmind'));
|
||||
$this->maxmind = new \GeoIp2\Record\MaxMind($raw['maxmind'] ?? []);
|
||||
$this->registeredCountry = new \GeoIp2\Record\Country(
|
||||
$this->get('registered_country'),
|
||||
$raw['registered_country'] ?? [],
|
||||
$locales
|
||||
);
|
||||
$this->representedCountry = new \GeoIp2\Record\RepresentedCountry(
|
||||
$this->get('represented_country'),
|
||||
$raw['represented_country'] ?? [],
|
||||
$locales
|
||||
);
|
||||
$this->traits = new \GeoIp2\Record\Traits($this->get('traits'));
|
||||
$this->traits = new \GeoIp2\Record\Traits($raw['traits'] ?? []);
|
||||
}
|
||||
|
||||
$this->locales = $locales;
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
$continent = $this->continent->jsonSerialize();
|
||||
if (!empty($continent)) {
|
||||
$js['continent'] = $continent;
|
||||
}
|
||||
$country = $this->country->jsonSerialize();
|
||||
if (!empty($country)) {
|
||||
$js['country'] = $country;
|
||||
}
|
||||
$maxmind = $this->maxmind->jsonSerialize();
|
||||
if (!empty($maxmind)) {
|
||||
$js['maxmind'] = $maxmind;
|
||||
}
|
||||
$registeredCountry = $this->registeredCountry->jsonSerialize();
|
||||
if (!empty($registeredCountry)) {
|
||||
$js['registered_country'] = $registeredCountry;
|
||||
}
|
||||
$representedCountry = $this->representedCountry->jsonSerialize();
|
||||
if (!empty($representedCountry)) {
|
||||
$js['represented_country'] = $representedCountry;
|
||||
}
|
||||
$traits = $this->traits->jsonSerialize();
|
||||
if (!empty($traits)) {
|
||||
$js['traits'] = $traits;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,43 +8,49 @@ use GeoIp2\Util;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 Domain model.
|
||||
*
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or
|
||||
* "example.co.uk", not "foo.example.com".
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Domain extends AbstractModel
|
||||
class Domain implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or
|
||||
* "example.co.uk", not "foo.example.com".
|
||||
*/
|
||||
protected $domain;
|
||||
public readonly ?string $domain;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string the IP address that the data in the model is
|
||||
* for
|
||||
*/
|
||||
protected $ipAddress;
|
||||
public readonly string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
protected $network;
|
||||
public readonly string $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
$this->domain = $this->get('domain');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->domain = $raw['domain'] ?? null;
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->domain !== null) {
|
||||
$js['domain'] = $this->domain;
|
||||
}
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
$js['network'] = $this->network;
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,5 @@ namespace GeoIp2\Model;
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more
|
||||
* details.
|
||||
*/
|
||||
class Enterprise extends City
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class Enterprise extends City {}
|
||||
|
@ -10,6 +10,5 @@ namespace GeoIp2\Model;
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for
|
||||
* more details.
|
||||
*/
|
||||
class Insights extends City
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class Insights extends City {}
|
||||
|
@ -8,86 +8,103 @@ use GeoIp2\Util;
|
||||
|
||||
/**
|
||||
* This class provides the GeoIP2 ISP model.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address.
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address.
|
||||
* @property-read string|null $mobileCountryCode The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
* @property-read string|null $mobileNetworkCode The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
* @property-read string|null $organization The name of the organization associated
|
||||
* with the IP address.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Isp extends AbstractModel
|
||||
class Isp implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
* @var int|null the autonomous system number
|
||||
* associated with the IP address
|
||||
*/
|
||||
protected $autonomousSystemNumber;
|
||||
public readonly ?int $autonomousSystemNumber;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null the organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address
|
||||
*/
|
||||
protected $autonomousSystemOrganization;
|
||||
public readonly ?string $autonomousSystemOrganization;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null the name of the ISP associated with the IP
|
||||
* address
|
||||
*/
|
||||
protected $isp;
|
||||
public readonly ?string $isp;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
*/
|
||||
protected $mobileCountryCode;
|
||||
public readonly ?string $mobileCountryCode;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
*/
|
||||
protected $mobileNetworkCode;
|
||||
public readonly ?string $mobileNetworkCode;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
* @var string|null the name of the organization associated
|
||||
* with the IP address
|
||||
*/
|
||||
protected $organization;
|
||||
public readonly ?string $organization;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string the IP address that the data in the model is
|
||||
* for
|
||||
*/
|
||||
protected $ipAddress;
|
||||
public readonly string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
protected $network;
|
||||
public readonly string $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
$this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null;
|
||||
$this->autonomousSystemOrganization =
|
||||
$this->get('autonomous_system_organization');
|
||||
$this->isp = $this->get('isp');
|
||||
$this->mobileCountryCode = $this->get('mobile_country_code');
|
||||
$this->mobileNetworkCode = $this->get('mobile_network_code');
|
||||
$this->organization = $this->get('organization');
|
||||
$raw['autonomous_system_organization'] ?? null;
|
||||
$this->isp = $raw['isp'] ?? null;
|
||||
$this->mobileCountryCode = $raw['mobile_country_code'] ?? null;
|
||||
$this->mobileNetworkCode = $raw['mobile_network_code'] ?? null;
|
||||
$this->organization = $raw['organization'] ?? null;
|
||||
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$ipAddress = $raw['ip_address'];
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->autonomousSystemNumber !== null) {
|
||||
$js['autonomous_system_number'] = $this->autonomousSystemNumber;
|
||||
}
|
||||
if ($this->autonomousSystemOrganization !== null) {
|
||||
$js['autonomous_system_organization'] = $this->autonomousSystemOrganization;
|
||||
}
|
||||
if ($this->isp !== null) {
|
||||
$js['isp'] = $this->isp;
|
||||
}
|
||||
if ($this->mobileCountryCode !== null) {
|
||||
$js['mobile_country_code'] = $this->mobileCountryCode;
|
||||
}
|
||||
if ($this->mobileNetworkCode !== null) {
|
||||
$js['mobile_network_code'] = $this->mobileNetworkCode;
|
||||
}
|
||||
if ($this->organization !== null) {
|
||||
$js['organization'] = $this->organization;
|
||||
}
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
$js['network'] = $this->network;
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
453
lib/maxmind/GeoIp2/README.md
Normal file
453
lib/maxmind/GeoIp2/README.md
Normal file
@ -0,0 +1,453 @@
|
||||
# GeoIP2 PHP API #
|
||||
|
||||
## Description ##
|
||||
|
||||
This package provides an API for the GeoIP2 and GeoLite2
|
||||
[web services](https://dev.maxmind.com/geoip/docs/web-services?lang=en) and
|
||||
[databases](https://dev.maxmind.com/geoip/docs/databases?lang=en).
|
||||
|
||||
## Install via Composer ##
|
||||
|
||||
We recommend installing this package with [Composer](https://getcomposer.org/).
|
||||
|
||||
### Download Composer ###
|
||||
|
||||
To download Composer, run in the root directory of your project:
|
||||
|
||||
```bash
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
```
|
||||
|
||||
You should now have the file `composer.phar` in your project directory.
|
||||
|
||||
### Install Dependencies ###
|
||||
|
||||
Run in your project root:
|
||||
|
||||
```sh
|
||||
php composer.phar require geoip2/geoip2:~2.0
|
||||
```
|
||||
|
||||
You should now have the files `composer.json` and `composer.lock` as well as
|
||||
the directory `vendor` in your project directory. If you use a version control
|
||||
system, `composer.json` should be added to it.
|
||||
|
||||
### Require Autoloader ###
|
||||
|
||||
After installing the dependencies, you need to require the Composer autoloader
|
||||
from your code:
|
||||
|
||||
```php
|
||||
require 'vendor/autoload.php';
|
||||
```
|
||||
|
||||
## Install via Phar ##
|
||||
|
||||
Although we strongly recommend using Composer, we also provide a
|
||||
[phar archive](https://php.net/manual/en/book.phar.php) containing most of the
|
||||
dependencies for GeoIP2. Our latest phar archive is available on
|
||||
[our releases page](https://github.com/maxmind/GeoIP2-php/releases).
|
||||
|
||||
### Install Dependencies ###
|
||||
|
||||
In order to use the phar archive, you must have the PHP
|
||||
[Phar extension](https://php.net/manual/en/book.phar.php) installed and
|
||||
enabled.
|
||||
|
||||
If you will be making web service requests, you must have the PHP
|
||||
[cURL extension](https://php.net/manual/en/book.curl.php)
|
||||
installed to use this archive. For Debian based distributions, this can
|
||||
typically be found in the the `php-curl` package. For other operating
|
||||
systems, please consult the relevant documentation. After installing the
|
||||
extension you may need to restart your web server.
|
||||
|
||||
If you are missing this extension, you will see errors like the following:
|
||||
|
||||
```
|
||||
PHP Fatal error: Uncaught Error: Call to undefined function MaxMind\WebService\curl_version()
|
||||
```
|
||||
|
||||
### Require Package ###
|
||||
|
||||
To use the archive, just require it from your script:
|
||||
|
||||
```php
|
||||
require 'geoip2.phar';
|
||||
```
|
||||
|
||||
## Optional C Extension ##
|
||||
|
||||
The [MaxMind DB API](https://github.com/maxmind/MaxMind-DB-Reader-php)
|
||||
includes an optional C extension that you may install to dramatically increase
|
||||
the performance of lookups in GeoIP2 or GeoLite2 databases. To install, please
|
||||
follow the instructions included with that API.
|
||||
|
||||
The extension has no effect on web-service lookups.
|
||||
|
||||
## IP Geolocation Usage ##
|
||||
|
||||
IP geolocation is inherently imprecise. Locations are often near the center of
|
||||
the population. Any location provided by a GeoIP2 database or web service
|
||||
should not be used to identify a particular address or household.
|
||||
|
||||
## Database Reader ##
|
||||
|
||||
### Usage ###
|
||||
|
||||
To use this API, you must create a new `\GeoIp2\Database\Reader` object with
|
||||
the path to the database file as the first argument to the constructor. You
|
||||
may then call the method corresponding to the database you are using.
|
||||
|
||||
If the lookup succeeds, the method call will return a model class for the
|
||||
record in the database. This model in turn contains multiple container
|
||||
classes for the different parts of the data such as the city in which the
|
||||
IP address is located.
|
||||
|
||||
If the record is not found, a `\GeoIp2\Exception\AddressNotFoundException`
|
||||
is thrown. If the database is invalid or corrupt, a
|
||||
`\MaxMind\Db\InvalidDatabaseException` will be thrown.
|
||||
|
||||
See the [API documentation](https://maxmind.github.io/GeoIP2-php/) for more
|
||||
details.
|
||||
|
||||
### City Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$cityDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');
|
||||
|
||||
// Replace "city" with the appropriate method for your database, e.g.,
|
||||
// "country".
|
||||
$record = $cityDbReader->city('128.101.101.101');
|
||||
|
||||
print($record->country->isoCode . "\n"); // 'US'
|
||||
print($record->country->name . "\n"); // 'United States'
|
||||
print($record->country->names['zh-CN'] . "\n"); // '美国'
|
||||
|
||||
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
|
||||
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
|
||||
|
||||
print($record->city->name . "\n"); // 'Minneapolis'
|
||||
|
||||
print($record->postal->code . "\n"); // '55455'
|
||||
|
||||
print($record->location->latitude . "\n"); // 44.9733
|
||||
print($record->location->longitude . "\n"); // -93.2323
|
||||
|
||||
print($record->traits->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### Anonymous IP 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/GeoIP2-Anonymous-IP.mmdb');
|
||||
|
||||
$record = $anonymousDbReader->anonymousIp('128.101.101.101');
|
||||
|
||||
if ($record->isAnonymous) { print "anon\n"; }
|
||||
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||
print($record->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### Connection-Type Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$connectionTypeDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-Connection-Type.mmdb');
|
||||
|
||||
$record = $connectionTypeDbReader->connectionType('128.101.101.101');
|
||||
|
||||
print($record->connectionType . "\n"); // 'Corporate'
|
||||
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||
print($record->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### Domain Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$domainDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-Domain.mmdb');
|
||||
|
||||
$record = $domainDbReader->domain('128.101.101.101');
|
||||
|
||||
print($record->domain . "\n"); // 'umn.edu'
|
||||
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||
print($record->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### Enterprise Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$enterpriseDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-Enterprise.mmdb');
|
||||
|
||||
// Use the ->enterprise method to do a lookup in the Enterprise database
|
||||
$record = $enterpriseDbReader->enterprise('128.101.101.101');
|
||||
|
||||
print($record->country->confidence . "\n"); // 99
|
||||
print($record->country->isoCode . "\n"); // 'US'
|
||||
print($record->country->name . "\n"); // 'United States'
|
||||
print($record->country->names['zh-CN'] . "\n"); // '美国'
|
||||
|
||||
print($record->mostSpecificSubdivision->confidence . "\n"); // 77
|
||||
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
|
||||
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
|
||||
|
||||
print($record->city->confidence . "\n"); // 60
|
||||
print($record->city->name . "\n"); // 'Minneapolis'
|
||||
|
||||
print($record->postal->code . "\n"); // '55455'
|
||||
|
||||
print($record->location->accuracyRadius . "\n"); // 50
|
||||
print($record->location->latitude . "\n"); // 44.9733
|
||||
print($record->location->longitude . "\n"); // -93.2323
|
||||
|
||||
print($record->traits->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
### ISP Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
// This creates the Reader object, which should be reused across
|
||||
// lookups.
|
||||
$ispDbReader = new Reader('/usr/local/share/GeoIP/GeoIP2-ISP.mmdb');
|
||||
|
||||
$record = $ispDbReader->isp('128.101.101.101');
|
||||
|
||||
print($record->autonomousSystemNumber . "\n"); // 217
|
||||
print($record->autonomousSystemOrganization . "\n"); // 'University of Minnesota'
|
||||
print($record->isp . "\n"); // 'University of Minnesota'
|
||||
print($record->organization . "\n"); // 'University of Minnesota'
|
||||
|
||||
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||
print($record->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
## Database Updates ##
|
||||
|
||||
You can keep your databases up to date with our
|
||||
[GeoIP Update program](https://github.com/maxmind/geoipupdate/releases).
|
||||
[Learn more about GeoIP Update on our developer
|
||||
portal.](https://dev.maxmind.com/geoip/updating-databases?lang=en)
|
||||
|
||||
There is also a third-party tool for updating databases using PHP and
|
||||
Composer. MaxMind does not offer support for this tool or maintain it.
|
||||
[Learn more about the Geoip2 Update tool for PHP and Composer on its
|
||||
GitHub page.](https://github.com/tronovav/geoip2-update)
|
||||
|
||||
## Web Service Client ##
|
||||
|
||||
### Usage ###
|
||||
|
||||
To use this API, you must create a new `\GeoIp2\WebService\Client`
|
||||
object with your `$accountId` and `$licenseKey`:
|
||||
|
||||
```php
|
||||
$client = new Client(42, 'abcdef123456');
|
||||
```
|
||||
|
||||
You may also call the constructor with additional arguments. The third argument
|
||||
specifies the language preferences when using the `->name` method on the model
|
||||
classes that this client creates. The fourth argument is additional options
|
||||
such as `host` and `timeout`.
|
||||
|
||||
For instance, to call the GeoLite2 web service instead of the GeoIP2 web
|
||||
service:
|
||||
|
||||
```php
|
||||
$client = new Client(42, 'abcdef123456', ['en'], ['host' => 'geolite.info']);
|
||||
```
|
||||
|
||||
To call the Sandbox GeoIP2 web service instead of the production GeoIP2 web
|
||||
service:
|
||||
|
||||
```php
|
||||
$client = new Client(42, 'abcdef123456', ['en'], ['host' => 'sandbox.maxmind.com']);
|
||||
```
|
||||
|
||||
After creating the client, you may now call the method corresponding to a
|
||||
specific endpoint with the IP address to look up, e.g.:
|
||||
|
||||
```php
|
||||
$record = $client->city('128.101.101.101');
|
||||
```
|
||||
|
||||
If the request succeeds, the method call will return a model class for the
|
||||
endpoint you called. This model in turn contains multiple record classes, each
|
||||
of which represents part of the data returned by the web service.
|
||||
|
||||
If there is an error, a structured exception is thrown.
|
||||
|
||||
See the [API documentation](https://maxmind.github.io/GeoIP2-php/) for more
|
||||
details.
|
||||
|
||||
### Example ###
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
use GeoIp2\WebService\Client;
|
||||
|
||||
// This creates a Client object that can be reused across requests.
|
||||
// Replace "42" with your account ID and "license_key" with your license
|
||||
// key. Set the "host" to "geolite.info" in the fourth argument options
|
||||
// array to use the GeoLite2 web service instead of the GeoIP2 web
|
||||
// service. Set the "host" to "sandbox.maxmind.com" in the fourth argument
|
||||
// options array to use the Sandbox GeoIP2 web service instead of the
|
||||
// production GeoIP2 web service.
|
||||
$client = new Client(42, 'abcdef123456');
|
||||
|
||||
// Replace "city" with the method corresponding to the web service that
|
||||
// you are using, e.g., "country", "insights".
|
||||
$record = $client->city('128.101.101.101');
|
||||
|
||||
print($record->country->isoCode . "\n"); // 'US'
|
||||
print($record->country->name . "\n"); // 'United States'
|
||||
print($record->country->names['zh-CN'] . "\n"); // '美国'
|
||||
|
||||
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
|
||||
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
|
||||
|
||||
print($record->city->name . "\n"); // 'Minneapolis'
|
||||
|
||||
print($record->postal->code . "\n"); // '55455'
|
||||
|
||||
print($record->location->latitude . "\n"); // 44.9733
|
||||
print($record->location->longitude . "\n"); // -93.2323
|
||||
|
||||
print($record->traits->network . "\n"); // '128.101.101.101/32'
|
||||
|
||||
```
|
||||
|
||||
## Values to use for Database or Array Keys ##
|
||||
|
||||
**We strongly discourage you from using a value from any `names` property as
|
||||
a key in a database or array.**
|
||||
|
||||
These names may change between releases. Instead we recommend using one of the
|
||||
following:
|
||||
|
||||
* `GeoIp2\Record\City` - `$city->geonameId`
|
||||
* `GeoIp2\Record\Continent` - `$continent->code` or `$continent->geonameId`
|
||||
* `GeoIp2\Record\Country` and `GeoIp2\Record\RepresentedCountry` -
|
||||
`$country->isoCode` or `$country->geonameId`
|
||||
* `GeoIp2\Record\Subdivision` - `$subdivision->isoCode` or `$subdivision->geonameId`
|
||||
|
||||
### What data is returned? ###
|
||||
|
||||
While many of the end points return the same basic records, the attributes
|
||||
which can be populated vary between end points. In addition, while an end
|
||||
point may offer a particular piece of data, MaxMind does not always have every
|
||||
piece of data for any given IP address.
|
||||
|
||||
Because of these factors, it is possible for any end point to return a record
|
||||
where some or all of the attributes are unpopulated.
|
||||
|
||||
See the
|
||||
[GeoIP2 web service docs](https://dev.maxmind.com/geoip/docs/web-services?lang=en)
|
||||
for details on what data each end point may return.
|
||||
|
||||
The only piece of data which is always returned is the `ipAddress`
|
||||
attribute in the `GeoIp2\Record\Traits` record.
|
||||
|
||||
## Integration with GeoNames ##
|
||||
|
||||
[GeoNames](https://www.geonames.org/) offers web services and downloadable
|
||||
databases with data on geographical features around the world, including
|
||||
populated places. They offer both free and paid premium data. Each
|
||||
feature is unique identified by a `geonameId`, which is an integer.
|
||||
|
||||
Many of the records returned by the GeoIP2 web services and databases
|
||||
include a `geonameId` property. This is the ID of a geographical feature
|
||||
(city, region, country, etc.) in the GeoNames database.
|
||||
|
||||
Some of the data that MaxMind provides is also sourced from GeoNames. We
|
||||
source things like place names, ISO codes, and other similar data from
|
||||
the GeoNames premium data set.
|
||||
|
||||
## Reporting data problems ##
|
||||
|
||||
If the problem you find is that an IP address is incorrectly mapped,
|
||||
please
|
||||
[submit your correction to MaxMind](https://www.maxmind.com/en/correction).
|
||||
|
||||
If you find some other sort of mistake, like an incorrect spelling,
|
||||
please check the [GeoNames site](https://www.geonames.org/) first. Once
|
||||
you've searched for a place and found it on the GeoNames map view, there
|
||||
are a number of links you can use to correct data ("move", "edit",
|
||||
"alternate names", etc.). Once the correction is part of the GeoNames
|
||||
data set, it will be automatically incorporated into future MaxMind
|
||||
releases.
|
||||
|
||||
If you are a paying MaxMind customer and you're not sure where to submit
|
||||
a correction, please
|
||||
[contact MaxMind support](https://www.maxmind.com/en/support) for help.
|
||||
|
||||
## Other Support ##
|
||||
|
||||
Please report all issues with this code using the
|
||||
[GitHub issue tracker](https://github.com/maxmind/GeoIP2-php/issues).
|
||||
|
||||
If you are having an issue with a MaxMind service that is not specific
|
||||
to the client API, please see
|
||||
[our support page](https://www.maxmind.com/en/support).
|
||||
|
||||
## Requirements ##
|
||||
|
||||
This library requires PHP 8.1 or greater.
|
||||
|
||||
This library also relies on the [MaxMind DB Reader](https://github.com/maxmind/MaxMind-DB-Reader-php).
|
||||
|
||||
## Contributing ##
|
||||
|
||||
Patches and pull requests are encouraged. All code should follow the PSR-2
|
||||
style guidelines. Please include unit tests whenever possible. You may obtain
|
||||
the test data for the maxmind-db folder by running `git submodule update
|
||||
--init --recursive` or adding `--recursive` to your initial clone, or from
|
||||
https://github.com/maxmind/MaxMind-DB
|
||||
|
||||
## Versioning ##
|
||||
|
||||
The GeoIP2 PHP API uses [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## Copyright and License ##
|
||||
|
||||
This software is Copyright (c) 2013-2023 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
49
lib/maxmind/GeoIp2/Record/AbstractNamedRecord.php
Normal file
49
lib/maxmind/GeoIp2/Record/AbstractNamedRecord.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractNamedRecord implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string|null The name based on the locales list
|
||||
* passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
public readonly ?string $name;
|
||||
|
||||
/**
|
||||
* @var array An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
public readonly array $names;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
$this->names = $record['names'] ?? [];
|
||||
|
||||
foreach ($locales as $locale) {
|
||||
if (isset($this->names[$locale])) {
|
||||
$this->name = $this->names[$locale];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->name = null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = [];
|
||||
if (!empty($this->names)) {
|
||||
$js['names'] = $this->names;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
@ -4,64 +4,43 @@ declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
abstract class AbstractPlaceRecord extends AbstractNamedRecord
|
||||
{
|
||||
/**
|
||||
* @var array<string>
|
||||
* @var int|null A value from 0-100 indicating MaxMind's
|
||||
* confidence that the location level is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
*/
|
||||
private $locales;
|
||||
public readonly ?int $confidence;
|
||||
|
||||
/**
|
||||
* @var int|null The GeoName ID for the location level. This attribute
|
||||
* is returned by all location services and databases.
|
||||
*/
|
||||
public readonly ?int $geonameId;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(?array $record, array $locales = ['en'])
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
$this->locales = $locales;
|
||||
parent::__construct($record);
|
||||
parent::__construct($record, $locales);
|
||||
|
||||
$this->confidence = $record['confidence'] ?? null;
|
||||
$this->geonameId = $record['geoname_id'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->name();
|
||||
$js = parent::jsonSerialize();
|
||||
if ($this->confidence !== null) {
|
||||
$js['confidence'] = $this->confidence;
|
||||
}
|
||||
|
||||
return parent::__get($attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->firstSetNameLocale() !== null;
|
||||
if ($this->geonameId !== null) {
|
||||
$js['geoname_id'] = $this->geonameId;
|
||||
}
|
||||
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
|
||||
private function name(): ?string
|
||||
{
|
||||
$locale = $this->firstSetNameLocale();
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
return $locale === null ? null : $this->names[$locale];
|
||||
}
|
||||
|
||||
private function firstSetNameLocale(): ?string
|
||||
{
|
||||
foreach ($this->locales as $locale) {
|
||||
if (isset($this->names[$locale])) {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractRecord implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $record;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(?array $record)
|
||||
{
|
||||
$this->record = isset($record) ? $record : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
// XXX - kind of ugly but greatly reduces boilerplate code
|
||||
$key = $this->attributeToKey($attr);
|
||||
|
||||
if ($this->__isset($attr)) {
|
||||
return $this->record[$key];
|
||||
}
|
||||
if ($this->validAttribute($attr)) {
|
||||
if (preg_match('/^is_/', $key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new \RuntimeException("Unknown attribute: $attr");
|
||||
}
|
||||
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
return $this->validAttribute($attr)
|
||||
&& isset($this->record[$this->attributeToKey($attr)]);
|
||||
}
|
||||
|
||||
private function attributeToKey(string $attr): string
|
||||
{
|
||||
return strtolower(preg_replace('/([A-Z])/', '_\1', $attr));
|
||||
}
|
||||
|
||||
private function validAttribute(string $attr): bool
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return \in_array($attr, $this->validAttributes, true);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
}
|
@ -9,25 +9,6 @@ namespace GeoIp2\Record;
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the city is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
* @property-read int|null $geonameId The GeoName ID for the city. This attribute
|
||||
* is returned by all location services and databases.
|
||||
* @property-read string|null $name The name of the city based on the locales list
|
||||
* passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class City extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['confidence', 'geonameId', 'names'];
|
||||
}
|
||||
// phpcs:disable
|
||||
class City extends AbstractPlaceRecord {}
|
||||
|
@ -8,29 +8,43 @@ namespace GeoIp2\Record;
|
||||
* Contains data for the continent record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read string|null $code A two character continent code like "NA" (North
|
||||
* America) or "OC" (Oceania). This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read int|null $geonameId The GeoName ID for the continent. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read string|null $name Returns the name of the continent based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Continent extends AbstractPlaceRecord
|
||||
class Continent extends AbstractNamedRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var string|null A two character continent code like "NA" (North
|
||||
* America) or "OC" (Oceania). This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'code',
|
||||
'geonameId',
|
||||
'names',
|
||||
];
|
||||
public readonly ?string $code;
|
||||
|
||||
/**
|
||||
* @var int|null The GeoName ID for the continent. This
|
||||
* attribute is returned by all location services and databases.
|
||||
*/
|
||||
public readonly ?int $geonameId;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($record, $locales);
|
||||
|
||||
$this->code = $record['code'] ?? null;
|
||||
$this->geonameId = $record['geoname_id'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = parent::jsonSerialize();
|
||||
if ($this->code !== null) {
|
||||
$js['code'] = $this->code;
|
||||
}
|
||||
if ($this->geonameId !== null) {
|
||||
$js['geoname_id'] = $this->geonameId;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,37 +8,44 @@ namespace GeoIp2\Record;
|
||||
* Contains data for the country record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the country is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
* @property-read int|null $geonameId The GeoName ID for the country. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read bool $isInEuropeanUnion This is true if the country is a
|
||||
* member state of the European Union. This attribute is returned by all
|
||||
* location services and databases.
|
||||
* @property-read string|null $isoCode The two-character ISO 3166-1 alpha code
|
||||
* for the country. See https://en.wikipedia.org/wiki/ISO_3166-1. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read string|null $name The name of the country based on the locales
|
||||
* list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Country extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var bool This is true if the country is a
|
||||
* member state of the European Union. This attribute is returned by all
|
||||
* location services and databases.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isInEuropeanUnion',
|
||||
'isoCode',
|
||||
'names',
|
||||
];
|
||||
public readonly bool $isInEuropeanUnion;
|
||||
|
||||
/**
|
||||
* @var string|null The two-character ISO 3166-1 alpha code
|
||||
* for the country. See https://en.wikipedia.org/wiki/ISO_3166-1. This
|
||||
* attribute is returned by all location services and databases.
|
||||
*/
|
||||
public readonly ?string $isoCode;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($record, $locales);
|
||||
|
||||
$this->isInEuropeanUnion = $record['is_in_european_union'] ?? false;
|
||||
$this->isoCode = $record['iso_code'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = parent::jsonSerialize();
|
||||
if ($this->isInEuropeanUnion !== false) {
|
||||
$js['is_in_european_union'] = $this->isInEuropeanUnion;
|
||||
}
|
||||
if ($this->isoCode !== null) {
|
||||
$js['iso_code'] = $this->isoCode;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -9,48 +9,97 @@ namespace GeoIp2\Record;
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $averageIncome The average income in US dollars
|
||||
* associated with the requested IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
* @property-read int|null $accuracyRadius The approximate accuracy radius in
|
||||
* kilometers around the latitude and longitude for the IP address. This is
|
||||
* the radius where we have a 67% confidence that the device using the IP
|
||||
* address resides within the circle centered at the latitude and longitude
|
||||
* with the provided radius.
|
||||
* @property-read float|null $latitude The approximate latitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
* @property-read float|null $longitude The approximate longitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
* @property-read int|null $populationDensity The estimated population per square
|
||||
* kilometer associated with the IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
* @property-read int|null $metroCode 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.
|
||||
* @property-read string|null $timeZone The time zone associated with location, as
|
||||
* specified by the IANA Time Zone Database, e.g., "America/New_York". See
|
||||
* https://www.iana.org/time-zones.
|
||||
*/
|
||||
class Location extends AbstractRecord
|
||||
class Location implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var int|null The average income in US dollars
|
||||
* associated with the requested IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'averageIncome',
|
||||
'accuracyRadius',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'metroCode',
|
||||
'populationDensity',
|
||||
'postalCode',
|
||||
'postalConfidence',
|
||||
'timeZone',
|
||||
];
|
||||
public readonly ?int $averageIncome;
|
||||
|
||||
/**
|
||||
* @var int|null The approximate accuracy radius in
|
||||
* kilometers around the latitude and longitude for the IP address. This is
|
||||
* the radius where we have a 67% confidence that the device using the IP
|
||||
* address resides within the circle centered at the latitude and longitude
|
||||
* with the provided radius.
|
||||
*/
|
||||
public readonly ?int $accuracyRadius;
|
||||
|
||||
/**
|
||||
* @var float|null The approximate latitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
*/
|
||||
public readonly ?float $latitude;
|
||||
|
||||
/**
|
||||
* @var float|null The approximate longitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public readonly ?int $metroCode;
|
||||
|
||||
/**
|
||||
* @var int|null The estimated population per square
|
||||
* kilometer associated with the IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
*/
|
||||
public readonly ?int $populationDensity;
|
||||
|
||||
/**
|
||||
* @var string|null The time zone associated with location, as
|
||||
* specified by the IANA Time Zone Database, e.g., "America/New_York". See
|
||||
* https://www.iana.org/time-zones.
|
||||
*/
|
||||
public readonly ?string $timeZone;
|
||||
|
||||
public function __construct(array $record)
|
||||
{
|
||||
$this->averageIncome = $record['average_income'] ?? null;
|
||||
$this->accuracyRadius = $record['accuracy_radius'] ?? null;
|
||||
$this->latitude = $record['latitude'] ?? null;
|
||||
$this->longitude = $record['longitude'] ?? null;
|
||||
$this->metroCode = $record['metro_code'] ?? null;
|
||||
$this->populationDensity = $record['population_density'] ?? null;
|
||||
$this->timeZone = $record['time_zone'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->averageIncome !== null) {
|
||||
$js['average_income'] = $this->averageIncome;
|
||||
}
|
||||
if ($this->accuracyRadius !== null) {
|
||||
$js['accuracy_radius'] = $this->accuracyRadius;
|
||||
}
|
||||
if ($this->latitude !== null) {
|
||||
$js['latitude'] = $this->latitude;
|
||||
}
|
||||
if ($this->longitude !== null) {
|
||||
$js['longitude'] = $this->longitude;
|
||||
}
|
||||
if ($this->metroCode !== null) {
|
||||
$js['metro_code'] = $this->metroCode;
|
||||
}
|
||||
if ($this->populationDensity !== null) {
|
||||
$js['population_density'] = $this->populationDensity;
|
||||
}
|
||||
if ($this->timeZone !== null) {
|
||||
$js['time_zone'] = $this->timeZone;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,27 @@ namespace GeoIp2\Record;
|
||||
* Contains data about your account.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $queriesRemaining The number of remaining queries you
|
||||
* have for the service you are calling.
|
||||
*/
|
||||
class MaxMind extends AbstractRecord
|
||||
class MaxMind implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var int|null the number of remaining queries you
|
||||
* have for the service you are calling
|
||||
*/
|
||||
protected $validAttributes = ['queriesRemaining'];
|
||||
public readonly ?int $queriesRemaining;
|
||||
|
||||
public function __construct(array $record)
|
||||
{
|
||||
$this->queriesRemaining = $record['queries_remaining'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->queriesRemaining !== null) {
|
||||
$js['queries_remaining'] = $this->queriesRemaining;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -9,22 +9,44 @@ namespace GeoIp2\Record;
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read string|null $code The postal code of the location. Postal codes
|
||||
* are not available for all countries. In some countries, this will only
|
||||
* contain part of the postal code. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the postal code is correct. This attribute is only
|
||||
* available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*/
|
||||
class Postal extends AbstractRecord
|
||||
class Postal implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var string|null The postal code of the location. Postal codes
|
||||
* are not available for all countries. In some countries, this will only
|
||||
* contain part of the postal code. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
*/
|
||||
protected $validAttributes = ['code', 'confidence'];
|
||||
public readonly ?string $code;
|
||||
|
||||
/**
|
||||
* @var int|null A value from 0-100 indicating MaxMind's
|
||||
* confidence that the postal code is correct. This attribute is only
|
||||
* available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*/
|
||||
public readonly ?int $confidence;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record)
|
||||
{
|
||||
$this->code = $record['code'] ?? null;
|
||||
$this->confidence = $record['confidence'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->code !== null) {
|
||||
$js['code'] = $this->code;
|
||||
}
|
||||
if ($this->confidence !== null) {
|
||||
$js['confidence'] = $this->confidence;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,33 @@ namespace GeoIp2\Record;
|
||||
* This class contains the country-level data associated with an IP address
|
||||
* for the IP's represented country. The represented country is the country
|
||||
* represented by something like a military base.
|
||||
*
|
||||
* @property-read string|null $type A string indicating the type of entity that is
|
||||
* representing the country. Currently we only return <code>military</code>
|
||||
* but this could expand to include other types in the future.
|
||||
*/
|
||||
class RepresentedCountry extends Country
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var string|null A string indicating the type of entity that is
|
||||
* representing the country. Currently we only return <code>military</code>
|
||||
* but this could expand to include other types in the future.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isInEuropeanUnion',
|
||||
'isoCode',
|
||||
'names',
|
||||
'type',
|
||||
];
|
||||
public readonly ?string $type;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($record, $locales);
|
||||
|
||||
$this->type = $record['type'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = parent::jsonSerialize();
|
||||
if ($this->type !== null) {
|
||||
$js['type'] = $this->type;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -9,36 +9,34 @@ namespace GeoIp2\Record;
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence This is a value from 0-100 indicating
|
||||
* MaxMind's confidence that the subdivision is correct. This attribute is
|
||||
* only available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
* @property-read int|null $geonameId This is a GeoName ID for the subdivision.
|
||||
* This attribute is returned by all location databases and services besides
|
||||
* Country.
|
||||
* @property-read string|null $isoCode This is a string up to three characters long
|
||||
* contain the subdivision portion of the ISO 3166-2 code. See
|
||||
* https://en.wikipedia.org/wiki/ISO_3166-2. This attribute is returned by all
|
||||
* location databases and services except Country.
|
||||
* @property-read string|null $name The name of the subdivision based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all
|
||||
* location databases and services besides Country.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
*/
|
||||
class Subdivision extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var string|null This is a string up to three characters long
|
||||
* contain the subdivision portion of the ISO 3166-2 code. See
|
||||
* https://en.wikipedia.org/wiki/ISO_3166-2. This attribute is returned by all
|
||||
* location databases and services except Country.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'confidence',
|
||||
'geonameId',
|
||||
'isoCode',
|
||||
'names',
|
||||
];
|
||||
public readonly ?string $isoCode;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $record, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($record, $locales);
|
||||
|
||||
$this->isoCode = $record['iso_code'] ?? null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = parent::jsonSerialize();
|
||||
if ($this->isoCode !== null) {
|
||||
$js['iso_code'] = $this->isoCode;
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -10,149 +10,289 @@ use GeoIp2\Util;
|
||||
* Contains data for the traits record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address. See
|
||||
* https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This attribute
|
||||
* is only available from the City Plus and Insights web services and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP address.
|
||||
* See https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This
|
||||
* attribute is only available from the City Plus and Insights web services and
|
||||
* the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future. This attribute is only
|
||||
* available in the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or "example.co.uk",
|
||||
* not "foo.example.com". This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise
|
||||
* database.
|
||||
* @property-read string $ipAddress The IP address that the data in the model
|
||||
* is for. If you performed a "me" lookup against the web service, this
|
||||
* will be the externally routable IP address for the system the code is
|
||||
* running on. If the system is behind a NAT, this may differ from the IP
|
||||
* address locally assigned to it. This attribute is returned by all end
|
||||
* points.
|
||||
* @property-read bool $isAnonymous This is true if the IP address belongs to
|
||||
* any sort of anonymous network. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
* @property-read bool $isAnonymousProxy *Deprecated.* Please see our GeoIP2
|
||||
* Anonymous IP database
|
||||
* (https://www.maxmind.com/en/geoip2-anonymous-ip-database) to determine
|
||||
* whether the IP address is used by an anonymizing service.
|
||||
* @property-read bool $isAnonymousVpn This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not register
|
||||
* subnets under names associated with them, we will likely only flag their IP
|
||||
* ranges using the isHostingProvider property. This property is only available
|
||||
* from GeoIP2 Insights.
|
||||
* @property-read bool $isHostingProvider This is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property).
|
||||
* This property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isLegitimateProxy This attribute is true if MaxMind
|
||||
* believes this IP address to be a legitimate proxy, such as an internal
|
||||
* VPN used by a corporation. This attribute is only available in the GeoIP2
|
||||
* Enterprise database.
|
||||
* @property-read bool $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy. This property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isResidentialProxy This is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP. This
|
||||
* property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isSatelliteProvider *Deprecated.* Due to the
|
||||
* increased coverage by mobile carriers, very few satellite providers now
|
||||
* serve multiple countries. As a result, the output does not provide
|
||||
* sufficiently relevant data for us to maintain it.
|
||||
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
|
||||
* exit node. This property is only available from GeoIP2 Insights.
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address. This attribute is only available from the City Plus and Insights
|
||||
* web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
* @property-read string|null $organization The name of the organization
|
||||
* associated with the IP address. This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $mobileCountryCode The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $mobileNetworkCode The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read float|null $staticIpScore An indicator of how static or
|
||||
* dynamic an IP address is. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
* @property-read int|null $userCount The estimated number of users sharing
|
||||
* the IP/network during the past 24 hours. For IPv4, the count is for the
|
||||
* individual IP. For IPv6, the count is for the /64 network. This property is
|
||||
* only available from GeoIP2 Insights.
|
||||
* @property-read string|null $userType <p>The user type associated with the IP
|
||||
* address. This can be one of the following values:</p>
|
||||
* <ul>
|
||||
* <li>business
|
||||
* <li>cafe
|
||||
* <li>cellular
|
||||
* <li>college
|
||||
* <li>consumer_privacy_network
|
||||
* <li>content_delivery_network
|
||||
* <li>dialup
|
||||
* <li>government
|
||||
* <li>hosting
|
||||
* <li>library
|
||||
* <li>military
|
||||
* <li>residential
|
||||
* <li>router
|
||||
* <li>school
|
||||
* <li>search_engine_spider
|
||||
* <li>traveler
|
||||
* </ul>
|
||||
* <p>
|
||||
* This attribute is only available from the Insights web service and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* </p>
|
||||
*/
|
||||
class Traits extends AbstractRecord
|
||||
class Traits implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
* @var int|null The autonomous system number
|
||||
* associated with the IP address. See
|
||||
* https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This attribute
|
||||
* is only available from the City Plus and Insights web services and the
|
||||
* GeoIP2 Enterprise database.
|
||||
*/
|
||||
protected $validAttributes = [
|
||||
'autonomousSystemNumber',
|
||||
'autonomousSystemOrganization',
|
||||
'connectionType',
|
||||
'domain',
|
||||
'ipAddress',
|
||||
'isAnonymous',
|
||||
'isAnonymousProxy',
|
||||
'isAnonymousVpn',
|
||||
'isHostingProvider',
|
||||
'isLegitimateProxy',
|
||||
'isp',
|
||||
'isPublicProxy',
|
||||
'isResidentialProxy',
|
||||
'isSatelliteProvider',
|
||||
'isTorExitNode',
|
||||
'mobileCountryCode',
|
||||
'mobileNetworkCode',
|
||||
'network',
|
||||
'organization',
|
||||
'staticIpScore',
|
||||
'userCount',
|
||||
'userType',
|
||||
];
|
||||
public readonly ?int $autonomousSystemNumber;
|
||||
|
||||
public function __construct(?array $record)
|
||||
/**
|
||||
* @var string|null The organization
|
||||
* associated with the registered autonomous system number for the IP address.
|
||||
* See https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This
|
||||
* attribute is only available from the City Plus and Insights web services and
|
||||
* the GeoIP2 Enterprise database.
|
||||
*/
|
||||
public readonly ?string $autonomousSystemOrganization;
|
||||
|
||||
/**
|
||||
* @var string|null The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular", and
|
||||
* "Satellite". Additional values may be added in the future. This attribute is
|
||||
* only available from the City Plus and Insights web services and the GeoIP2
|
||||
* Enterprise database.
|
||||
*/
|
||||
public readonly ?string $connectionType;
|
||||
|
||||
/**
|
||||
* @var string|null The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or "example.co.uk",
|
||||
* not "foo.example.com". This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*/
|
||||
public readonly ?string $domain;
|
||||
|
||||
/**
|
||||
* @var string|null The IP address that the data in the model
|
||||
* is for. If you performed a "me" lookup against the web service, this
|
||||
* will be the externally routable IP address for the system the code is
|
||||
* running on. If the system is behind a NAT, this may differ from the IP
|
||||
* address locally assigned to it. This attribute is returned by all end
|
||||
* points.
|
||||
*/
|
||||
public readonly ?string $ipAddress;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address belongs to
|
||||
* any sort of anonymous network. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
*/
|
||||
public readonly bool $isAnonymous;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not register
|
||||
* subnets under names associated with them, we will likely only flag their IP
|
||||
* ranges using the isHostingProvider property. This property is only available
|
||||
* from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly bool $isAnonymousVpn;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address belongs to an [anycast
|
||||
* network](https://en.wikipedia.org/wiki/Anycast). This property is not
|
||||
* available from GeoLite databases or web services.
|
||||
*/
|
||||
public readonly bool $isAnycast;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property).
|
||||
* This property is only available from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly bool $isHostingProvider;
|
||||
|
||||
/**
|
||||
* @var bool This attribute is true if MaxMind
|
||||
* believes this IP address to be a legitimate proxy, such as an internal
|
||||
* VPN used by a corporation. This attribute is only available in the GeoIP2
|
||||
* Enterprise database.
|
||||
*/
|
||||
public readonly bool $isLegitimateProxy;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address belongs to
|
||||
* a public proxy. This property is only available from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly bool $isPublicProxy;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP. This
|
||||
* property is only available from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly bool $isResidentialProxy;
|
||||
|
||||
/**
|
||||
* @var bool This is true if the IP address is a Tor
|
||||
* exit node. This property is only available from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly bool $isTorExitNode;
|
||||
|
||||
/**
|
||||
* @var string|null The name of the ISP associated with the IP
|
||||
* address. This attribute is only available from the City Plus and Insights
|
||||
* web services and the GeoIP2 Enterprise database.
|
||||
*/
|
||||
public readonly ?string $isp;
|
||||
|
||||
/**
|
||||
* @var string|null The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
*/
|
||||
public readonly ?string $mobileCountryCode;
|
||||
|
||||
/**
|
||||
* @var string|null The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
*/
|
||||
public readonly ?string $mobileNetworkCode;
|
||||
|
||||
/**
|
||||
* @var string|null The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
public readonly ?string $network;
|
||||
|
||||
/**
|
||||
* @var string|null The name of the organization
|
||||
* associated with the IP address. This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise database.
|
||||
*/
|
||||
public readonly ?string $organization;
|
||||
|
||||
/**
|
||||
* @var float|null An indicator of how static or
|
||||
* dynamic an IP address is. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
*/
|
||||
public readonly ?float $staticIpScore;
|
||||
|
||||
/**
|
||||
* @var int|null The estimated number of users sharing
|
||||
* the IP/network during the past 24 hours. For IPv4, the count is for the
|
||||
* individual IP. For IPv6, the count is for the /64 network. This property is
|
||||
* only available from GeoIP2 Insights.
|
||||
*/
|
||||
public readonly ?int $userCount;
|
||||
|
||||
/**
|
||||
* @var string|null <p>The user type associated with the IP
|
||||
* address. This can be one of the following values:</p>
|
||||
* <ul>
|
||||
* <li>business
|
||||
* <li>cafe
|
||||
* <li>cellular
|
||||
* <li>college
|
||||
* <li>consumer_privacy_network
|
||||
* <li>content_delivery_network
|
||||
* <li>dialup
|
||||
* <li>government
|
||||
* <li>hosting
|
||||
* <li>library
|
||||
* <li>military
|
||||
* <li>residential
|
||||
* <li>router
|
||||
* <li>school
|
||||
* <li>search_engine_spider
|
||||
* <li>traveler
|
||||
* </ul>
|
||||
* <p>
|
||||
* This attribute is only available from the Insights web service and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* </p>
|
||||
*/
|
||||
public readonly ?string $userType;
|
||||
|
||||
public function __construct(array $record)
|
||||
{
|
||||
if (!isset($record['network']) && isset($record['ip_address'], $record['prefix_len'])) {
|
||||
$record['network'] = Util::cidr($record['ip_address'], $record['prefix_len']);
|
||||
$this->autonomousSystemNumber = $record['autonomous_system_number'] ?? null;
|
||||
$this->autonomousSystemOrganization = $record['autonomous_system_organization'] ?? null;
|
||||
$this->connectionType = $record['connection_type'] ?? null;
|
||||
$this->domain = $record['domain'] ?? null;
|
||||
$this->ipAddress = $record['ip_address'] ?? null;
|
||||
$this->isAnonymous = $record['is_anonymous'] ?? false;
|
||||
$this->isAnonymousVpn = $record['is_anonymous_vpn'] ?? false;
|
||||
$this->isAnycast = $record['is_anycast'] ?? false;
|
||||
$this->isHostingProvider = $record['is_hosting_provider'] ?? false;
|
||||
$this->isLegitimateProxy = $record['is_legitimate_proxy'] ?? false;
|
||||
$this->isp = $record['isp'] ?? null;
|
||||
$this->isPublicProxy = $record['is_public_proxy'] ?? false;
|
||||
$this->isResidentialProxy = $record['is_residential_proxy'] ?? false;
|
||||
$this->isTorExitNode = $record['is_tor_exit_node'] ?? false;
|
||||
$this->mobileCountryCode = $record['mobile_country_code'] ?? null;
|
||||
$this->mobileNetworkCode = $record['mobile_network_code'] ?? null;
|
||||
$this->organization = $record['organization'] ?? null;
|
||||
$this->staticIpScore = $record['static_ip_score'] ?? null;
|
||||
$this->userCount = $record['user_count'] ?? null;
|
||||
$this->userType = $record['user_type'] ?? null;
|
||||
|
||||
if (isset($record['network'])) {
|
||||
$this->network = $record['network'];
|
||||
} else {
|
||||
$this->network = isset($record['prefix_len']) ? Util::cidr($this->ipAddress, $record['prefix_len']) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$js = [];
|
||||
if ($this->autonomousSystemNumber !== null) {
|
||||
$js['autonomous_system_number'] = $this->autonomousSystemNumber;
|
||||
}
|
||||
if ($this->autonomousSystemOrganization !== null) {
|
||||
$js['autonomous_system_organization'] = $this->autonomousSystemOrganization;
|
||||
}
|
||||
if ($this->connectionType !== null) {
|
||||
$js['connection_type'] = $this->connectionType;
|
||||
}
|
||||
if ($this->domain !== null) {
|
||||
$js['domain'] = $this->domain;
|
||||
}
|
||||
if ($this->ipAddress !== null) {
|
||||
$js['ip_address'] = $this->ipAddress;
|
||||
}
|
||||
if ($this->isAnonymous !== false) {
|
||||
$js['is_anonymous'] = $this->isAnonymous;
|
||||
}
|
||||
if ($this->isAnonymousVpn !== false) {
|
||||
$js['is_anonymous_vpn'] = $this->isAnonymousVpn;
|
||||
}
|
||||
if ($this->isAnycast !== false) {
|
||||
$js['is_anycast'] = $this->isAnycast;
|
||||
}
|
||||
if ($this->isHostingProvider !== false) {
|
||||
$js['is_hosting_provider'] = $this->isHostingProvider;
|
||||
}
|
||||
if ($this->isLegitimateProxy !== false) {
|
||||
$js['is_legitimate_proxy'] = $this->isLegitimateProxy;
|
||||
}
|
||||
if ($this->isPublicProxy !== false) {
|
||||
$js['is_public_proxy'] = $this->isPublicProxy;
|
||||
}
|
||||
if ($this->isResidentialProxy !== false) {
|
||||
$js['is_residential_proxy'] = $this->isResidentialProxy;
|
||||
}
|
||||
if ($this->isTorExitNode !== false) {
|
||||
$js['is_tor_exit_node'] = $this->isTorExitNode;
|
||||
}
|
||||
if ($this->isp !== null) {
|
||||
$js['isp'] = $this->isp;
|
||||
}
|
||||
if ($this->mobileCountryCode !== null) {
|
||||
$js['mobile_country_code'] = $this->mobileCountryCode;
|
||||
}
|
||||
if ($this->mobileNetworkCode !== null) {
|
||||
$js['mobile_network_code'] = $this->mobileNetworkCode;
|
||||
}
|
||||
if ($this->network !== null) {
|
||||
$js['network'] = $this->network;
|
||||
}
|
||||
if ($this->organization !== null) {
|
||||
$js['organization'] = $this->organization;
|
||||
}
|
||||
if ($this->staticIpScore !== null) {
|
||||
$js['static_ip_score'] = $this->staticIpScore;
|
||||
}
|
||||
if ($this->userCount !== null) {
|
||||
$js['user_count'] = $this->userCount;
|
||||
}
|
||||
if ($this->userType !== null) {
|
||||
$js['user_type'] = $this->userType;
|
||||
}
|
||||
|
||||
parent::__construct($record);
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ class Util
|
||||
* length. This is for internal use only.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
public static function cidr(string $ipAddress, int $prefixLen): string
|
||||
|
@ -51,19 +51,11 @@ class Client implements ProviderInterface
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private $locales;
|
||||
private array $locales;
|
||||
private WsClient $client;
|
||||
private static string $basePath = '/geoip/v2.1';
|
||||
|
||||
/**
|
||||
* @var WsClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $basePath = '/geoip/v2.1';
|
||||
|
||||
public const VERSION = 'v2.13.0';
|
||||
public const VERSION = 'v3.0.0';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -76,7 +68,12 @@ class Client implements ProviderInterface
|
||||
* * `host` - The host to use when querying the web
|
||||
* service. To query the GeoLite2 web service
|
||||
* instead of the GeoIP2 web service, set the
|
||||
* host to `geolite.info`.
|
||||
* host to `geolite.info`. To query the Sandbox
|
||||
* GeoIP2 web service instead of the production
|
||||
* GeoIP2 web service, set the host to
|
||||
* `sandbox.maxmind.com`. The sandbox allows you to
|
||||
* experiment with the API without affecting your
|
||||
* production data.
|
||||
* * `timeout` - Timeout in seconds.
|
||||
* * `connectTimeout` - Initial connection timeout in seconds.
|
||||
* * `proxy` - The HTTP proxy to use. May include a schema, port,
|
||||
@ -135,6 +132,8 @@ class Client implements ProviderInterface
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly
|
||||
* if a 200 status code is returned but the body is invalid.
|
||||
* @throws \InvalidArgumentException if something other than a single IP address or "me" is
|
||||
* passed to the method
|
||||
*/
|
||||
public function city(string $ipAddress = 'me'): City
|
||||
{
|
||||
@ -165,6 +164,8 @@ class Client implements ProviderInterface
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent class to the above exceptions. It
|
||||
* will be thrown directly if a 200 status code is returned but
|
||||
* the body is invalid.
|
||||
* @throws \InvalidArgumentException if something other than a single IP address or "me" is
|
||||
* passed to the method
|
||||
*/
|
||||
public function country(string $ipAddress = 'me'): Country
|
||||
{
|
||||
@ -195,6 +196,8 @@ class Client implements ProviderInterface
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly
|
||||
* if a 200 status code is returned but the body is invalid.
|
||||
* @throws \InvalidArgumentException if something other than a single IP address or "me" is
|
||||
* passed to the method
|
||||
*/
|
||||
public function insights(string $ipAddress = 'me'): Insights
|
||||
{
|
||||
@ -204,6 +207,11 @@ class Client implements ProviderInterface
|
||||
|
||||
private function responseFor(string $endpoint, string $class, string $ipAddress): Country
|
||||
{
|
||||
if ($ipAddress !== 'me' && !filter_var($ipAddress, \FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
$path = implode('/', [self::$basePath, $endpoint, $ipAddress]);
|
||||
|
||||
try {
|
||||
|
32
lib/maxmind/GeoIp2/composer.json
Normal file
32
lib/maxmind/GeoIp2/composer.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "geoip2/geoip2",
|
||||
"description": "MaxMind GeoIP2 PHP API",
|
||||
"keywords": ["geoip", "geoip2", "geolocation", "ip", "maxmind"],
|
||||
"homepage": "https://github.com/maxmind/GeoIP2-php",
|
||||
"type": "library",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "https://www.maxmind.com/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"maxmind-db/reader": "^1.11.1",
|
||||
"maxmind/web-service-common": "~0.8",
|
||||
"php": ">=8.1",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "3.*",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"squizlabs/php_codesniffer": "3.*",
|
||||
"phpstan/phpstan": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GeoIp2\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
1.11.0
|
||||
1.11.1 (2023-12-01)
|
||||
-------------------
|
||||
|
||||
* Resolve warnings when compiling the C extension.
|
||||
* Fix various type issues detected by PHPStan level. Pull request by
|
||||
LauraTaylorUK. GitHub #160.
|
||||
|
||||
1.11.0 (2021-10-18)
|
||||
-------------------
|
||||
|
||||
* Replace runtime define of a constant to facilitate opcache preloading.
|
||||
|
@ -4,15 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use ArgumentCountError;
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
@ -24,14 +19,17 @@ class Reader
|
||||
* @var int
|
||||
*/
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @var int<0, max>
|
||||
*/
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@ -41,18 +39,22 @@ class Reader
|
||||
* @var Decoder
|
||||
*/
|
||||
private $decoder;
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileHandle;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $fileSize;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $ipV4Start;
|
||||
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
@ -65,22 +67,22 @@ class Reader
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct(string $database)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
$fileHandle = @fopen($database, 'rb');
|
||||
if ($fileHandle === false) {
|
||||
throw new InvalidArgumentException(
|
||||
throw new \InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
@ -88,7 +90,7 @@ class Reader
|
||||
|
||||
$fileSize = @filesize($database);
|
||||
if ($fileSize === false) {
|
||||
throw new UnexpectedValueException(
|
||||
throw new \UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
@ -111,18 +113,18 @@ class Reader
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws \BadMethodCallException if this method is called on a closed database
|
||||
* @throws \InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return mixed the record for the IP address
|
||||
*/
|
||||
public function get(string $ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
@ -137,11 +139,11 @@ class Reader
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws \BadMethodCallException if this method is called on a closed database
|
||||
* @throws \InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return array an array where the first element is the record and the
|
||||
* second the network prefix length for the record
|
||||
@ -149,13 +151,13 @@ class Reader
|
||||
public function getWithPrefixLen(string $ipAddress): array
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
@ -172,12 +174,17 @@ class Reader
|
||||
{
|
||||
$packedAddr = @inet_pton($ipAddress);
|
||||
if ($packedAddr === false) {
|
||||
throw new InvalidArgumentException(
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
$rawAddress = unpack('C*', $packedAddr);
|
||||
if ($rawAddress === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned char of the packed in_addr representation.'
|
||||
);
|
||||
}
|
||||
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
|
||||
@ -194,7 +201,7 @@ class Reader
|
||||
$node = $this->ipV4Start;
|
||||
}
|
||||
} elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
|
||||
throw new InvalidArgumentException(
|
||||
throw new \InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. ' IPv6 address in an IPv4-only database.'
|
||||
);
|
||||
@ -245,7 +252,13 @@ class Reader
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
[, $node] = unpack('N', "\x00" . $bytes);
|
||||
$rc = unpack('N', "\x00" . $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
@ -256,13 +269,25 @@ class Reader
|
||||
} else {
|
||||
$middle = 0x0F & \ord($bytes[0]);
|
||||
}
|
||||
[, $node] = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
$rc = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
[, $node] = unpack('N', $bytes);
|
||||
$rc = unpack('N', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack the unsigned long of the node.'
|
||||
);
|
||||
}
|
||||
[, $node] = $rc;
|
||||
|
||||
return $node;
|
||||
|
||||
@ -301,6 +326,11 @@ class Reader
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
if ($fstat === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
"Error getting file information ($filename)."
|
||||
);
|
||||
}
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
@ -325,15 +355,15 @@ class Reader
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if arguments are passed to the method
|
||||
* @throws BadMethodCallException if the database has been closed
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method
|
||||
* @throws \BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata(): Metadata
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
@ -341,7 +371,7 @@ class Reader
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
@ -352,19 +382,19 @@ class Reader
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
* @throws \Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
use RuntimeException;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
@ -13,20 +12,19 @@ class Decoder
|
||||
* @var resource
|
||||
*/
|
||||
private $fileStream;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $pointerBase;
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $pointerBaseByteSize;
|
||||
|
||||
/**
|
||||
* This is only used for unit testing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $pointerTestHack;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@ -44,8 +42,8 @@ class Decoder
|
||||
private const _UINT64 = 9;
|
||||
private const _UINT128 = 10;
|
||||
private const _ARRAY = 11;
|
||||
private const _CONTAINER = 12;
|
||||
private const _END_MARKER = 13;
|
||||
// 12 is the container type
|
||||
// 13 is the end marker type
|
||||
private const _BOOLEAN = 14;
|
||||
private const _FLOAT = 15;
|
||||
|
||||
@ -60,7 +58,6 @@ class Decoder
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
|
||||
$this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
@ -111,6 +108,9 @@ class Decoder
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int<0, max> $size
|
||||
*/
|
||||
private function decodeByType(int $type, int $offset, int $size): array
|
||||
{
|
||||
switch ($type) {
|
||||
@ -188,7 +188,13 @@ class Decoder
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $double] = unpack('E', $bytes);
|
||||
$rc = unpack('E', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a double value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $double] = $rc;
|
||||
|
||||
return $double;
|
||||
}
|
||||
@ -197,7 +203,13 @@ class Decoder
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $float] = unpack('G', $bytes);
|
||||
$rc = unpack('G', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a float value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $float] = $rc;
|
||||
|
||||
return $float;
|
||||
}
|
||||
@ -224,7 +236,13 @@ class Decoder
|
||||
);
|
||||
}
|
||||
|
||||
[, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
$rc = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack a 32bit integer value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $int] = $rc;
|
||||
|
||||
return $int;
|
||||
}
|
||||
@ -247,19 +265,31 @@ class Decoder
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
$offset += $pointerSize;
|
||||
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = unpack('n', $packed);
|
||||
$rc = unpack('n', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes (pointerSize is 1).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$rc = unpack('N', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes (pointerSize is 2).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
|
||||
break;
|
||||
@ -269,7 +299,13 @@ class Decoder
|
||||
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$rc = unpack('N', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes (pointerSize is 3).'
|
||||
);
|
||||
}
|
||||
[, $pointer] = $rc;
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
|
||||
break;
|
||||
@ -284,7 +320,7 @@ class Decoder
|
||||
if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
|
||||
$pointer = $pointerOffset + $pointerBase;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
throw new \RuntimeException(
|
||||
'The database offset is too large to be represented on your platform.'
|
||||
);
|
||||
}
|
||||
@ -307,32 +343,39 @@ class Decoder
|
||||
return 0;
|
||||
}
|
||||
|
||||
$integer = 0;
|
||||
|
||||
// PHP integers are signed. PHP_INT_SIZE - 1 is the number of
|
||||
// complete bytes that can be converted to an integer. However,
|
||||
// we can convert another byte if the leading bit is zero.
|
||||
$useRealInts = $byteLength <= \PHP_INT_SIZE - 1
|
||||
|| ($byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0);
|
||||
|
||||
if ($useRealInts) {
|
||||
$integer = 0;
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
$integer = ($integer << 8) + $part;
|
||||
}
|
||||
|
||||
return $integer;
|
||||
}
|
||||
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
$integerAsString = '0';
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($useRealInts) {
|
||||
$integer = ($integer << 8) + $part;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul((string) $integer, '256'), $part));
|
||||
if (\extension_loaded('gmp')) {
|
||||
$integerAsString = gmp_strval(gmp_add(gmp_mul($integerAsString, '256'), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul((string) $integer, '256'), (string) $part);
|
||||
$integerAsString = bcadd(bcmul($integerAsString, '256'), (string) $part);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
throw new \RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $integer;
|
||||
return $integerAsString;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte(int $ctrlByte, int $offset): array
|
||||
@ -349,10 +392,22 @@ class Decoder
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
[, $adjust] = unpack('n', $bytes);
|
||||
$rc = unpack('n', $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $adjust] = $rc;
|
||||
$size = 285 + $adjust;
|
||||
} else {
|
||||
[, $adjust] = unpack('N', "\x00" . $bytes);
|
||||
$rc = unpack('N', "\x00" . $bytes);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned long value from the given bytes.'
|
||||
);
|
||||
}
|
||||
[, $adjust] = $rc;
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
|
||||
@ -368,7 +423,13 @@ class Decoder
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
$rc = unpack('v', $packed);
|
||||
if ($rc === false) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Could not unpack an unsigned short value from the given bytes.'
|
||||
);
|
||||
}
|
||||
|
||||
return $testint === current(unpack('v', $packed));
|
||||
return $testint === current($rc);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends Exception
|
||||
{
|
||||
}
|
||||
// phpcs:disable
|
||||
class InvalidDatabaseException extends \Exception {}
|
||||
|
@ -4,8 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use ArgumentCountError;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*/
|
||||
@ -18,6 +16,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMajorVersion;
|
||||
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the minor version number
|
||||
* for the database's binary format.
|
||||
@ -25,6 +24,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMinorVersion;
|
||||
|
||||
/**
|
||||
* This is an unsigned 64-bit integer that contains the database build
|
||||
* timestamp as a Unix epoch value.
|
||||
@ -32,6 +32,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $buildEpoch;
|
||||
|
||||
/**
|
||||
* This is a string that indicates the structure of each data record
|
||||
* associated with an IP address. The actual definition of these
|
||||
@ -40,6 +41,7 @@ class Metadata
|
||||
* @var string
|
||||
*/
|
||||
public $databaseType;
|
||||
|
||||
/**
|
||||
* This key will always point to a map (associative array). The keys of
|
||||
* that map will be language codes, and the values will be a description
|
||||
@ -49,6 +51,7 @@ class Metadata
|
||||
* @var array
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* This is an unsigned 16-bit integer which is always 4 or 6. It indicates
|
||||
* whether the database contains IPv4 or IPv6 address data.
|
||||
@ -56,6 +59,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $ipVersion;
|
||||
|
||||
/**
|
||||
* An array of strings, each of which is a language code. A given record
|
||||
* may contain data items that have been localized to some or all of
|
||||
@ -64,10 +68,12 @@ class Metadata
|
||||
* @var array
|
||||
*/
|
||||
public $languages;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $nodeByteSize;
|
||||
|
||||
/**
|
||||
* This is an unsigned 32-bit integer indicating the number of nodes in
|
||||
* the search tree.
|
||||
@ -75,6 +81,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $nodeCount;
|
||||
|
||||
/**
|
||||
* This is an unsigned 16-bit integer. It indicates the number of bits in a
|
||||
* record in the search tree. Note that each node consists of two records.
|
||||
@ -82,6 +89,7 @@ class Metadata
|
||||
* @var int
|
||||
*/
|
||||
public $recordSize;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@ -90,7 +98,7 @@ class Metadata
|
||||
public function __construct(array $metadata)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
throw new \ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ namespace MaxMind\Db\Reader;
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param resource $stream
|
||||
* @param resource $stream
|
||||
* @param int<0, max> $numberOfBytes
|
||||
*/
|
||||
public static function read($stream, int $offset, int $numberOfBytes): string
|
||||
{
|
||||
|
@ -132,7 +132,7 @@ make test
|
||||
sudo make install
|
||||
```
|
||||
|
||||
You then must load your extension. The recommend method is to add the
|
||||
You then must load your extension. The recommended method is to add the
|
||||
following to your `php.ini` file:
|
||||
|
||||
```
|
||||
@ -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-2020 by MaxMind, Inc.
|
||||
This software is Copyright (c) 2014-2023 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
||||
|
@ -35,7 +35,7 @@ function mmdb_autoload($class): void
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
// and finally, add the PHP file extension to the result.
|
||||
$path = $path . '.php';
|
||||
$path .= '.php';
|
||||
|
||||
// $path should now contain the path to a PHP file defining $class
|
||||
if (file_exists($path)) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
"ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-maxminddb": "<1.10.1,>=2.0.0"
|
||||
"ext-maxminddb": "<1.11.1,>=2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "3.*",
|
||||
|
@ -28,6 +28,11 @@ mv GeoIP2-php-X.Y.Z/src/ /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/src/MaxMind/ /path/to/moodle/lib/maxmind/MaxMind/
|
||||
|
||||
4) Update other MaxMind related files:
|
||||
mv GeoIP2-php-X.Y.Z/CHANGELOG.md /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv GeoIP2-php-X.Y.Z/README.md /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv GeoIP2-php-X.Y.Z/composer.json /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv GeoIP2-php-X.Y.Z/LICENSE /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/LICENSE /path/to/moodle/lib/maxmind/MaxMind/
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/CHANGELOG.md /path/to/moodle/lib/maxmind/MaxMind/
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/README.md /path/to/moodle/lib/maxmind/MaxMind/
|
||||
|
@ -388,7 +388,7 @@ All rights reserved.</copyright>
|
||||
<location>maxmind/GeoIp2</location>
|
||||
<name>GeoIP2 PHP API</name>
|
||||
<description>Library for processing of GeoIP data files.</description>
|
||||
<version>2.13.0</version>
|
||||
<version>3.0.0</version>
|
||||
<license>Apache</license>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
<repository>https://github.com/maxmind/GeoIP2-php</repository>
|
||||
@ -400,7 +400,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.11.0</version>
|
||||
<version>1.11.1</version>
|
||||
<license>Apache</license>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
<repository>https://github.com/maxmind/MaxMind-DB-Reader-php/</repository>
|
||||
|
Loading…
x
Reference in New Issue
Block a user