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\GeoIP2; |
||
14 | |||
15 | use Geocoder\Collection; |
||
16 | use Geocoder\Exception\InvalidCredentials; |
||
17 | use Geocoder\Exception\QuotaExceeded; |
||
18 | use Geocoder\Exception\UnsupportedOperation; |
||
19 | use Geocoder\Model\Address; |
||
20 | use Geocoder\Model\AddressCollection; |
||
21 | use Geocoder\Provider\AbstractProvider; |
||
22 | use Geocoder\Provider\Provider; |
||
23 | use Geocoder\Query\GeocodeQuery; |
||
24 | use Geocoder\Query\ReverseQuery; |
||
25 | use GeoIp2\Exception\AddressNotFoundException; |
||
26 | use GeoIp2\Exception\AuthenticationException; |
||
27 | use GeoIp2\Exception\OutOfQueriesException; |
||
28 | |||
29 | /** |
||
30 | * @author Jens Wiese <[email protected]> |
||
31 | */ |
||
32 | final class GeoIP2 extends AbstractProvider implements Provider |
||
33 | { |
||
34 | /** |
||
35 | * @var GeoIP2Adapter |
||
36 | */ |
||
37 | private $adapter; |
||
38 | |||
39 | 12 | public function __construct(GeoIP2Adapter $adapter) |
|
40 | { |
||
41 | 12 | $this->adapter = $adapter; |
|
42 | } |
||
43 | |||
44 | 10 | public function geocodeQuery(GeocodeQuery $query): Collection |
|
45 | { |
||
46 | 10 | $address = $query->getText(); |
|
47 | 10 | $locale = $query->getLocale() ?: 'en'; // Default to English |
|
48 | 10 | if (!filter_var($address, FILTER_VALIDATE_IP)) { |
|
49 | 1 | throw new UnsupportedOperation('The GeoIP2 provider does not support street addresses, only IP addresses.'); |
|
50 | } |
||
51 | |||
52 | 9 | if ('127.0.0.1' === $address) { |
|
53 | 1 | return new AddressCollection([$this->getLocationForLocalhost()]); |
|
54 | } |
||
55 | |||
56 | 8 | $result = json_decode($this->executeQuery($address)); |
|
57 | |||
58 | 6 | if (null === $result) { |
|
59 | 1 | return new AddressCollection([]); |
|
60 | } |
||
61 | |||
62 | 5 | $adminLevels = []; |
|
63 | 5 | if (isset($result->subdivisions) && is_array($result->subdivisions)) { |
|
64 | 3 | foreach ($result->subdivisions as $i => $subdivision) { |
|
65 | 3 | $name = (isset($subdivision->names->{$locale}) ? $subdivision->names->{$locale} : null); |
|
66 | 3 | $code = (isset($subdivision->iso_code) ? $subdivision->iso_code : null); |
|
67 | |||
68 | 3 | if (null !== $name || null !== $code) { |
|
69 | 3 | $adminLevels[] = ['name' => $name, 'code' => $code, 'level' => $i + 1]; |
|
70 | } |
||
71 | } |
||
72 | } |
||
73 | |||
74 | 5 | return new AddressCollection([ |
|
75 | 5 | Address::createFromArray([ |
|
76 | 5 | 'providedBy' => $this->getName(), |
|
77 | 5 | 'countryCode' => (isset($result->country->iso_code) ? $result->country->iso_code : null), |
|
78 | 5 | 'country' => (isset($result->country->names->{$locale}) ? $result->country->names->{$locale} : null), |
|
79 | 5 | 'locality' => (isset($result->city->names->{$locale}) ? $result->city->names->{$locale} : null), |
|
80 | 5 | 'latitude' => (isset($result->location->latitude) ? $result->location->latitude : null), |
|
81 | 5 | 'longitude' => (isset($result->location->longitude) ? $result->location->longitude : null), |
|
82 | 5 | 'timezone' => (isset($result->location->time_zone) ? $result->location->time_zone : null), |
|
83 | 5 | 'postalCode' => (isset($result->postal->code) ? $result->postal->code : null), |
|
84 | 5 | 'adminLevels' => $adminLevels, |
|
85 | 5 | ]), |
|
86 | 5 | ]); |
|
87 | } |
||
88 | |||
89 | 1 | public function reverseQuery(ReverseQuery $query): Collection |
|
90 | { |
||
91 | 1 | throw new UnsupportedOperation('The GeoIP2 provider is not able to do reverse geocoding.'); |
|
92 | } |
||
93 | |||
94 | 7 | public function getName(): string |
|
95 | { |
||
96 | 7 | return 'geoip2'; |
|
97 | } |
||
98 | |||
99 | 8 | private function executeQuery(string $address): string |
|
100 | { |
||
101 | 8 | $uri = sprintf('file://geoip?%s', $address); |
|
102 | |||
103 | try { |
||
104 | 8 | $result = $this->adapter->getContent($uri); |
|
105 | 2 | } catch (AddressNotFoundException $e) { |
|
106 | return ''; |
||
107 | 2 | } catch (AuthenticationException $e) { |
|
108 | 1 | throw new InvalidCredentials($e->getMessage(), $e->getCode(), $e); |
|
109 | 1 | } catch (OutOfQueriesException $e) { |
|
110 | 1 | throw new QuotaExceeded($e->getMessage(), $e->getCode(), $e); |
|
111 | } |
||
112 | |||
113 | 6 | return $result; |
|
114 | } |
||
115 | } |
||
116 |