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