-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathGeoService.php
200 lines (167 loc) · 6.78 KB
/
GeoService.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?php
/**
* Geo Cookie plugin for Craft CMS 3.x
*
* Collect information about a visitor's location based on their IP address and store the information as a cookie.
*
* @link https://github.com/lukeyouell
* @copyright Copyright (c) 2017 Luke Youell
*/
namespace lukeyouell\geocookie\services;
use lukeyouell\geocookie\GeoCookie;
use lukeyouell\geocookie\records\Log as LogRecord;
use Craft;
use craft\base\Component;
class GeoService extends Component
{
// Public Methods
// =========================================================================
public function location()
{
// Get settings
$settings = GeoCookie::$plugin->getSettings();
// Request ip address
$ipAddress = $this->getIpAddress($settings);
// Request cookie
$cookie = $this->getCookie($settings);
if ($cookie) {
// Cookie already exists, so set the location as the cookie value and set 'cached' to true to show that the cookie already existed
$location = @unserialize($cookie->value);
if ($location === false) {
$location = $cookie->value;
}
$location->cached = true;
return $location;
} else {
// Cookie doesn't exist, so fetch the user's location using api source and store it as a cookie, set 'cached' to false to show that the cookie didn't exist
$apiSource = $settings->apiSource;
$location = unserialize($this->getLocation($settings, $ipAddress));
// $location->cached = false;
// Log this
GeoCookie::$plugin->logService->insertLog(LogRecord::STATUS_SUCCESS, $apiSource, $location);
return $location;
}
}
public function getIpAddress($settings)
{
// Request visitor's ip address, if unable to do so use the fallback value
$ipAddress = Craft::$app->request->getUserIP();
if (!$ipAddress) {
// Unable to source ip address so use fallback value
$ipAddress = $settings->fallbackIp;
}
// If anonymisation is enabled
if ($settings->anonymisation) {
// Check if ip address is ipv4 or ipv6
if (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
// ip address is ipv4
$delimiter = '.';
$explode = explode($delimiter, $ipAddress);
} elseif (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
// ip address is ipv6
$delimiter = ':';
$explode = explode($delimiter, $ipAddress);
} else {
// ip address is neither ipv4 or ipv6
$explode = false;
}
if ($explode) {
// Fetch last element
$lastElement = count($explode) - 1;
// Set last element as 0 (anonymising the ip address)
$explode[$lastElement] = '0';
// Update ip address with anonymised version by imploding
$ipAddress = implode($delimiter, $explode);
}
}
return $ipAddress;
}
public function getCookie($settings)
{
// Request cookie to check if it already exists
$cookie = Craft::$app->request->cookies->get($settings->cookieName);
if ($cookie) {
// Cookie exists, so return the cookie object
return $cookie;
} else {
// Cookie doesn't exist so return false
return false;
}
}
public function getLocation($settings, $ipAddress)
{
// Request location based on ip address
// Set client based on preferred api source
switch ($settings->apiSource) {
case 'dbip':
$clientUrl = 'http://api.db-ip.com';
$clientPath = 'v2/'.$settings->apiKey.'/'.$ipAddress;
break;
case 'extremeiplookup':
$clientUrl = 'https://extreme-ip-lookup.com';
$clientPath = 'json/'.$ipAddress;
break;
case 'freegeoip':
$clientUrl = 'https://freegeoip.net';
$clientPath = 'json/'.$ipAddress;
break;
case 'ipapi':
$clientUrl = 'https://ipapi.co';
$clientPath = $ipAddress.'/json';
break;
case 'ipapicom':
$clientUrl = 'http://ip-api.com';
$clientPath = 'json/'.$ipAddress;
break;
case 'ipfind':
$clientUrl = 'https://ipfind.co';
$clientPath = '?ip='.$ipAddress.'&auth='.$settings->apiKey;
break;
case 'ipinfo':
$clientUrl = 'https://ipinfo.io';
$clientPath = $ipAddress.'/json';
break;
case 'ipvigilante':
$clientUrl = 'https://ipvigilante.com';
$clientPath = $ipAddress;
break;
case 'keycdn':
$clientUrl = 'https://tools.keycdn.com';
$clientPath = 'geo.json?host='.$ipAddress;
break;
default:
$clientUrl = 'https://ipapi.co';
$clientPath = $ipAddress.'/json';
}
$client = new \GuzzleHttp\Client([
'base_uri' => $clientUrl,
'http_errors' => false,
'timeout' => $settings->requestTimeout
]);
try {
$response = $client->request('GET', $clientPath);
if ($response->getStatusCode() === 200) {
// Request was successful, so decode json response and store as a cookie
$location = json_decode($response->getBody());
$location->cached = false;
$cookies = Craft::$app->response->cookies;
$cookies->add(new \yii\web\Cookie([
'name' => $settings->cookieName,
'value' => serialize($location),
// current timestamp + (cookieDuration setting in hours x number of seconds in an hour)
'expire' => time() + ($settings->cookieDuration * 3600)
]));
$cookie = $cookies->get($settings->cookieName);
return $cookie->value;
} else {
// Log warning
Craft::error((string)$response->getBody(), 'geocookie');
return (object) array('error' => true, 'statusCode' => $response->getStatusCode());
}
} catch (\Exception $e) {
// Log error
Craft::error($e->getMessage(), 'geocookie');
return (object) array('error' => true, 'errorMessage' => $e->getMessage());
}
}
}