-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPublicIpResolver.php
More file actions
96 lines (82 loc) · 2.91 KB
/
Copy pathPublicIpResolver.php
File metadata and controls
96 lines (82 loc) · 2.91 KB
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
<?php
/**
* Resolves the current public IPv4 and IPv6 addresses from configured providers.
* It only handles detection and basic validation.
*/
final class PublicIpResolver
{
private array $ipv4Providers;
private array $ipv6Providers;
private Logger $logger;
private int $connectTimeout;
private int $requestTimeout;
public function __construct(
array $ipv4Providers,
array $ipv6Providers,
Logger $logger,
int $connectTimeout,
int $requestTimeout
)
{
$this->ipv4Providers = $ipv4Providers;
$this->ipv6Providers = $ipv6Providers;
$this->logger = $logger;
$this->connectTimeout = $connectTimeout;
$this->requestTimeout = $requestTimeout;
}
public function resolve(string $family = 'ipv4'): ?string
{
$providers = $family === 'ipv6' ? $this->ipv6Providers : $this->ipv4Providers;
foreach ($providers as $provider) {
$ip = $this->requestIp($provider);
if ($ip === null) {
continue;
}
if ($this->isValidForFamily($ip, $family)) {
return $ip;
}
$this->logger->warning('Public IP provider returned an invalid response', array(
'provider' => $provider,
'family' => $family,
));
}
return null;
}
private function requestIp(string $provider): ?string
{
$ch = curl_init($provider);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_USERAGENT, AppInfo::userAgent());
$response = curl_exec($ch);
if ($response === false) {
$this->logger->warning('Public IP detection provider failed', array(
'provider' => $provider,
'error' => curl_error($ch),
));
curl_close($ch);
return null;
}
$statusCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($statusCode < 200 || $statusCode >= 300) {
$this->logger->warning('Public IP detection provider returned a non-success status', array(
'provider' => $provider,
'status' => $statusCode,
));
return null;
}
return trim($response);
}
private function isValidForFamily(string $value, string $family): bool
{
if ($family === 'ipv6') {
return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
}
return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
}
}