Passed
Push — master ( ae7124...f41d72 )
by Davide
02:18 queued 28s
created

Ipinfo   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 289
Duplicated Lines 9.69 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 96.55%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 3
dl 28
loc 289
ccs 56
cts 58
cp 0.9655
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A checkErrors() 0 8 3
A getYourOwnIpDetails() 7 7 1
A getFullIpDetails() 7 7 1
A getSpecificField() 7 7 1
A getYourOwnIpSpecificField() 7 7 1
A getIpGeoDetails() 0 4 1
A checkGeo() 0 12 2
A makeCurlRequest() 0 32 5
A jsonDecodeResponse() 0 11 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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