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