Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  namespace GeoIp2\WebService;
   6  
   7  use GeoIp2\Exception\AddressNotFoundException;
   8  use GeoIp2\Exception\AuthenticationException;
   9  use GeoIp2\Exception\GeoIp2Exception;
  10  use GeoIp2\Exception\HttpException;
  11  use GeoIp2\Exception\InvalidRequestException;
  12  use GeoIp2\Exception\OutOfQueriesException;
  13  use GeoIp2\ProviderInterface;
  14  use MaxMind\WebService\Client as WsClient;
  15  
  16  /**
  17   * This class provides a client API for all the GeoIP2 Precision web services.
  18   * The services are Country, City, and Insights. Each service returns a
  19   * different set of data about an IP address, with Country returning the
  20   * least data and Insights the most.
  21   *
  22   * Each web service is represented by a different model class, and these model
  23   * classes in turn contain multiple record classes. The record classes have
  24   * attributes which contain data about the IP address.
  25   *
  26   * If the web service does not return a particular piece of data for an IP
  27   * address, the associated attribute is not populated.
  28   *
  29   * The web service may not return any information for an entire record, in
  30   * which case all of the attributes for that record class will be empty.
  31   *
  32   * ## Usage ##
  33   *
  34   * The basic API for this class is the same for all of the web service end
  35   * points. First you create a web service object with your MaxMind `$accountId`
  36   * and `$licenseKey`, then you call the method corresponding to a specific end
  37   * point, passing it the IP address you want to look up.
  38   *
  39   * If the request succeeds, the method call will return a model class for
  40   * the service you called. This model in turn contains multiple record
  41   * classes, each of which represents part of the data returned by the web
  42   * service.
  43   *
  44   * If the request fails, the client class throws an exception.
  45   */
  46  class Client implements ProviderInterface
  47  {
  48      private $locales;
  49      private $client;
  50      private static $basePath = '/geoip/v2.1';
  51  
  52      const VERSION = 'v2.11.0';
  53  
  54      /**
  55       * Constructor.
  56       *
  57       * @param int    $accountId  your MaxMind account ID
  58       * @param string $licenseKey your MaxMind license key
  59       * @param array  $locales    list of locale codes to use in name property
  60       *                           from most preferred to least preferred
  61       * @param array  $options    array of options. Valid options include:
  62       *                           * `host` - The host to use when querying the web service.
  63       *                           * `timeout` - Timeout in seconds.
  64       *                           * `connectTimeout` - Initial connection timeout in seconds.
  65       *                           * `proxy` - The HTTP proxy to use. May include a schema, port,
  66       *                           username, and password, e.g.,
  67       *                           `http://username:password@127.0.0.1:10`.
  68       */
  69      public function __construct(
  70          int $accountId,
  71          string $licenseKey,
  72          array $locales = ['en'],
  73          array $options = []
  74      ) {
  75          $this->locales = $locales;
  76  
  77          // This is for backwards compatibility. Do not remove except for a
  78          // major version bump.
  79          if (\is_string($options)) {
  80              $options = ['host' => $options];
  81          }
  82  
  83          if (!isset($options['host'])) {
  84              $options['host'] = 'geoip.maxmind.com';
  85          }
  86  
  87          $options['userAgent'] = $this->userAgent();
  88  
  89          $this->client = new WsClient($accountId, $licenseKey, $options);
  90      }
  91  
  92      private function userAgent(): string
  93      {
  94          return 'GeoIP2-API/' . self::VERSION;
  95      }
  96  
  97      /**
  98       * This method calls the GeoIP2 Precision: City service.
  99       *
 100       * @param string $ipAddress IPv4 or IPv6 address as a string. If no
 101       *                          address is provided, the address that the web service is called
 102       *                          from will be used.
 103       *
 104       * @throws \GeoIp2\Exception\AddressNotFoundException if the address you
 105       *                                                    provided is not in our database (e.g., a private address).
 106       * @throws \GeoIp2\Exception\AuthenticationException  if there is a problem
 107       *                                                    with the account ID or license key that you provided
 108       * @throws \GeoIp2\Exception\OutOfQueriesException    if your account is out
 109       *                                                    of queries
 110       * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
 111       *                                                    invalid for some other reason.  This may indicate an issue
 112       *                                                    with this API. Please report the error to MaxMind.
 113       * @throws \GeoIp2\Exception\HttpException            if an unexpected HTTP error code or message was returned.
 114       *                                                    This could indicate a problem with the connection between
 115       *                                                    your server and the web service or that the web service
 116       *                                                    returned an invalid document or 500 error code
 117       * @throws \GeoIp2\Exception\GeoIp2Exception          This serves as the parent
 118       *                                                    class to the above exceptions. It will be thrown directly
 119       *                                                    if a 200 status code is returned but the body is invalid.
 120       */
 121      public function city(string $ipAddress = 'me'): \GeoIp2\Model\City
 122      {
 123          return $this->responseFor('city', 'City', $ipAddress);
 124      }
 125  
 126      /**
 127       * This method calls the GeoIP2 Precision: Country service.
 128       *
 129       * @param string $ipAddress IPv4 or IPv6 address as a string. If no
 130       *                          address is provided, the address that the web service is called
 131       *                          from will be used.
 132       *
 133       * @throws \GeoIp2\Exception\AddressNotFoundException if the address you provided is not in our database (e.g.,
 134       *                                                    a private address).
 135       * @throws \GeoIp2\Exception\AuthenticationException  if there is a problem
 136       *                                                    with the account ID or license key that you provided
 137       * @throws \GeoIp2\Exception\OutOfQueriesException    if your account is out of queries
 138       * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
 139       *                                                    invalid for some other reason.  This may indicate an
 140       *                                                    issue with this API. Please report the error to MaxMind.
 141       * @throws \GeoIp2\Exception\HttpException            if an unexpected HTTP error
 142       *                                                    code or message was returned. This could indicate a problem
 143       *                                                    with the connection between your server and the web service
 144       *                                                    or that the web service returned an invalid document or 500
 145       *                                                    error code.
 146       * @throws \GeoIp2\Exception\GeoIp2Exception          This serves as the parent class to the above exceptions. It
 147       *                                                    will be thrown directly if a 200 status code is returned but
 148       *                                                    the body is invalid.
 149       */
 150      public function country(string $ipAddress = 'me'): \GeoIp2\Model\Country
 151      {
 152          return $this->responseFor('country', 'Country', $ipAddress);
 153      }
 154  
 155      /**
 156       * This method calls the GeoIP2 Precision: Insights service.
 157       *
 158       * @param string $ipAddress IPv4 or IPv6 address as a string. If no
 159       *                          address is provided, the address that the web service is called
 160       *                          from will be used.
 161       *
 162       * @throws \GeoIp2\Exception\AddressNotFoundException if the address you
 163       *                                                    provided is not in our database (e.g., a private address).
 164       * @throws \GeoIp2\Exception\AuthenticationException  if there is a problem
 165       *                                                    with the account ID or license key that you provided
 166       * @throws \GeoIp2\Exception\OutOfQueriesException    if your account is out
 167       *                                                    of queries
 168       * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
 169       *                                                    invalid for some other reason.  This may indicate an
 170       *                                                    issue with this API. Please report the error to MaxMind.
 171       * @throws \GeoIp2\Exception\HttpException            if an unexpected HTTP error code or message was returned.
 172       *                                                    This could indicate a problem with the connection between
 173       *                                                    your server and the web service or that the web service
 174       *                                                    returned an invalid document or 500 error code
 175       * @throws \GeoIp2\Exception\GeoIp2Exception          This serves as the parent
 176       *                                                    class to the above exceptions. It will be thrown directly
 177       *                                                    if a 200 status code is returned but the body is invalid.
 178       */
 179      public function insights(string $ipAddress = 'me'): \GeoIp2\Model\Insights
 180      {
 181          return $this->responseFor('insights', 'Insights', $ipAddress);
 182      }
 183  
 184      private function responseFor(string $endpoint, string $class, string $ipAddress)
 185      {
 186          $path = implode('/', [self::$basePath, $endpoint, $ipAddress]);
 187  
 188          try {
 189              $body = $this->client->get('GeoIP2 ' . $class, $path);
 190          } catch (\MaxMind\Exception\IpAddressNotFoundException $ex) {
 191              throw new AddressNotFoundException(
 192                  $ex->getMessage(),
 193                  $ex->getStatusCode(),
 194                  $ex
 195              );
 196          } catch (\MaxMind\Exception\AuthenticationException $ex) {
 197              throw new AuthenticationException(
 198                  $ex->getMessage(),
 199                  $ex->getStatusCode(),
 200                  $ex
 201              );
 202          } catch (\MaxMind\Exception\InsufficientFundsException $ex) {
 203              throw new OutOfQueriesException(
 204                  $ex->getMessage(),
 205                  $ex->getStatusCode(),
 206                  $ex
 207              );
 208          } catch (\MaxMind\Exception\InvalidRequestException $ex) {
 209              throw new InvalidRequestException(
 210                  $ex->getMessage(),
 211                  $ex->getErrorCode(),
 212                  $ex->getStatusCode(),
 213                  $ex->getUri(),
 214                  $ex
 215              );
 216          } catch (\MaxMind\Exception\HttpException $ex) {
 217              throw new HttpException(
 218                  $ex->getMessage(),
 219                  $ex->getStatusCode(),
 220                  $ex->getUri(),
 221                  $ex
 222              );
 223          } catch (\MaxMind\Exception\WebServiceException $ex) {
 224              throw new GeoIp2Exception(
 225                  $ex->getMessage(),
 226                  $ex->getCode(),
 227                  $ex
 228              );
 229          }
 230  
 231          $class = 'GeoIp2\\Model\\' . $class;
 232  
 233          return new $class($body, $this->locales);
 234      }
 235  }