Code

< 40 %
40-60 %
> 60 %
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