mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 04:52:36 +02:00
MDL-70303 libraries: upgrade GeoIP to 2.11.0 and MaxMind DB to 1.9.0
This commit is contained in:
parent
c381757f2a
commit
23b681c7b5
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Database;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
@ -48,8 +50,8 @@ class Reader implements ProviderInterface
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function __construct(
|
||||
$filename,
|
||||
$locales = ['en']
|
||||
string $filename,
|
||||
array $locales = ['en']
|
||||
) {
|
||||
$this->dbReader = new DbReader($filename);
|
||||
$this->dbType = $this->dbReader->metadata()->databaseType;
|
||||
@ -65,10 +67,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\City
|
||||
*/
|
||||
public function city($ipAddress)
|
||||
public function city(string $ipAddress): \GeoIp2\Model\City
|
||||
{
|
||||
return $this->modelFor('City', 'City', $ipAddress);
|
||||
}
|
||||
@ -82,10 +82,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\Country
|
||||
*/
|
||||
public function country($ipAddress)
|
||||
public function country(string $ipAddress): \GeoIp2\Model\Country
|
||||
{
|
||||
return $this->modelFor('Country', 'Country', $ipAddress);
|
||||
}
|
||||
@ -99,10 +97,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\AnonymousIp
|
||||
*/
|
||||
public function anonymousIp($ipAddress)
|
||||
public function anonymousIp(string $ipAddress): \GeoIp2\Model\AnonymousIp
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'AnonymousIp',
|
||||
@ -120,10 +116,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\Asn
|
||||
*/
|
||||
public function asn($ipAddress)
|
||||
public function asn(string $ipAddress): \GeoIp2\Model\Asn
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'Asn',
|
||||
@ -141,10 +135,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\ConnectionType
|
||||
*/
|
||||
public function connectionType($ipAddress)
|
||||
public function connectionType(string $ipAddress): \GeoIp2\Model\ConnectionType
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'ConnectionType',
|
||||
@ -162,10 +154,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\Domain
|
||||
*/
|
||||
public function domain($ipAddress)
|
||||
public function domain(string $ipAddress): \GeoIp2\Model\Domain
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'Domain',
|
||||
@ -183,10 +173,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\Enterprise
|
||||
*/
|
||||
public function enterprise($ipAddress)
|
||||
public function enterprise(string $ipAddress): \GeoIp2\Model\Enterprise
|
||||
{
|
||||
return $this->modelFor('Enterprise', 'Enterprise', $ipAddress);
|
||||
}
|
||||
@ -200,10 +188,8 @@ class Reader implements ProviderInterface
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*
|
||||
* @return \GeoIp2\Model\Isp
|
||||
*/
|
||||
public function isp($ipAddress)
|
||||
public function isp(string $ipAddress): \GeoIp2\Model\Isp
|
||||
{
|
||||
return $this->flatModelFor(
|
||||
'Isp',
|
||||
@ -212,7 +198,7 @@ class Reader implements ProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
private function modelFor($class, $type, $ipAddress)
|
||||
private function modelFor(string $class, string $type, string $ipAddress)
|
||||
{
|
||||
list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
@ -224,7 +210,7 @@ class Reader implements ProviderInterface
|
||||
return new $class($record, $this->locales);
|
||||
}
|
||||
|
||||
private function flatModelFor($class, $type, $ipAddress)
|
||||
private function flatModelFor(string $class, string $type, string $ipAddress)
|
||||
{
|
||||
list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress);
|
||||
|
||||
@ -235,7 +221,7 @@ class Reader implements ProviderInterface
|
||||
return new $class($record);
|
||||
}
|
||||
|
||||
private function getRecord($class, $type, $ipAddress)
|
||||
private function getRecord(string $class, string $type, string $ipAddress): array
|
||||
{
|
||||
if (strpos($this->dbType, $type) === false) {
|
||||
$method = lcfirst($class);
|
||||
@ -272,7 +258,7 @@ class Reader implements ProviderInterface
|
||||
*
|
||||
* @return \MaxMind\Db\Reader\Metadata object for the database
|
||||
*/
|
||||
public function metadata()
|
||||
public function metadata(): \MaxMind\Db\Reader\Metadata
|
||||
{
|
||||
return $this->dbReader->metadata();
|
||||
}
|
||||
@ -280,7 +266,7 @@ class Reader implements ProviderInterface
|
||||
/**
|
||||
* Closes the GeoIP2 database and returns the resources to the system.
|
||||
*/
|
||||
public function close()
|
||||
public function close(): void
|
||||
{
|
||||
$this->dbReader->close();
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
@ -13,9 +15,9 @@ class HttpException extends GeoIp2Exception
|
||||
public $uri;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
$httpStatus,
|
||||
$uri,
|
||||
string $message,
|
||||
int $httpStatus,
|
||||
string $uri,
|
||||
\Exception $previous = null
|
||||
) {
|
||||
$this->uri = $uri;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
@ -14,10 +16,10 @@ class InvalidRequestException extends HttpException
|
||||
public $error;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
$error,
|
||||
$httpStatus,
|
||||
$uri,
|
||||
string $message,
|
||||
string $error,
|
||||
int $httpStatus,
|
||||
string $uri,
|
||||
\Exception $previous = null
|
||||
) {
|
||||
$this->error = $error;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
@ -11,20 +13,16 @@ abstract class AbstractModel implements \JsonSerializable
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
$this->raw = $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $field
|
||||
*/
|
||||
protected function get($field)
|
||||
protected function get(string $field)
|
||||
{
|
||||
if (isset($this->raw[$field])) {
|
||||
return $this->raw[$field];
|
||||
@ -38,10 +36,8 @@ abstract class AbstractModel implements \JsonSerializable
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __get($attr)
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr !== 'instance' && property_exists($this, $attr)) {
|
||||
return $this->$attr;
|
||||
@ -52,15 +48,13 @@ abstract class AbstractModel implements \JsonSerializable
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __isset($attr)
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
return $attr !== 'instance' && isset($this->$attr);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->raw;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -17,6 +19,8 @@ use GeoIp2\Util;
|
||||
* 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
|
||||
@ -31,16 +35,15 @@ class AnonymousIp extends AbstractModel
|
||||
protected $isAnonymousVpn;
|
||||
protected $isHostingProvider;
|
||||
protected $isPublicProxy;
|
||||
protected $isResidentialProxy;
|
||||
protected $isTorExitNode;
|
||||
protected $ipAddress;
|
||||
protected $network;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
@ -48,6 +51,7 @@ class AnonymousIp extends AbstractModel
|
||||
$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->ipAddress = $ipAddress;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -27,10 +29,8 @@ class Asn extends AbstractModel
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
@ -48,11 +50,8 @@ class City extends Country
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
* @param mixed $locales
|
||||
*/
|
||||
public function __construct($raw, $locales = ['en'])
|
||||
public function __construct(array $raw, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($raw, $locales);
|
||||
|
||||
@ -63,7 +62,7 @@ class City extends Country
|
||||
$this->createSubdivisions($raw, $locales);
|
||||
}
|
||||
|
||||
private function createSubdivisions($raw, $locales)
|
||||
private function createSubdivisions(array $raw, array $locales): void
|
||||
{
|
||||
if (!isset($raw['subdivisions'])) {
|
||||
return;
|
||||
@ -79,10 +78,8 @@ class City extends Country
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __get($attr)
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
return $this->$attr();
|
||||
@ -93,10 +90,8 @@ class City extends Country
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __isset($attr)
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
// We always return a mostSpecificSubdivision, even if it is the
|
||||
@ -107,7 +102,7 @@ class City extends Country
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
|
||||
private function mostSpecificSubdivision()
|
||||
private function mostSpecificSubdivision(): \GeoIp2\Record\Subdivision
|
||||
{
|
||||
return empty($this->subdivisions) ?
|
||||
new \GeoIp2\Record\Subdivision([], $this->locales) :
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -24,10 +26,8 @@ class ConnectionType extends AbstractModel
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
@ -39,11 +41,8 @@ class Country extends AbstractModel
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
* @param mixed $locales
|
||||
*/
|
||||
public function __construct($raw, $locales = ['en'])
|
||||
public function __construct(array $raw, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -24,10 +26,8 @@ class Domain extends AbstractModel
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Model;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -33,10 +35,8 @@ class Isp extends AbstractModel
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $raw
|
||||
*/
|
||||
public function __construct($raw)
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2;
|
||||
|
||||
interface ProviderInterface
|
||||
@ -9,12 +11,12 @@ interface ProviderInterface
|
||||
*
|
||||
* @return \GeoIp2\Model\Country a Country model for the requested IP address
|
||||
*/
|
||||
public function country($ipAddress);
|
||||
public function country(string $ipAddress): \GeoIp2\Model\Country;
|
||||
|
||||
/**
|
||||
* @param string $ipAddress an IPv4 or IPv6 address to lookup
|
||||
*
|
||||
* @return \GeoIp2\Model\City a City model for the requested IP address
|
||||
*/
|
||||
public function city($ipAddress);
|
||||
public function city(string $ipAddress): \GeoIp2\Model\City;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
@ -8,11 +10,8 @@ abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $record
|
||||
* @param mixed $locales
|
||||
*/
|
||||
public function __construct($record, $locales = ['en'])
|
||||
public function __construct(?array $record, array $locales = ['en'])
|
||||
{
|
||||
$this->locales = $locales;
|
||||
parent::__construct($record);
|
||||
@ -20,10 +19,8 @@ abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __get($attr)
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->name();
|
||||
@ -34,26 +31,24 @@ abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __isset($attr)
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->firstSetNameLocale() === null ? false : true;
|
||||
return $this->firstSetNameLocale() !== null;
|
||||
}
|
||||
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
|
||||
private function name()
|
||||
private function name(): ?string
|
||||
{
|
||||
$locale = $this->firstSetNameLocale();
|
||||
|
||||
return $locale === null ? null : $this->names[$locale];
|
||||
}
|
||||
|
||||
private function firstSetNameLocale()
|
||||
private function firstSetNameLocale(): ?string
|
||||
{
|
||||
foreach ($this->locales as $locale) {
|
||||
if (isset($this->names[$locale])) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
abstract class AbstractRecord implements \JsonSerializable
|
||||
@ -8,20 +10,16 @@ abstract class AbstractRecord implements \JsonSerializable
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $record
|
||||
*/
|
||||
public function __construct($record)
|
||||
public function __construct(?array $record)
|
||||
{
|
||||
$this->record = isset($record) ? $record : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $attr
|
||||
*/
|
||||
public function __get($attr)
|
||||
public function __get(string $attr)
|
||||
{
|
||||
// XXX - kind of ugly but greatly reduces boilerplate code
|
||||
$key = $this->attributeToKey($attr);
|
||||
@ -38,23 +36,23 @@ abstract class AbstractRecord implements \JsonSerializable
|
||||
throw new \RuntimeException("Unknown attribute: $attr");
|
||||
}
|
||||
|
||||
public function __isset($attr)
|
||||
public function __isset(string $attr): bool
|
||||
{
|
||||
return $this->validAttribute($attr) &&
|
||||
isset($this->record[$this->attributeToKey($attr)]);
|
||||
}
|
||||
|
||||
private function attributeToKey($attr)
|
||||
private function attributeToKey(string $attr): string
|
||||
{
|
||||
return strtolower(preg_replace('/([A-Z])/', '_\1', $attr));
|
||||
}
|
||||
|
||||
private function validAttribute($attr)
|
||||
private function validAttribute(string $attr): bool
|
||||
{
|
||||
return \in_array($attr, $this->validAttributes, true);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): ?array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\Record;
|
||||
|
||||
use GeoIp2\Util;
|
||||
@ -56,6 +58,9 @@ use GeoIp2\Util;
|
||||
* @property-read bool $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy. This property is only available from GeoIP2 Precision
|
||||
* 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 Precision 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
|
||||
@ -120,6 +125,7 @@ class Traits extends AbstractRecord
|
||||
'isLegitimateProxy',
|
||||
'isp',
|
||||
'isPublicProxy',
|
||||
'isResidentialProxy',
|
||||
'isSatelliteProvider',
|
||||
'isTorExitNode',
|
||||
'network',
|
||||
@ -129,7 +135,7 @@ class Traits extends AbstractRecord
|
||||
'userType',
|
||||
];
|
||||
|
||||
public function __construct($record)
|
||||
public function __construct(?array $record)
|
||||
{
|
||||
if (!isset($record['network']) && isset($record['ip_address']) && isset($record['prefix_len'])) {
|
||||
$record['network'] = Util::cidr($record['ip_address'], $record['prefix_len']);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2;
|
||||
|
||||
class Util
|
||||
@ -10,11 +12,8 @@ class Util
|
||||
*
|
||||
* @internal
|
||||
* @ignore
|
||||
*
|
||||
* @param mixed $ipAddress
|
||||
* @param mixed $prefixLen
|
||||
*/
|
||||
public static function cidr($ipAddress, $prefixLen)
|
||||
public static function cidr(string $ipAddress, int $prefixLen): string
|
||||
{
|
||||
$ipBytes = inet_pton($ipAddress);
|
||||
$networkBytes = str_repeat("\0", \strlen($ipBytes));
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GeoIp2\WebService;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
@ -47,7 +49,7 @@ class Client implements ProviderInterface
|
||||
private $client;
|
||||
private static $basePath = '/geoip/v2.1';
|
||||
|
||||
const VERSION = 'v2.10.0';
|
||||
const VERSION = 'v2.11.0';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -65,10 +67,10 @@ class Client implements ProviderInterface
|
||||
* `http://username:password@127.0.0.1:10`.
|
||||
*/
|
||||
public function __construct(
|
||||
$accountId,
|
||||
$licenseKey,
|
||||
$locales = ['en'],
|
||||
$options = []
|
||||
int $accountId,
|
||||
string $licenseKey,
|
||||
array $locales = ['en'],
|
||||
array $options = []
|
||||
) {
|
||||
$this->locales = $locales;
|
||||
|
||||
@ -87,7 +89,7 @@ class Client implements ProviderInterface
|
||||
$this->client = new WsClient($accountId, $licenseKey, $options);
|
||||
}
|
||||
|
||||
private function userAgent()
|
||||
private function userAgent(): string
|
||||
{
|
||||
return 'GeoIP2-API/' . self::VERSION;
|
||||
}
|
||||
@ -115,10 +117,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.
|
||||
*
|
||||
* @return \GeoIp2\Model\City
|
||||
*/
|
||||
public function city($ipAddress = 'me')
|
||||
public function city(string $ipAddress = 'me'): \GeoIp2\Model\City
|
||||
{
|
||||
return $this->responseFor('city', 'City', $ipAddress);
|
||||
}
|
||||
@ -146,10 +146,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.
|
||||
*
|
||||
* @return \GeoIp2\Model\Country
|
||||
*/
|
||||
public function country($ipAddress = 'me')
|
||||
public function country(string $ipAddress = 'me'): \GeoIp2\Model\Country
|
||||
{
|
||||
return $this->responseFor('country', 'Country', $ipAddress);
|
||||
}
|
||||
@ -177,15 +175,13 @@ 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.
|
||||
*
|
||||
* @return \GeoIp2\Model\Insights
|
||||
*/
|
||||
public function insights($ipAddress = 'me')
|
||||
public function insights(string $ipAddress = 'me'): \GeoIp2\Model\Insights
|
||||
{
|
||||
return $this->responseFor('insights', 'Insights', $ipAddress);
|
||||
}
|
||||
|
||||
private function responseFor($endpoint, $class, $ipAddress)
|
||||
private function responseFor(string $endpoint, string $class, string $ipAddress)
|
||||
{
|
||||
$path = implode('/', [self::$basePath, $endpoint, $ipAddress]);
|
||||
|
||||
|
@ -1,6 +1,45 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
1.9.0 (2021-01-07)
|
||||
------------------
|
||||
|
||||
* The `maxminddb` extension is now buildable on Windows. Pull request
|
||||
by Jan Ehrhardt. GitHub #115.
|
||||
|
||||
1.8.0 (2020-10-01)
|
||||
------------------
|
||||
|
||||
* Fixes for PHP 8.0. Pull Request by Remi Collet. GitHub #108.
|
||||
|
||||
1.7.0 (2020-08-07)
|
||||
------------------
|
||||
|
||||
* IMPORTANT: PHP 7.2 or greater is now required.
|
||||
* The extension no longer depends on the pure PHP classes in
|
||||
`maxmind-db/reader`. You can use it independently.
|
||||
* Type hints have been added to both the pure PHP implementation
|
||||
and the extension.
|
||||
* The `metadata` method on the reader now returns a new copy of the
|
||||
metadata object rather than the actual object used by the reader.
|
||||
* Work around PHP `is_readable()` bug. Reported by Ben Roberts. GitHub
|
||||
#92.
|
||||
* This is the first release of the extension as a PECL package.
|
||||
GitHub #34.
|
||||
|
||||
1.6.0 (2019-12-19)
|
||||
------------------
|
||||
|
||||
* 1.5.0 and 1.5.1 contained a possible memory corruptions when using
|
||||
`getWithPrefixLen`. This has been fixed. Reported by proton-ab.
|
||||
GitHub #96.
|
||||
* The `composer.json` file now conflicts with all versions of the
|
||||
`maxminddb` C extension less than the Composer version. This is to
|
||||
reduce the chance of having an older, conflicting version of the
|
||||
extension installed. You will need to upgrade the extension before
|
||||
running `composer update`. Pull request by Benoît Burnichon. GitHub
|
||||
#97.
|
||||
|
||||
1.5.1 (2019-12-12)
|
||||
------------------
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use ArgumentCountError;
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
@ -17,15 +20,42 @@ use UnexpectedValueException;
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KB
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KiB
|
||||
|
||||
/**
|
||||
* @var Decoder
|
||||
*/
|
||||
private $decoder;
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileHandle;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $fileSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $ipV4Start;
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
private $metadata;
|
||||
|
||||
/**
|
||||
@ -35,40 +65,38 @@ class Reader
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct($database)
|
||||
public function __construct(string $database)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'The constructor takes exactly one argument.'
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_readable($database)) {
|
||||
$fileHandle = @fopen($database, 'rb');
|
||||
if ($fileHandle === false) {
|
||||
throw new InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
$this->fileHandle = @fopen($database, 'rb');
|
||||
if ($this->fileHandle === false) {
|
||||
throw new InvalidArgumentException(
|
||||
"Error opening \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = @filesize($database);
|
||||
if ($this->fileSize === false) {
|
||||
$this->fileHandle = $fileHandle;
|
||||
|
||||
$fileSize = @filesize($database);
|
||||
if ($fileSize === false) {
|
||||
throw new UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = $fileSize;
|
||||
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
list($metadataArray) = $metadataDecoder->decode($start);
|
||||
[$metadataArray] = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder(
|
||||
$this->fileHandle,
|
||||
@ -91,14 +119,14 @@ class Reader
|
||||
*
|
||||
* @return mixed the record for the IP address
|
||||
*/
|
||||
public function get($ipAddress)
|
||||
public function get(string $ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
list($record) = $this->getWithPrefixLen($ipAddress);
|
||||
[$record] = $this->getWithPrefixLen($ipAddress);
|
||||
|
||||
return $record;
|
||||
}
|
||||
@ -118,11 +146,11 @@ class Reader
|
||||
* @return array an array where the first element is the record and the
|
||||
* second the network prefix length for the record
|
||||
*/
|
||||
public function getWithPrefixLen($ipAddress)
|
||||
public function getWithPrefixLen(string $ipAddress): array
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
@ -132,13 +160,7 @@ class Reader
|
||||
);
|
||||
}
|
||||
|
||||
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
|
||||
throw new InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
list($pointer, $prefixLen) = $this->findAddressInTree($ipAddress);
|
||||
[$pointer, $prefixLen] = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer === 0) {
|
||||
return [null, $prefixLen];
|
||||
}
|
||||
@ -146,9 +168,16 @@ class Reader
|
||||
return [$this->resolveDataPointer($pointer), $prefixLen];
|
||||
}
|
||||
|
||||
private function findAddressInTree($ipAddress)
|
||||
private function findAddressInTree(string $ipAddress): array
|
||||
{
|
||||
$rawAddress = unpack('C*', inet_pton($ipAddress));
|
||||
$packedAddr = @inet_pton($ipAddress);
|
||||
if ($packedAddr === false) {
|
||||
throw new InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
$rawAddress = unpack('C*', $packedAddr);
|
||||
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
|
||||
@ -186,10 +215,12 @@ class Reader
|
||||
// Record is a data pointer
|
||||
return [$node, $i];
|
||||
}
|
||||
throw new InvalidDatabaseException('Something bad happened');
|
||||
throw new InvalidDatabaseException(
|
||||
'Invalid or corrupt database. Maximum search depth reached without finding a leaf node'
|
||||
);
|
||||
}
|
||||
|
||||
private function ipV4StartNode()
|
||||
private function ipV4StartNode(): int
|
||||
{
|
||||
// If we have an IPv4 database, the start node is the first node
|
||||
if ($this->metadata->ipVersion === 4) {
|
||||
@ -205,14 +236,14 @@ class Reader
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function readNode($nodeNumber, $index)
|
||||
private function readNode(int $nodeNumber, int $index): int
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
list(, $node) = unpack('N', "\x00" . $bytes);
|
||||
[, $node] = unpack('N', "\x00" . $bytes);
|
||||
|
||||
return $node;
|
||||
case 28:
|
||||
@ -222,12 +253,12 @@ class Reader
|
||||
} else {
|
||||
$middle = 0x0F & \ord($bytes[0]);
|
||||
}
|
||||
list(, $node) = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
[, $node] = unpack('N', \chr($middle) . substr($bytes, $index, 3));
|
||||
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
list(, $node) = unpack('N', $bytes);
|
||||
[, $node] = unpack('N', $bytes);
|
||||
|
||||
return $node;
|
||||
default:
|
||||
@ -238,7 +269,10 @@ class Reader
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveDataPointer($pointer)
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function resolveDataPointer(int $pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount
|
||||
+ $this->metadata->searchTreeSize;
|
||||
@ -248,7 +282,7 @@ class Reader
|
||||
);
|
||||
}
|
||||
|
||||
list($data) = $this->decoder->decode($resolved);
|
||||
[$data] = $this->decoder->decode($resolved);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@ -258,7 +292,7 @@ class Reader
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart($filename)
|
||||
private function findMetadataStart(string $filename): int
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
@ -290,11 +324,11 @@ class Reader
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata()
|
||||
public function metadata(): Metadata
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new InvalidArgumentException(
|
||||
'Method takes no arguments.'
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
@ -306,7 +340,7 @@ class Reader
|
||||
);
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
return clone $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,8 +349,14 @@ class Reader
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close()
|
||||
public function close(): void
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
@ -14,50 +16,53 @@ use RuntimeException;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileStream;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $pointerBase;
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $pointerBaseByteSize;
|
||||
// This is only used for unit testing
|
||||
/**
|
||||
* This is only used for unit testing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $pointerTestHack;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $switchByteOrder;
|
||||
|
||||
/** @ignore */
|
||||
const _EXTENDED = 0;
|
||||
/** @ignore */
|
||||
const _POINTER = 1;
|
||||
/** @ignore */
|
||||
const _UTF8_STRING = 2;
|
||||
/** @ignore */
|
||||
const _DOUBLE = 3;
|
||||
/** @ignore */
|
||||
const _BYTES = 4;
|
||||
/** @ignore */
|
||||
const _UINT16 = 5;
|
||||
/** @ignore */
|
||||
const _UINT32 = 6;
|
||||
/** @ignore */
|
||||
const _MAP = 7;
|
||||
/** @ignore */
|
||||
const _INT32 = 8;
|
||||
/** @ignore */
|
||||
const _UINT64 = 9;
|
||||
/** @ignore */
|
||||
const _UINT128 = 10;
|
||||
/** @ignore */
|
||||
const _ARRAY = 11;
|
||||
/** @ignore */
|
||||
const _CONTAINER = 12;
|
||||
/** @ignore */
|
||||
const _END_MARKER = 13;
|
||||
/** @ignore */
|
||||
const _BOOLEAN = 14;
|
||||
/** @ignore */
|
||||
const _FLOAT = 15;
|
||||
private const _EXTENDED = 0;
|
||||
private const _POINTER = 1;
|
||||
private const _UTF8_STRING = 2;
|
||||
private const _DOUBLE = 3;
|
||||
private const _BYTES = 4;
|
||||
private const _UINT16 = 5;
|
||||
private const _UINT32 = 6;
|
||||
private const _MAP = 7;
|
||||
private const _INT32 = 8;
|
||||
private const _UINT64 = 9;
|
||||
private const _UINT128 = 10;
|
||||
private const _ARRAY = 11;
|
||||
private const _CONTAINER = 12;
|
||||
private const _END_MARKER = 13;
|
||||
private const _BOOLEAN = 14;
|
||||
private const _FLOAT = 15;
|
||||
|
||||
/**
|
||||
* @param resource $fileStream
|
||||
*/
|
||||
public function __construct(
|
||||
$fileStream,
|
||||
$pointerBase = 0,
|
||||
$pointerTestHack = false
|
||||
int $pointerBase = 0,
|
||||
bool $pointerTestHack = false
|
||||
) {
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
@ -68,7 +73,7 @@ class Decoder
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
|
||||
public function decode($offset)
|
||||
public function decode(int $offset): array
|
||||
{
|
||||
$ctrlByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
++$offset;
|
||||
@ -79,14 +84,14 @@ class Decoder
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type === self::_POINTER) {
|
||||
list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
|
||||
[$pointer, $offset] = $this->decodePointer($ctrlByte, $offset);
|
||||
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return [$pointer];
|
||||
}
|
||||
|
||||
list($result) = $this->decode($pointer);
|
||||
[$result] = $this->decode($pointer);
|
||||
|
||||
return [$result, $offset];
|
||||
}
|
||||
@ -108,12 +113,12 @@ class Decoder
|
||||
++$offset;
|
||||
}
|
||||
|
||||
list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
[$size, $offset] = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
private function decodeByType($type, $offset, $size)
|
||||
private function decodeByType(int $type, int $offset, int $size): array
|
||||
{
|
||||
switch ($type) {
|
||||
case self::_MAP:
|
||||
@ -152,7 +157,7 @@ class Decoder
|
||||
}
|
||||
}
|
||||
|
||||
private function verifySize($expected, $actual)
|
||||
private function verifySize(int $expected, int $actual): void
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new InvalidDatabaseException(
|
||||
@ -161,50 +166,42 @@ class Decoder
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeArray($size, $offset)
|
||||
private function decodeArray(int $size, int $offset): array
|
||||
{
|
||||
$array = [];
|
||||
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
array_push($array, $value);
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$array[] = $value;
|
||||
}
|
||||
|
||||
return [$array, $offset];
|
||||
}
|
||||
|
||||
private function decodeBoolean($size)
|
||||
private function decodeBoolean(int $size): bool
|
||||
{
|
||||
return $size === 0 ? false : true;
|
||||
return $size !== 0;
|
||||
}
|
||||
|
||||
private function decodeDouble($bits)
|
||||
private function decodeDouble(string $bytes): float
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
//
|
||||
// We are not using the "E" format as that was only added in
|
||||
// 7.0.15 and 7.1.1. As such, we must switch byte order on
|
||||
// little endian machines.
|
||||
list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
|
||||
[, $double] = unpack('E', $bytes);
|
||||
|
||||
return $double;
|
||||
}
|
||||
|
||||
private function decodeFloat($bits)
|
||||
private function decodeFloat(string $bytes): float
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
//
|
||||
// We are not using the "G" format as that was only added in
|
||||
// 7.0.15 and 7.1.1. As such, we must switch byte order on
|
||||
// little endian machines.
|
||||
list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
|
||||
[, $float] = unpack('G', $bytes);
|
||||
|
||||
return $float;
|
||||
}
|
||||
|
||||
private function decodeInt32($bytes, $size)
|
||||
private function decodeInt32(string $bytes, int $size): int
|
||||
{
|
||||
switch ($size) {
|
||||
case 0:
|
||||
@ -222,25 +219,25 @@ class Decoder
|
||||
);
|
||||
}
|
||||
|
||||
list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
[, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeMap($size, $offset)
|
||||
private function decodeMap(int $size, int $offset): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
list($key, $offset) = $this->decode($offset);
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
[$key, $offset] = $this->decode($offset);
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
|
||||
return [$map, $offset];
|
||||
}
|
||||
|
||||
private function decodePointer($ctrlByte, $offset)
|
||||
private function decodePointer(int $ctrlByte, int $offset): array
|
||||
{
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
@ -250,12 +247,12 @@ class Decoder
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
list(, $pointer) = unpack('n', $packed);
|
||||
[, $pointer] = unpack('n', $packed);
|
||||
$pointer += $this->pointerBase;
|
||||
break;
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
list(, $pointer) = unpack('N', $packed);
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
break;
|
||||
case 3:
|
||||
@ -263,7 +260,7 @@ class Decoder
|
||||
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
list(, $pointer) = unpack('N', $packed);
|
||||
[, $pointer] = unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
break;
|
||||
case 4:
|
||||
@ -278,18 +275,23 @@ class Decoder
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$pointer = gmp_strval(gmp_add($pointerOffset, $this->pointerBase));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$pointer = bcadd($pointerOffset, $this->pointerBase);
|
||||
$pointer = bcadd($pointerOffset, (string) $this->pointerBase);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unexpected pointer size ' . $pointerSize
|
||||
);
|
||||
}
|
||||
|
||||
return [$pointer, $offset];
|
||||
}
|
||||
|
||||
private function decodeUint($bytes, $byteLength)
|
||||
private function decodeUint(string $bytes, int $byteLength)
|
||||
{
|
||||
if ($byteLength === 0) {
|
||||
return 0;
|
||||
@ -304,9 +306,9 @@ class Decoder
|
||||
if ($byteLength <= _MM_MAX_INT_BYTES) {
|
||||
$integer = ($integer << 8) + $part;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul($integer, 256), $part));
|
||||
$integer = gmp_strval(gmp_add(gmp_mul((string) $integer, '256'), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul($integer, 256), $part);
|
||||
$integer = bcadd(bcmul((string) $integer, '256'), (string) $part);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
@ -317,7 +319,7 @@ class Decoder
|
||||
return $integer;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte($ctrlByte, $offset)
|
||||
private function sizeFromCtrlByte(int $ctrlByte, int $offset): array
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
|
||||
@ -331,22 +333,22 @@ class Decoder
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
list(, $adjust) = unpack('n', $bytes);
|
||||
[, $adjust] = unpack('n', $bytes);
|
||||
$size = 285 + $adjust;
|
||||
} elseif ($size > 30) {
|
||||
list(, $adjust) = unpack('N', "\x00" . $bytes);
|
||||
} else {
|
||||
[, $adjust] = unpack('N', "\x00" . $bytes);
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
|
||||
return [$size, $offset + $bytesToRead];
|
||||
}
|
||||
|
||||
private function maybeSwitchByteOrder($bytes)
|
||||
private function maybeSwitchByteOrder(string $bytes): string
|
||||
{
|
||||
return $this->switchByteOrder ? strrev($bytes) : $bytes;
|
||||
}
|
||||
|
||||
private function isPlatformLittleEndian()
|
||||
private function isPlatformLittleEndian(): bool
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
|
@ -1,71 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
use ArgumentCountError;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*
|
||||
* @property int $nodeCount This is an unsigned 32-bit
|
||||
* integer indicating the number of
|
||||
* nodes in the search tree.
|
||||
* @property int $recordSize 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.
|
||||
* @property int $ipVersion This is an unsigned 16-bit
|
||||
* integer which is always 4 or 6.
|
||||
* It indicates whether the database
|
||||
* contains IPv4 or IPv6 address
|
||||
* data.
|
||||
* @property string $databaseType This is a string that indicates
|
||||
* the structure of each data record
|
||||
* associated with an IP address.
|
||||
* The actual definition of these
|
||||
* structures is left up to the
|
||||
* database creator.
|
||||
* @property array $languages 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 these languages. This
|
||||
* may be undefined.
|
||||
* @property int $binaryFormatMajorVersion This is an unsigned 16-bit
|
||||
* integer indicating the major
|
||||
* version number for the database's
|
||||
* binary format.
|
||||
* @property int $binaryFormatMinorVersion This is an unsigned 16-bit
|
||||
* integer indicating the minor
|
||||
* version number for the database's
|
||||
* binary format.
|
||||
* @property int $buildEpoch This is an unsigned 64-bit
|
||||
* integer that contains the
|
||||
* database build timestamp as a
|
||||
* Unix epoch value.
|
||||
* @property array $description 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 in that language as a
|
||||
* UTF-8 string. May be undefined
|
||||
* for some databases.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
private $binaryFormatMajorVersion;
|
||||
private $binaryFormatMinorVersion;
|
||||
private $buildEpoch;
|
||||
private $databaseType;
|
||||
private $description;
|
||||
private $ipVersion;
|
||||
private $languages;
|
||||
private $nodeByteSize;
|
||||
private $nodeCount;
|
||||
private $recordSize;
|
||||
private $searchTreeSize;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the major version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMajorVersion;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the minor version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMinorVersion;
|
||||
/**
|
||||
* This is an unsigned 64-bit integer that contains the database build
|
||||
* timestamp as a Unix epoch value.
|
||||
*
|
||||
* @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
|
||||
* structures is left up to the database creator.
|
||||
*
|
||||
* @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
|
||||
* in that language as a UTF-8 string. May be undefined for some
|
||||
* databases.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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
|
||||
* these languages. This may be undefined.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $languages;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $nodeByteSize;
|
||||
/**
|
||||
* This is an unsigned 32-bit integer indicating the number of nodes in
|
||||
* the search tree.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $recordSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $searchTreeSize;
|
||||
|
||||
public function __construct($metadata)
|
||||
public function __construct(array $metadata)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(
|
||||
sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
|
||||
);
|
||||
}
|
||||
|
||||
$this->binaryFormatMajorVersion =
|
||||
$metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion =
|
||||
@ -80,9 +109,4 @@ class Metadata
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
|
||||
public function __get($var)
|
||||
{
|
||||
return $this->$var;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function read($stream, $offset, $numberOfBytes)
|
||||
/**
|
||||
* @param resource $stream
|
||||
*/
|
||||
public static function read($stream, int $offset, int $numberOfBytes): string
|
||||
{
|
||||
if ($numberOfBytes === 0) {
|
||||
return '';
|
||||
@ -15,7 +20,7 @@ class Util
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if (ftell($stream) - $offset === $numberOfBytes) {
|
||||
if ($value !== false && ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ client API, please see [our support page](https://www.maxmind.com/en/support).
|
||||
|
||||
## Requirements ##
|
||||
|
||||
This library requires PHP 5.6 or greater.
|
||||
This library requires PHP 7.2 or greater.
|
||||
|
||||
The GMP or BCMath extension may be required to read some databases
|
||||
using the pure PHP API.
|
||||
@ -173,6 +173,6 @@ The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## Copyright and License ##
|
||||
|
||||
This software is Copyright (c) 2014-2019 by MaxMind, Inc.
|
||||
This software is Copyright (c) 2014-2020 by MaxMind, Inc.
|
||||
|
||||
This is free software, licensed under the Apache License, Version 2.0.
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* PSR-4 autoloader implementation for the MaxMind\DB namespace.
|
||||
* First we define the 'mmdb_autoload' function, and then we register
|
||||
@ -14,7 +16,7 @@
|
||||
* @param string $class
|
||||
* the name of the class to load
|
||||
*/
|
||||
function mmdb_autoload($class)
|
||||
function mmdb_autoload($class): void
|
||||
{
|
||||
/*
|
||||
* A project-specific mapping between the namespaces and where
|
||||
|
@ -13,18 +13,21 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-maxminddb": "<1.9.0,>=2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "2.*",
|
||||
"phpunit/phpunit": "5.*",
|
||||
"friendsofphp/php-cs-fixer": "*",
|
||||
"phpunit/phpunit": ">=8.0.0,<10.0.0",
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpcov": "^3.0",
|
||||
"phpunit/phpcov": ">=6.0.0",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -16,15 +16,24 @@ Installation
|
||||
------------
|
||||
|
||||
1) Download the latest versions of GeoIP2-php and MaxMind-DB-Reader-php
|
||||
wget https://github.com/maxmind/GeoIP2-php/archive/v2.10.0.zip
|
||||
wget https://github.com/maxmind/MaxMind-DB-Reader-php/archive/v1.5.1.zip
|
||||
wget https://github.com/maxmind/GeoIP2-php/archive/vX.Y.Z.zip
|
||||
wget https://github.com/maxmind/MaxMind-DB-Reader-php/archive/vX.Y.Z.zip
|
||||
|
||||
2) Unzip the archives
|
||||
unzip v2.10.0.zip
|
||||
unzip v1.5.1.zip
|
||||
unzip vX.Y.Z.zip
|
||||
unzip vX.Y.Z.zip
|
||||
|
||||
3) Move the source code directories into place
|
||||
mv GeoIP2-php-2.10.0/src/ /path/to/moodle/lib/maxmind/GeoIp2/
|
||||
mv MaxMind-DB-Reader-php-1.5.1/src/MaxMind/ /path/to/moodle/lib/maxmind/MaxMind/
|
||||
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) Run unit tests on iplookup/tests/geoip_test.php.
|
||||
4) Update other MaxMind related files:
|
||||
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/
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/composer.json /path/to/moodle/lib/maxmind/MaxMind/
|
||||
mv MaxMind-DB-Reader-php-X.Y.Z/autoload.php /path/to/moodle/lib/maxmind/MaxMind/
|
||||
|
||||
5) Run unit tests on iplookup/tests/geoip_test.php.
|
||||
|
||||
6) Update maxmind/GeoIp2 and maxmind/MaxMin versions in lib/thirdpartylibs.xml
|
||||
|
@ -248,13 +248,13 @@
|
||||
<location>maxmind/GeoIp2</location>
|
||||
<name>GeoIP2 PHP API</name>
|
||||
<license>Apache 2.0</license>
|
||||
<version>2.10.0</version>
|
||||
<version>2.11.0</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>maxmind/MaxMind</location>
|
||||
<name>MaxMind DB Reader API</name>
|
||||
<license>Apache 2.0</license>
|
||||
<version>1.5.1</version>
|
||||
<version>1.9.0</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>ltiprovider</location>
|
||||
|
Loading…
x
Reference in New Issue
Block a user