vendor/geoip2/geoip2/src/Database/Reader.php line 69

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace GeoIp2\Database;
  4. use GeoIp2\Exception\AddressNotFoundException;
  5. use GeoIp2\Model\AnonymousIp;
  6. use GeoIp2\Model\Asn;
  7. use GeoIp2\Model\City;
  8. use GeoIp2\Model\ConnectionType;
  9. use GeoIp2\Model\Country;
  10. use GeoIp2\Model\Domain;
  11. use GeoIp2\Model\Enterprise;
  12. use GeoIp2\Model\Isp;
  13. use GeoIp2\ProviderInterface;
  14. use MaxMind\Db\Reader as DbReader;
  15. use MaxMind\Db\Reader\InvalidDatabaseException;
  16. /**
  17.  * Instances of this class provide a reader for the GeoIP2 database format.
  18.  * IP addresses can be looked up using the database specific methods.
  19.  *
  20.  * ## Usage ##
  21.  *
  22.  * The basic API for this class is the same for every database. First, you
  23.  * create a reader object, specifying a file name. You then call the method
  24.  * corresponding to the specific database, passing it the IP address you want
  25.  * to look up.
  26.  *
  27.  * If the request succeeds, the method call will return a model class for
  28.  * the method you called. This model in turn contains multiple record classes,
  29.  * each of which represents part of the data returned by the database. If
  30.  * the database does not contain the requested information, the attributes
  31.  * on the record class will have a `null` value.
  32.  *
  33.  * If the address is not in the database, an
  34.  * {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
  35.  * thrown. If an invalid IP address is passed to one of the methods, a
  36.  * SPL {@link \InvalidArgumentException} will be thrown. If the database is
  37.  * corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
  38.  * will be thrown.
  39.  */
  40. class Reader implements ProviderInterface
  41. {
  42.     private DbReader $dbReader;
  43.     private string $dbType;
  44.     /**
  45.      * @var array<string>
  46.      */
  47.     private array $locales;
  48.     /**
  49.      * Constructor.
  50.      *
  51.      * @param string $filename the path to the GeoIP2 database file
  52.      * @param array  $locales  list of locale codes to use in name property
  53.      *                         from most preferred to least preferred
  54.      *
  55.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  56.      *                                                     is corrupt or invalid
  57.      */
  58.     public function __construct(
  59.         string $filename,
  60.         array $locales = ['en']
  61.     ) {
  62.         $this->dbReader = new DbReader($filename);
  63.         $this->dbType $this->dbReader->metadata()->databaseType;
  64.         $this->locales $locales;
  65.     }
  66.     /**
  67.      * This method returns a GeoIP2 City model.
  68.      *
  69.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  70.      *
  71.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  72.      *                                                     not in the database
  73.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  74.      *                                                     is corrupt or invalid
  75.      */
  76.     public function city(string $ipAddress): City
  77.     {
  78.         return $this->modelFor(City::class, 'City'$ipAddress);
  79.     }
  80.     /**
  81.      * This method returns a GeoIP2 Country model.
  82.      *
  83.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  84.      *
  85.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  86.      *                                                     not in the database
  87.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  88.      *                                                     is corrupt or invalid
  89.      */
  90.     public function country(string $ipAddress): Country
  91.     {
  92.         return $this->modelFor(Country::class, 'Country'$ipAddress);
  93.     }
  94.     /**
  95.      * This method returns a GeoIP2 Anonymous IP model.
  96.      *
  97.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  98.      *
  99.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  100.      *                                                     not in the database
  101.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  102.      *                                                     is corrupt or invalid
  103.      */
  104.     public function anonymousIp(string $ipAddress): AnonymousIp
  105.     {
  106.         return $this->flatModelFor(
  107.             AnonymousIp::class,
  108.             'GeoIP2-Anonymous-IP',
  109.             $ipAddress
  110.         );
  111.     }
  112.     /**
  113.      * This method returns a GeoLite2 ASN model.
  114.      *
  115.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  116.      *
  117.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  118.      *                                                     not in the database
  119.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  120.      *                                                     is corrupt or invalid
  121.      */
  122.     public function asn(string $ipAddress): Asn
  123.     {
  124.         return $this->flatModelFor(
  125.             Asn::class,
  126.             'GeoLite2-ASN',
  127.             $ipAddress
  128.         );
  129.     }
  130.     /**
  131.      * This method returns a GeoIP2 Connection Type model.
  132.      *
  133.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  134.      *
  135.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  136.      *                                                     not in the database
  137.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  138.      *                                                     is corrupt or invalid
  139.      */
  140.     public function connectionType(string $ipAddress): ConnectionType
  141.     {
  142.         return $this->flatModelFor(
  143.             ConnectionType::class,
  144.             'GeoIP2-Connection-Type',
  145.             $ipAddress
  146.         );
  147.     }
  148.     /**
  149.      * This method returns a GeoIP2 Domain model.
  150.      *
  151.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  152.      *
  153.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  154.      *                                                     not in the database
  155.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  156.      *                                                     is corrupt or invalid
  157.      */
  158.     public function domain(string $ipAddress): Domain
  159.     {
  160.         return $this->flatModelFor(
  161.             Domain::class,
  162.             'GeoIP2-Domain',
  163.             $ipAddress
  164.         );
  165.     }
  166.     /**
  167.      * This method returns a GeoIP2 Enterprise model.
  168.      *
  169.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  170.      *
  171.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  172.      *                                                     not in the database
  173.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  174.      *                                                     is corrupt or invalid
  175.      */
  176.     public function enterprise(string $ipAddress): Enterprise
  177.     {
  178.         return $this->modelFor(Enterprise::class, 'Enterprise'$ipAddress);
  179.     }
  180.     /**
  181.      * This method returns a GeoIP2 ISP model.
  182.      *
  183.      * @param string $ipAddress an IPv4 or IPv6 address as a string
  184.      *
  185.      * @throws \GeoIp2\Exception\AddressNotFoundException  if the address is
  186.      *                                                     not in the database
  187.      * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
  188.      *                                                     is corrupt or invalid
  189.      */
  190.     public function isp(string $ipAddress): Isp
  191.     {
  192.         return $this->flatModelFor(
  193.             Isp::class,
  194.             'GeoIP2-ISP',
  195.             $ipAddress
  196.         );
  197.     }
  198.     private function modelFor(string $classstring $typestring $ipAddress): object
  199.     {
  200.         [$record$prefixLen] = $this->getRecord($class$type$ipAddress);
  201.         $record['traits']['ip_address'] = $ipAddress;
  202.         $record['traits']['prefix_len'] = $prefixLen;
  203.         return new $class($record$this->locales);
  204.     }
  205.     private function flatModelFor(string $classstring $typestring $ipAddress): object
  206.     {
  207.         [$record$prefixLen] = $this->getRecord($class$type$ipAddress);
  208.         $record['ip_address'] = $ipAddress;
  209.         $record['prefix_len'] = $prefixLen;
  210.         return new $class($record);
  211.     }
  212.     private function getRecord(string $classstring $typestring $ipAddress): array
  213.     {
  214.         if (!str_contains($this->dbType$type)) {
  215.             $method lcfirst((new \ReflectionClass($class))->getShortName());
  216.             throw new \BadMethodCallException(
  217.                 "The $method method cannot be used to open a {$this->dbType} database"
  218.             );
  219.         }
  220.         [$record$prefixLen] = $this->dbReader->getWithPrefixLen($ipAddress);
  221.         if ($record === null) {
  222.             throw new AddressNotFoundException(
  223.                 "The address $ipAddress is not in the database."
  224.             );
  225.         }
  226.         if (!\is_array($record)) {
  227.             // This can happen on corrupt databases. Generally,
  228.             // MaxMind\Db\Reader will throw a
  229.             // MaxMind\Db\Reader\InvalidDatabaseException, but occasionally
  230.             // the lookup may result in a record that looks valid but is not
  231.             // an array. This mostly happens when the user is ignoring all
  232.             // exceptions and the more frequent InvalidDatabaseException
  233.             // exceptions go unnoticed.
  234.             throw new InvalidDatabaseException(
  235.                 "Expected an array when looking up $ipAddress but received: "
  236.                 \gettype($record)
  237.             );
  238.         }
  239.         return [$record$prefixLen];
  240.     }
  241.     /**
  242.      * @throws \InvalidArgumentException if arguments are passed to the method
  243.      * @throws \BadMethodCallException   if the database has been closed
  244.      *
  245.      * @return \MaxMind\Db\Reader\Metadata object for the database
  246.      */
  247.     public function metadata(): DbReader\Metadata
  248.     {
  249.         return $this->dbReader->metadata();
  250.     }
  251.     /**
  252.      * Closes the GeoIP2 database and returns the resources to the system.
  253.      */
  254.     public function close(): void
  255.     {
  256.         $this->dbReader->close();
  257.     }
  258. }