-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathIPinfo.php
141 lines (119 loc) · 4.11 KB
/
IPinfo.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
namespace ipinfo\ipinfo;
require_once(__DIR__.'/cache/Default.php');
use GuzzleHttp\Exception\TransferException;
use ipinfo\ipinfo\Details;
/**
* Exposes the IPinfo library to client code.
*/
class IPinfo
{
const API_URL = 'https://ipinfo.io';
const CACHE_MAXSIZE = 4096;
const CACHE_TTL = 60 * 60 * 24;
const COUNTRIES_FILE_DEFAULT = __DIR__ . '/countries.json';
const REQUEST_TYPE_GET = 'GET';
const STATUS_CODE_QUOTA_EXCEEDED = 429;
public $access_token;
public $cache;
public $countries;
protected $http_client;
public function __construct($access_token = null, $settings = [])
{
$this->access_token = $access_token;
$this->http_client = new \GuzzleHttp\Client(['http_errors' => false]);
$countries_file = $settings['countries_file'] ?? self::COUNTRIES_FILE_DEFAULT;
$this->countries = $this->readCountryNames($countries_file);
if (array_key_exists('cache', $settings)) {
$this->cache = $settings['cache'];
} else {
$maxsize = $settings['cache_maxsize'] ?? self::CACHE_MAXSIZE;
$ttl = $settings['cache_ttl'] ?? self::CACHE_TTL;
$this->cache = new cache\DefaultCache($maxsize, $ttl);
}
}
/**
* Get formatted details for an IP address.
* @param string|null $ip_address IP address to look up.
* @return Details Formatted IPinfo data.
*/
public function getDetails($ip_address = null)
{
$response_details = $this->getRequestDetails((string) $ip_address);
return $this->formatDetailsObject($response_details);
}
/**
* Format details and return as an object.
* @param array $details IP address details.
* @return Details Formatted IPinfo Details object.
*/
public function formatDetailsObject($details = [])
{
$country = $details['country'] ?? null;
$details['country_name'] = $this->countries[$country] ?? null;
if (array_key_exists('loc', $details)) {
$coords = explode(',', $details['loc']);
$details['latitude'] = $coords[0];
$details['longitude'] = $coords[1];
} else {
$details['latitude'] = null;
$details['longitude'] = null;
}
return new Details($details);
}
/**
* Get details for a specific IP address.
* @param string $ip_address IP address to query API for.
* @return array IP response data.
*/
public function getRequestDetails(string $ip_address)
{
if (!$this->cache->has($ip_address)) {
$url = self::API_URL;
if ($ip_address) {
$url .= "/$ip_address";
}
$response = $this->http_client->request(
self::REQUEST_TYPE_GET,
$url,
$this->buildHeaders()
);
if ($response->getStatusCode() == self::STATUS_CODE_QUOTA_EXCEEDED) {
throw new Exception('IPinfo request quota exceeded.');
} elseif ($response->getStatusCode() >= 400) {
throw new Exception('Exception: ' . json_encode([
'status' => $response->getStatusCode(),
'reason' => $response->getReasonPhrase(),
]));
}
$raw_details = json_decode($response->getBody(), true);
$this->cache->set($ip_address, $raw_details);
}
return $this->cache->get($ip_address);
}
/**
* Build headers for API request.
* @return array Headers for API request.
*/
public function buildHeaders()
{
$headers = [
'user-agent' => 'IPinfoClient/PHP/1.0',
'accept' => 'application/json',
];
if ($this->access_token) {
$headers['authorization'] = "Bearer {$this->access_token}";
}
return ['headers' => $headers];
}
/**
* Read country names from a file and return as an array.
* @param string $countries_file JSON file of country_code => country_name mappings
* @return array country_code => country_name mappings
*/
private function readCountryNames($countries_file)
{
$file_contents = file_get_contents($countries_file);
return json_decode($file_contents, true);
}
}