IP2Location::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 2
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\IP2Location;
14
15
use Geocoder\Exception\InvalidCredentials;
16
use Geocoder\Exception\UnsupportedOperation;
17
use Geocoder\Collection;
18
use Geocoder\Model\Address;
19
use Geocoder\Model\AddressCollection;
20
use Geocoder\Query\GeocodeQuery;
21
use Geocoder\Query\ReverseQuery;
22
use Geocoder\Http\Provider\AbstractHttpProvider;
23
use Geocoder\Provider\Provider;
24
use Http\Client\HttpClient;
25
26
/**
27
 * @author William Durand <[email protected]>
28
 */
29
final class IP2Location extends AbstractHttpProvider implements Provider
30
{
31
    /**
32
     * @var string
33
     */
34
    const ENDPOINT_URL = 'https://api.ip2location.com/v2/?key=%s&ip=%s&format=json&package=WS9';
35
36
    /**
37
     * @var string
38
     */
39
    private $apiKey;
40
41
    /**
42
     * @var string
43
     */
44
    private $endpointUrl;
45
46
    /**
47
     * @param HttpClient $client a HTTP adapter
48
     * @param string     $apiKey an API key
49
     */
50
    public function __construct(HttpClient $client, string $apiKey)
51
    {
52
        parent::__construct($client);
53
54
        $this->apiKey = $apiKey;
55
        $this->endpointUrl = self::ENDPOINT_URL;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function geocodeQuery(GeocodeQuery $query): Collection
62
    {
63
        $address = $query->getText();
64
65
        if (empty($this->apiKey)) {
66
            throw new InvalidCredentials('No API key provided.');
67
        }
68
69
        if (!filter_var($address, FILTER_VALIDATE_IP)) {
70
            throw new UnsupportedOperation('The IP2Location provider does not support street addresses, only IP addresses.');
71
        }
72
73
        if (in_array($address, ['127.0.0.1', '::1'])) {
74
            return new AddressCollection([$this->getLocationForLocalhost()]);
75
        }
76
77
        $url = sprintf($this->endpointUrl, $this->apiKey, $address);
78
79
        return $this->executeQuery($url);
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function reverseQuery(ReverseQuery $query): Collection
86
    {
87
        throw new UnsupportedOperation('The IP2Location provider is not able to do reverse geocoding.');
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function getName(): string
94
    {
95
        return 'ip2location';
96
    }
97
98
    /**
99
     * @param string $url
100
     *
101
     * @return Collection
102
     */
103
    private function executeQuery(string $url): AddressCollection
104
    {
105
        $content = $this->getUrlContents($url);
106
        $data = json_decode($content, true);
107
108
        if (empty($data)) {
109
            return new AddressCollection([]);
110
        }
111
112
        if (isset($data['response'])) {
113
            if (preg_match('/suspended|denied|invalid account/i', $data['response'])) {
114
                throw new InvalidCredentials('API Key provided is not valid.');
115
            } elseif (preg_match('/insufficient/i', $data['response'])) {
116
                throw new InvalidCredentials('Insufficient credits to use IP2Location service.');
117
            } elseif (preg_match('/invalid ip address/i', $data['response'])) {
118
                throw new UnsupportedOperation('Invalid IP address.');
119
            } else {
120
                throw new UnsupportedOperation('Unexpected error.');
121
            }
122
        }
123
124
        if (isset($data['region_name'])) {
125
            $adminLevels = [[
126
                'name' => $data['region_name'],
127
                'level' => 1,
128
            ]];
129
        } else {
130
            $adminLevels = [];
131
        }
132
133
        return new AddressCollection([
134
            Address::createFromArray([
135
                'providedBy' => $this->getName(),
136
                'latitude' => $data['latitude'] ?? null,
137
                'longitude' => $data['longitude'] ?? null,
138
                'locality' => $data['city_name'] ?? null,
139
                'postalCode' => $data['zip_code'] ?? null,
140
                'adminLevels' => $adminLevels,
141
                'country' => $data['country_name'] ?? null,
142
                'countryCode' => $data['country_code'] ?? null,
143
            ]),
144
        ]);
145
    }
146
}
147