Skip to content

Commit a2a1ef0

Browse files
committed
Add resproxy API support
Add getResproxy method to IPinfo for looking up residential proxy information for IP addresses. The resproxy API endpoint returns: - ip: The IP address - last_seen: Last recorded date when the proxy was active - percent_days_seen: Percentage of days active in the last 7-day period - service: Name of the residential proxy service
1 parent e378e66 commit a2a1ef0

3 files changed

Lines changed: 87 additions & 0 deletions

File tree

.phpactor.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "/phpactor.schema.json",
3+
"php_code_sniffer.enabled": true
4+
}

src/IPinfo.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,57 @@ public function getRequestDetails(string $ip_address)
254254
return $raw_details;
255255
}
256256

257+
/**
258+
* Get residential proxy information for an IP address.
259+
* @param string $ip_address IP address to look up.
260+
* @return array Resproxy data containing ip, last_seen, percent_days_seen, service.
261+
* @throws IPinfoException
262+
*/
263+
public function getResproxy(string $ip_address)
264+
{
265+
$cacheKey = "resproxy/$ip_address";
266+
267+
if ($this->cache != null) {
268+
$cachedRes = $this->cache->get($this->cacheKey($cacheKey));
269+
if ($cachedRes != null) {
270+
// The cache may modify the 'ip' field for IPv6 normalization,
271+
// but for resproxy the key contains a prefix, so restore original IP
272+
$cachedRes['ip'] = $ip_address;
273+
return $cachedRes;
274+
}
275+
}
276+
277+
$url = self::API_URL . "/resproxy/$ip_address";
278+
279+
try {
280+
$response = $this->http_client->request('GET', $url);
281+
} catch (GuzzleException $e) {
282+
throw new IPinfoException($e->getMessage());
283+
} catch (Exception $e) {
284+
throw new IPinfoException($e->getMessage());
285+
}
286+
287+
if ($response->getStatusCode() == self::STATUS_CODE_QUOTA_EXCEEDED) {
288+
throw new IPinfoException('IPinfo request quota exceeded.');
289+
} elseif ($response->getStatusCode() >= 400) {
290+
throw new IPinfoException(
291+
'Exception: ' .
292+
json_encode([
293+
'status' => $response->getStatusCode(),
294+
'reason' => $response->getReasonPhrase(),
295+
]),
296+
);
297+
}
298+
299+
$details = json_decode($response->getBody(), true);
300+
301+
if ($this->cache != null) {
302+
$this->cache->set($this->cacheKey($cacheKey), $details);
303+
}
304+
305+
return $details;
306+
}
307+
257308
/**
258309
* Gets a URL to a map on https://ipinfo.io/map given a list of IPs (max
259310
* 500,000).

tests/IPinfoTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,4 +405,36 @@ public function testIPv6NotationsCaching()
405405
$normalized_ip = inet_ntop(inet_pton($standard_ip));
406406
$h->getDetails($normalized_ip);
407407
}
408+
409+
public function testResproxy()
410+
{
411+
$tok = getenv('IPINFO_TOKEN');
412+
if (!$tok) {
413+
$this->markTestSkipped('IPINFO_TOKEN env var required');
414+
}
415+
416+
$h = new IPinfo($tok);
417+
$ip = '175.107.211.204';
418+
419+
// test multiple times for cache hits
420+
for ($i = 0; $i < 5; $i++) {
421+
$res = $h->getResproxy($ip);
422+
$this->assertEquals($res['ip'], $ip);
423+
$this->assertNotNull($res['last_seen']);
424+
$this->assertNotNull($res['percent_days_seen']);
425+
$this->assertNotNull($res['service']);
426+
}
427+
}
428+
429+
public function testResproxyEmpty()
430+
{
431+
$tok = getenv("IPINFO_TOKEN");
432+
if (!$tok) {
433+
$this->markTestSkipped("IPINFO_TOKEN env var required");
434+
}
435+
436+
$h = new IPinfo($tok);
437+
$res = $h->getResproxy("8.8.8.8");
438+
$this->assertEquals($res, []);
439+
}
408440
}

0 commit comments

Comments
 (0)