Completed
Pull Request — master (#53)
by Davide
04:17 queued 02:31
created

Ipinfo::makeCurlRequest()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6.0798

Importance

Changes 0
Metric Value
dl 0
loc 41
ccs 20
cts 23
cp 0.8696
rs 8.6417
c 0
b 0
f 0
cc 6
nc 24
nop 1
crap 6.0798
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
9
/**
10
 * ipinfo.io service wrapper.
11
 *
12
 * @author davidepastore
13
 */
14
class Ipinfo
15
{
16
    /**
17
     * The base url of the ipinfo service.
18
     *
19
     * @var string
20
     */
21
    const BASE_URL = 'https://ipinfo.io/';
22
23
    /**
24
     * The ip string.
25
     *
26
     * @var string
27
     */
28
    const IP = 'ip';
29
30
    /**
31
     * The hostname string.
32
     *
33
     * @var string
34
     */
35
    const HOSTNAME = 'hostname';
36
37
    /**
38
     * The loc string.
39
     *
40
     * @var string
41
     */
42
    const LOC = 'loc';
43
44
    /**
45
     * The org string.
46
     *
47
     * @var string
48
     */
49
    const ORG = 'org';
50
51
    /**
52
     * The city string.
53
     *
54
     * @var string
55
     */
56
    const CITY = 'city';
57
58
    /**
59
     * The region string.
60
     *
61
     * @var string
62
     */
63
    const REGION = 'region';
64
65
    /**
66
     * The country string.
67
     *
68
     * @var string
69
     */
70
    const COUNTRY = 'country';
71
72
    /**
73
     * The phone string.
74
     *
75
     * @var string
76
     */
77
    const PHONE = 'phone';
78
79
    /**
80
     * The geo string.
81
     *
82
     * @var string
83
     */
84
    const GEO = 'geo';
85
86
    /**
87
     * The postal string.
88
     *
89
     * @var string
90
     */
91
    const POSTAL = 'postal';
92
93
    /**
94
     * All the settings.
95
     *
96
     * @var array
97
     */
98
    protected $settings;
99
100
    /**
101
     * Create an Ipinfo instance.
102
     *
103
     * @param array $settings An array with all the settings.
104
     *                        Supported keys are:
105
     *                        - token: string the developer token;
106
     *                        - debug: boolean active or not the debug.
107 11
     */
108
    public function __construct($settings = array())
109
    {
110 11
        //Merge user settings
111 11
        $this->settings = array_merge(array(
112 11
                'token' => '',
113 11
                'debug' => false,
114 11
                'curlOptions' => array()
115 11
        ), $settings);
116
    }
117
118
    /**
119
     * Get all the info about your own ip address.
120
     *
121
     * @return \DavidePastore\Ipinfo\Host The Host object with all the info.
122
     * @throws InvalidTokenException
123
     * @throws RateLimitExceedException
124 2
     */
125 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...
126 2
    {
127 2
        $response = $this->makeCurlRequest($this::BASE_URL.'json');
128
        $response = $this->jsonDecodeResponse($response);
129 1
130
        return new Host($response);
131
    }
132
133
    /**
134
     * Get all the info about an ip address.
135
     *
136
     * @param string $ipAddress The ip address.
137
     *
138
     * @return \DavidePastore\Ipinfo\Host The Host object with all the info.
139
     * @throws InvalidTokenException
140
     * @throws RateLimitExceedException
141 2
     */
142 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...
143 2
    {
144 2
        $response = $this->makeCurlRequest($this::BASE_URL.$ipAddress);
145
        $response = $this->jsonDecodeResponse($response);
146 2
147
        return new Host($response);
148
    }
149
150
    /**
151
     * Get a specific field value.
152
     *
153
     * @param string $ipAddress The ip address.
154
     * @param string $field The field.
155
     *
156
     * @return string|\DavidePastore\Ipinfo\Host The value of the given field for the given ip.
157
     *                                           This could returns an Host object if you call it with for the field
158
     *                                           \DavidePastore\Ipinfo\Ipinfo::GEO.
159
     * @throws InvalidTokenException
160
     * @throws RateLimitExceedException
161 6
     */
162 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...
163 6
    {
164 6
        $response = $this->makeCurlRequest($this::BASE_URL.$ipAddress.'/'.$field);
165
        $response = $this->checkGeo($field, $response);
166 5
167
        return $response;
168
    }
169
170
    /**
171
     * Get a specific field value of your own ip address.
172
     *
173
     * @param string $field The field.
174
     *
175
     * @return string|\DavidePastore\Ipinfo\Host The value of the given field for your own ip.
176
     *                                           This could returns an Host object if you call it with for the field
177
     *                                           \DavidePastore\Ipinfo\Ipinfo::GEO.
178
     * @throws InvalidTokenException
179
     * @throws RateLimitExceedException
180 1
     */
181 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...
182 1
    {
183 1
        $response = $this->makeCurlRequest($this::BASE_URL.$field);
184
        $response = $this->checkGeo($field, $response);
185 1
186
        return $response;
187
    }
188
189
    /**
190
     * Use the /geo call to get just the geolocation information, which will often be
191
     * faster than getting the full response.
192
     *
193
     * @param string $ipAddress The ip address.
194
     *
195
     * @return \DavidePastore\Ipinfo\Host
196
     * @throws InvalidTokenException
197
     * @throws RateLimitExceedException
198 2
     */
199
    public function getIpGeoDetails($ipAddress)
200 2
    {
201
        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 201 which is incompatible with the return type documented by DavidePastore\Ipinfo\Ipinfo::getIpGeoDetails of type DavidePastore\Ipinfo\Host.
Loading history...
202
    }
203
204
    /**
205
     * Check if the response is GEO and set the parameters accordingly.
206
     *
207
     * @param string $field The field value.
208
     * @param string $response The response from the server.
209
     *
210
     * @return \DavidePastore\Ipinfo\Host|string Returns an Host object if the request is
211
     *                  of the GEO type, a string otherwise. If the field value is different from the GEO type, it will
212
     *                  delete the last character ('\n').
213
     * @throws InvalidTokenException
214
     * @throws RateLimitExceedException
215 7
     */
216
    private function checkGeo($field, $response)
217 7
    {
218 2
        if ($field == $this::GEO) {
219 2
            $response = $this->jsonDecodeResponse($response);
220 2
            $response = new Host($response);
221 5
        } else {
222 4
            $this->checkErrors($response);
223
            $response = substr($response, 0, -1);
224
        }
225 6
226
        return $response;
227
    }
228
229
    /**
230
     * Make a curl request.
231
     *
232
     * @param string $address The address of the request.
233
     *
234
     * @return string Returns the response from the request.
235 11
     */
236
    private function makeCurlRequest($address)
237 11
    {
238
        $curl = curl_init();
239 11
240 2
        if (!empty($this->settings['token'])) {
241 2
            $address .= '?token='.$this->settings['token'];
242
        }
243 11
244 1
        if ($this->settings['debug']) {
245 1
            echo 'Request address: '.$address."\n";
246
        }
247 11
248 11
        curl_setopt_array(
249 11
            $curl,
250 11
            array_replace(
251
                $this->settings['curlOptions'],
252 11
                array(
253 11
                    CURLOPT_RETURNTRANSFER => 1,
254 11
                    CURLOPT_URL => $address
255 11
                )
256 11
            )
257
        );
258 11
259
        $response = curl_exec($curl);
260 11
261
        if (curl_errno($curl)) {
262
            $errorMessage = curl_error($curl);
263
264
            if ($this->settings['debug']) {
265 11
                echo "The error is".$errorMessage;
266
            }
267 11
        }
268
269
        if (isset($errorMessage)) {
270
            throw new IpInfoException('cURL error', $errorMessage);
271
        }
272
273
        curl_close($curl);
274
275
        return $response;
276
    }
277 6
278
    /**
279 6
     * Returns the json decoded associative array.
280
     * @param  string $response Response from the http call.
281 5
     * @return array           Returns the associative array with the response.
282 4
     * @throws RateLimitExceedException    If you exceed the rate limit.
283 4
     * @throws InvalidTokenException If the used token is invalid.
284 1
     */
285
    private function jsonDecodeResponse($response)
286 5
    {
287
        if ($response) {
288
            // Check if the response contains an error message
289
            $this->checkErrors($response);
290
            $response = json_decode($response, true);
291
        } else {
292
            $response = array();
293
        }
294
        return $response;
295 10
    }
296
297 10
    /**
298 1
     * Check if the given response has some kind of errors.
299 9
     * @param string $response The response to check.
300 1
     * @throws RateLimitExceedException    If you exceed the rate limit.
301
     * @throws InvalidTokenException If the used token is invalid.
302 8
     */
303
    private function checkErrors($response)
304 1
    {
305
        if (strpos($response, 'Rate limit exceeded.') !== false) {
306
            throw new RateLimitExceedException("You exceed the rate limit.", $response);
307
        } elseif (strpos($response, 'Unknown token') !== false) {
308
            throw new InvalidTokenException("The used token is invalid.", $response);
309
        }
310
    }
311
}
312