Passed
Push — master ( 0695bf...48cd6e )
by Davide
47s queued 10s
created

Ipinfo::makeCurlRequest()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6.0702

Importance

Changes 0
Metric Value
dl 0
loc 41
ccs 21
cts 24
cp 0.875
rs 8.6417
c 0
b 0
f 0
cc 6
nc 24
nop 1
crap 6.0702
1
<?php
2
3
namespace DavidePastore\Ipinfo;
4
5
use DavidePastore\Ipinfo\Exception\InvalidTokenException;
6
use DavidePastore\Ipinfo\Exception\IpInfoException;
7
use DavidePastore\Ipinfo\Exception\RateLimitExceedException;
8
use DavidePastore\Ipinfo\Exception\WrongIpException;
9
10
/**
11
 * ipinfo.io service wrapper.
12
 *
13
 * @author davidepastore
14
 */
15
class Ipinfo
16
{
17
    /**
18
     * The base url of the ipinfo service.
19
     *
20
     * @var string
21
     */
22
    const BASE_URL = 'https://ipinfo.io/';
23
24
    /**
25
     * The ip string.
26
     *
27
     * @var string
28
     */
29
    const IP = 'ip';
30
31
    /**
32
     * The hostname string.
33
     *
34
     * @var string
35
     */
36
    const HOSTNAME = 'hostname';
37
38
    /**
39
     * The loc string.
40
     *
41
     * @var string
42
     */
43
    const LOC = 'loc';
44
45
    /**
46
     * The org string.
47
     *
48
     * @var string
49
     */
50
    const ORG = 'org';
51
52
    /**
53
     * The city string.
54
     *
55
     * @var string
56
     */
57
    const CITY = 'city';
58
59
    /**
60
     * The region string.
61
     *
62
     * @var string
63
     */
64
    const REGION = 'region';
65
66
    /**
67
     * The country string.
68
     *
69
     * @var string
70
     */
71
    const COUNTRY = 'country';
72
73
    /**
74
     * The phone string.
75
     *
76
     * @var string
77
     */
78
    const PHONE = 'phone';
79
80
    /**
81
     * The geo string.
82
     *
83
     * @var string
84
     */
85
    const GEO = 'geo';
86
87
    /**
88
     * The postal string.
89
     *
90
     * @var string
91
     */
92
    const POSTAL = 'postal';
93
94
    /**
95
     * All the settings.
96
     *
97
     * @var array
98
     */
99
    protected $settings;
100
101
    /**
102
     * Create an Ipinfo instance.
103
     *
104
     * @param array $settings An array with all the settings.
105
     *                        Supported keys are:
106
     *                        - token: string the developer token;
107 11
     *                        - debug: boolean active or not the debug.
108
     */
109
    public function __construct($settings = array())
110 11
    {
111 11
        //Merge user settings
112 11
        $this->settings = array_merge(array(
113 11
                'token' => '',
114 11
                'debug' => false,
115 11
                'curlOptions' => array()
116
        ), $settings);
117
    }
118
119
    /**
120
     * Get all the info about your own ip address.
121
     *
122
     * @return \DavidePastore\Ipinfo\Host The Host object with all the info.
123
     * @throws InvalidTokenException
124 2
     * @throws RateLimitExceedException
125
     * @throws WrongIpException
126 2
     */
127 2 View Code Duplication
    public function getYourOwnIpDetails()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
    {
129 1
        $response = $this->makeCurlRequest($this::BASE_URL.'json');
130
        $response = $this->jsonDecodeResponse($response);
131
132
        return new Host($response);
133
    }
134
135
    /**
136
     * Get all the info about an ip address.
137
     *
138
     * @param string $ipAddress The ip address.
139
     *
140
     * @return \DavidePastore\Ipinfo\Host The Host object with all the info.
141 2
     * @throws InvalidTokenException
142
     * @throws RateLimitExceedException
143 2
     * @throws WrongIpException
144 2
     */
145 View Code Duplication
    public function getFullIpDetails($ipAddress)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146 2
    {
147
        $response = $this->makeCurlRequest($this::BASE_URL.$ipAddress);
148
        $response = $this->jsonDecodeResponse($response);
149
150
        return new Host($response);
151
    }
152
153
    /**
154
     * Get a specific field value.
155
     *
156
     * @param string $ipAddress The ip address.
157
     * @param string $field The field.
158
     *
159
     * @return string|\DavidePastore\Ipinfo\Host The value of the given field for the given ip.
160
     *                                           This could returns an Host object if you call it with for the field
161 6
     *                                           \DavidePastore\Ipinfo\Ipinfo::GEO.
162
     * @throws InvalidTokenException
163 6
     * @throws RateLimitExceedException
164 6
     * @throws WrongIpException
165
     */
166 5 View Code Duplication
    public function getSpecificField($ipAddress, $field)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
    {
168
        $response = $this->makeCurlRequest($this::BASE_URL.$ipAddress.'/'.$field);
169
        $response = $this->checkGeo($field, $response);
170
171
        return $response;
172
    }
173
174
    /**
175
     * Get a specific field value of your own ip address.
176
     *
177
     * @param string $field The field.
178
     *
179
     * @return string|\DavidePastore\Ipinfo\Host The value of the given field for your own ip.
180 1
     *                                           This could returns an Host object if you call it with for the field
181
     *                                           \DavidePastore\Ipinfo\Ipinfo::GEO.
182 1
     * @throws InvalidTokenException
183 1
     * @throws RateLimitExceedException
184
     * @throws WrongIpException
185 1
     */
186 View Code Duplication
    public function getYourOwnIpSpecificField($field)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
    {
188
        $response = $this->makeCurlRequest($this::BASE_URL.$field);
189
        $response = $this->checkGeo($field, $response);
190
191
        return $response;
192
    }
193
194
    /**
195
     * Use the /geo call to get just the geolocation information, which will often be
196
     * faster than getting the full response.
197
     *
198 2
     * @param string $ipAddress The ip address.
199
     *
200 2
     * @return \DavidePastore\Ipinfo\Host
201
     * @throws InvalidTokenException
202
     * @throws RateLimitExceedException
203
     * @throws WrongIpException
204
     */
205
    public function getIpGeoDetails($ipAddress)
206
    {
207
        return $this->getSpecificField($ipAddress, $this::GEO);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getSpecificField($ipAddress, $this::GEO); of type string|DavidePastore\Ipinfo\Host adds the type string to the return on line 207 which is incompatible with the return type documented by DavidePastore\Ipinfo\Ipinfo::getIpGeoDetails of type DavidePastore\Ipinfo\Host.
Loading history...
208
    }
209
210
    /**
211
     * Check if the response is GEO and set the parameters accordingly.
212
     *
213
     * @param string $field The field value.
214
     * @param string $response The response from the server.
215 7
     *
216
     * @return \DavidePastore\Ipinfo\Host|string Returns an Host object if the request is
217 7
     *                  of the GEO type, a string otherwise. If the field value is different from the GEO type, it will
218 2
     *                  delete the last character ('\n').
219 2
     * @throws InvalidTokenException
220 2
     * @throws RateLimitExceedException
221 5
     * @throws WrongIpException
222 4
     */
223
    private function checkGeo($field, $response)
224
    {
225 6
        if ($field == $this::GEO) {
226
            $response = $this->jsonDecodeResponse($response);
227
            $response = new Host($response);
228
        } else {
229
            $this->checkErrors($response);
230
            $response = substr($response, 0, -1);
231
        }
232
233
        return $response;
234
    }
235 11
236
    /**
237 11
     * Make a curl request.
238
     *
239 11
     * @param string $address The address of the request.
240 2
     *
241 2
     * @return string Returns the response from the request.
242
     */
243 11
    private function makeCurlRequest($address)
244 1
    {
245 1
        $curl = curl_init();
246
247 11
        if (!empty($this->settings['token'])) {
248 11
            $address .= '?token='.$this->settings['token'];
249 11
        }
250 11
251
        if ($this->settings['debug']) {
252 11
            echo 'Request address: '.$address."\n";
253 11
        }
254 11
255 11
        curl_setopt_array(
256 11
            $curl,
257
            array_replace(
258 11
                $this->settings['curlOptions'],
259
                array(
260 11
                    CURLOPT_RETURNTRANSFER => 1,
261
                    CURLOPT_URL => $address
262
                )
263
            )
264
        );
265 11
266
        $response = curl_exec($curl);
267 11
268
        if (curl_errno($curl)) {
269
            $errorMessage = curl_error($curl);
270
271
            if ($this->settings['debug']) {
272
                echo "The error is".$errorMessage;
273
            }
274
        }
275
276
        if (isset($errorMessage)) {
277 6
            throw new IpInfoException('cURL error', $errorMessage);
278
        }
279 6
280
        curl_close($curl);
281 5
282 4
        return $response;
283 4
    }
284 1
285
    /**
286 5
     * Returns the json decoded associative array.
287
     * @param  string $response Response from the http call.
288
     * @return array           Returns the associative array with the response.
289
     * @throws RateLimitExceedException    If you exceed the rate limit.
290
     * @throws InvalidTokenException If the used token is invalid.
291
     * @throws WrongIpException If the used token is invalid.
292
     */
293
    private function jsonDecodeResponse($response)
294
    {
295 10
        $output = array();
296
        if ($response) {
297 10
            // Check if the response contains an error message
298 1
            $this->checkErrors($response);
299 9
            $output = json_decode($response, true);
300 1
            if ($output === null && json_last_error() !== JSON_ERROR_NONE) {
301
                throw new IpInfoException("Wrong response", $response);
302 8
            }
303
        }
304 1
        return $output;
305
    }
306
307
    /**
308
     * Check if the given response has some kind of errors.
309
     * @param string $response The response to check.
310
     * @throws RateLimitExceedException    If you exceed the rate limit.
311
     * @throws InvalidTokenException If the used token is invalid.
312
     * @throws WrongIpException If the used token is invalid.
313
     */
314
    private function checkErrors($response)
315
    {
316
        if (strpos($response, 'Rate limit exceeded.') !== false) {
317
            throw new RateLimitExceedException("You exceed the rate limit.", $response);
318
        } elseif (strpos($response, 'Unknown token') !== false) {
319
            throw new InvalidTokenException("The used token is invalid.", $response);
320
        } elseif (strpos($response, 'Wrong ip') !== false) {
321
            throw new WrongIpException("The used IP address is not valid.", $response);
322
        }
323
    }
324
}
325