1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* |
||
6 | * This file is part of the Geocoder package. |
||
7 | * For the full copyright and license information, please view the LICENSE |
||
8 | * file that was distributed with this source code. |
||
9 | * |
||
10 | * @license MIT License |
||
11 | */ |
||
12 | |||
13 | namespace Geocoder\Provider\GeoIPs; |
||
14 | |||
15 | use Geocoder\Collection; |
||
16 | use Geocoder\Exception\InvalidArgument; |
||
17 | use Geocoder\Exception\InvalidCredentials; |
||
18 | use Geocoder\Exception\InvalidServerResponse; |
||
19 | use Geocoder\Exception\QuotaExceeded; |
||
20 | use Geocoder\Exception\UnsupportedOperation; |
||
21 | use Geocoder\Model\Address; |
||
22 | use Geocoder\Model\AddressCollection; |
||
23 | use Geocoder\Query\GeocodeQuery; |
||
24 | use Geocoder\Query\ReverseQuery; |
||
25 | use Geocoder\Http\Provider\AbstractHttpProvider; |
||
26 | use Geocoder\Provider\Provider; |
||
27 | use Http\Client\HttpClient; |
||
28 | |||
29 | /** |
||
30 | * @author Andrea Cristaudo <[email protected]> |
||
31 | * @author Arthur Bodera <[email protected]> |
||
32 | * |
||
33 | * @deprecated The GeoIPs provider has shut down |
||
34 | * @see https://github.com/geocoder-php/Geocoder/issues/965 |
||
35 | */ |
||
36 | final class GeoIPs extends AbstractHttpProvider implements Provider |
||
37 | { |
||
38 | /** |
||
39 | * @var string |
||
40 | */ |
||
41 | const GEOCODE_ENDPOINT_URL = 'https://api.geoips.com/ip/%s/key/%s/output/json/timezone/true/'; |
||
42 | |||
43 | const CODE_SUCCESS = '200_1'; // The following results has been returned. |
||
44 | |||
45 | const CODE_NOT_FOUND = '200_2'; // No result set has been returned. |
||
46 | |||
47 | const CODE_BAD_KEY = '400_1'; // Error in the URI - The API call should include a API key parameter. |
||
48 | |||
49 | const CODE_BAD_IP = '400_2'; // Error in the URI - The API call should include a valid IP address. |
||
50 | |||
51 | const CODE_NOT_AUTHORIZED = '403_1'; // The API key associated with your request was not recognized. |
||
52 | |||
53 | const CODE_ACCOUNT_INACTIVE = '403_2'; // The API key has not been approved or has been disabled. |
||
54 | |||
55 | const CODE_LIMIT_EXCEEDED = '403_3'; // The service you have requested is over capacity. |
||
56 | |||
57 | /** |
||
58 | * @var string |
||
59 | */ |
||
60 | private $apiKey; |
||
61 | |||
62 | /** |
||
63 | * @deprecated The GeoIPs provider has shut down |
||
64 | * |
||
65 | * @param HttpClient $client An HTTP adapter |
||
66 | * @param string $apiKey An API key |
||
67 | */ |
||
68 | 22 | public function __construct(HttpClient $client, string $apiKey) |
|
69 | { |
||
70 | 22 | if (empty($apiKey)) { |
|
71 | throw new InvalidCredentials('No API key provided.'); |
||
72 | } |
||
73 | |||
74 | 22 | $this->apiKey = $apiKey; |
|
75 | 22 | parent::__construct($client); |
|
76 | 22 | } |
|
77 | |||
78 | /** |
||
79 | * {@inheritdoc} |
||
80 | */ |
||
81 | 20 | public function geocodeQuery(GeocodeQuery $query): Collection |
|
82 | { |
||
83 | 20 | $address = $query->getText(); |
|
84 | 20 | if (!filter_var($address, FILTER_VALIDATE_IP)) { |
|
85 | 1 | throw new UnsupportedOperation('The GeoIPs provider does not support street addresses, only IPv4 addresses.'); |
|
86 | } |
||
87 | |||
88 | 19 | if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { |
|
89 | 1 | throw new UnsupportedOperation('The GeoIPs provider does not support IPv6 addresses, only IPv4 addresses.'); |
|
90 | } |
||
91 | |||
92 | 18 | if ('127.0.0.1' === $address) { |
|
93 | 1 | return new AddressCollection([$this->getLocationForLocalhost()]); |
|
94 | } |
||
95 | |||
96 | 17 | $query = sprintf(self::GEOCODE_ENDPOINT_URL, $address, $this->apiKey); |
|
97 | |||
98 | 17 | return $this->executeQuery($query); |
|
99 | } |
||
100 | |||
101 | /** |
||
102 | * {@inheritdoc} |
||
103 | */ |
||
104 | 1 | public function reverseQuery(ReverseQuery $query): Collection |
|
105 | { |
||
106 | 1 | throw new UnsupportedOperation('The GeoIPs provider is not able to do reverse geocoding.'); |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * {@inheritdoc} |
||
111 | */ |
||
112 | 6 | public function getName(): string |
|
113 | { |
||
114 | 6 | return 'geo_ips'; |
|
115 | } |
||
116 | |||
117 | /** |
||
118 | * @param string $url |
||
119 | * |
||
120 | * @return AddressCollection |
||
121 | */ |
||
122 | 17 | private function executeQuery(string $url): AddressCollection |
|
123 | { |
||
124 | 17 | $content = $this->getUrlContents($url); |
|
125 | 10 | $json = json_decode($content, true); |
|
126 | |||
127 | 10 | if (isset($json['error'])) { |
|
128 | 5 | switch ($json['error']['code']) { |
|
129 | 5 | case static::CODE_BAD_IP: |
|
130 | 1 | throw new InvalidArgument('The API call should include a valid IP address.'); |
|
131 | 4 | case static::CODE_BAD_KEY: |
|
132 | 1 | throw new InvalidCredentials('The API call should include a API key parameter.'); |
|
133 | 3 | case static::CODE_NOT_AUTHORIZED: |
|
134 | 1 | throw new InvalidCredentials('The API key associated with your request was not recognized.'); |
|
135 | 2 | case static::CODE_ACCOUNT_INACTIVE: |
|
136 | 1 | throw new InvalidCredentials('The API key has not been approved or has been disabled.'); |
|
137 | 1 | case static::CODE_LIMIT_EXCEEDED: |
|
138 | 1 | throw new QuotaExceeded('The service you have requested is over capacity.'); |
|
139 | default: |
||
140 | throw new InvalidServerResponse(sprintf('GeoIPs error %s%s%s%s - query: %s', $json['error']['code'], isset($json['error']['status']) ? ', '.$json['error']['status'] : '', isset($json['error']['message']) ? ', '.$json['error']['message'] : '', isset($json['error']['notes']) ? ', '.$json['error']['notes'] : '', $url)); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | 5 | if (!is_array($json) || empty($json) || empty($json['response']) || empty($json['response']['code'])) { |
|
145 | throw InvalidServerResponse::create($url); |
||
146 | } |
||
147 | |||
148 | 5 | $response = $json['response']; |
|
149 | |||
150 | // Check response code |
||
151 | 5 | switch ($response['code']) { |
|
152 | 5 | case static::CODE_SUCCESS: |
|
153 | // everything is ok |
||
154 | 4 | break; |
|
155 | 1 | case static::CODE_NOT_FOUND: |
|
156 | 1 | return new AddressCollection([]); |
|
157 | default: |
||
158 | throw new InvalidServerResponse(sprintf('The GeoIPs API returned unknown result code "%s" for query: "%s".', $response['code'], $url)); |
||
159 | } |
||
160 | |||
161 | // Make sure that we do have proper result array |
||
162 | 4 | if (empty($response['location']) || !is_array($response['location'])) { |
|
163 | return new AddressCollection([]); |
||
164 | } |
||
165 | |||
166 | $location = array_map(function ($value) { |
||
167 | 4 | return '' === $value ? null : $value; |
|
168 | 4 | }, $response['location']); |
|
169 | |||
170 | 4 | $adminLevels = []; |
|
171 | |||
172 | 4 | if (null !== $location['region_name'] || null !== $location['region_code']) { |
|
173 | 2 | $adminLevels[] = [ |
|
174 | 2 | 'name' => $location['region_name'], |
|
175 | 2 | 'code' => $location['region_code'], |
|
176 | 2 | 'level' => 1, |
|
177 | ]; |
||
178 | } |
||
179 | |||
180 | 4 | if (null !== $location['county_name']) { |
|
181 | 2 | $adminLevels[] = [ |
|
182 | 2 | 'name' => $location['county_name'], |
|
183 | 2 | 'level' => 2, |
|
184 | ]; |
||
185 | } |
||
186 | |||
187 | 4 | $results = Address::createFromArray([ |
|
188 | 4 | 'providedBy' => $this->getName(), |
|
189 | 4 | 'country' => $location['country_name'], |
|
190 | 4 | 'countryCode' => $location['country_code'], |
|
191 | 4 | 'adminLevels' => $adminLevels, |
|
192 | 4 | 'locality' => $location['city_name'], |
|
193 | 4 | 'latitude' => $location['latitude'], |
|
194 | 4 | 'longitude' => $location['longitude'], |
|
195 | 4 | 'timezone' => $location['timezone'], |
|
196 | ]); |
||
197 | |||
198 | 4 | return new AddressCollection([$results]); |
|
199 | } |
||
200 | } |
||
201 |