95 lines
1.9 KiB
PHP
95 lines
1.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Adres IP klienta (pierwszy z X-Forwarded-For lub REMOTE_ADDR).
|
|
*/
|
|
function getRequestClientIp(): string
|
|
{
|
|
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
$parts = explode(',', (string) $_SERVER['HTTP_X_FORWARDED_FOR']);
|
|
|
|
return trim($parts[0]);
|
|
}
|
|
|
|
return trim((string) ($_SERVER['REMOTE_ADDR'] ?? ''));
|
|
}
|
|
|
|
/**
|
|
* Pojedyncze IP z pominięciem geo (zewnętrzne, dev, przykładowe hosty LAN).
|
|
*/
|
|
function getGeoBypassTrustedIps(): array
|
|
{
|
|
return [
|
|
'82.160.190.247',
|
|
'127.0.0.1',
|
|
'::1',
|
|
'192.168.20.84',
|
|
'10.0.0.3',
|
|
'10.0.0.7',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Pule wewnętrznych sieci — goście widziani przez lokalny serwer (REMOTE_ADDR z LAN).
|
|
*/
|
|
function getGeoBypassTrustedCidrs(): array
|
|
{
|
|
return [
|
|
'10.0.0.0/24',
|
|
];
|
|
}
|
|
|
|
function normalizeClientIp(string $ip): string
|
|
{
|
|
if (strpos($ip, '::ffff:') === 0) {
|
|
return substr($ip, 7);
|
|
}
|
|
|
|
return $ip;
|
|
}
|
|
|
|
function ipv4InCidr(string $ip, string $cidr): bool
|
|
{
|
|
if (!str_contains($cidr, '/')) {
|
|
return false;
|
|
}
|
|
|
|
[$subnet, $bits] = explode('/', $cidr, 2);
|
|
$bits = (int) $bits;
|
|
if ($bits < 0 || $bits > 32) {
|
|
return false;
|
|
}
|
|
|
|
$ipLong = ip2long($ip);
|
|
$subnetLong = ip2long($subnet);
|
|
if ($ipLong === false || $subnetLong === false) {
|
|
return false;
|
|
}
|
|
|
|
$mask = $bits === 0 ? 0 : (-1 << (32 - $bits)) & 0xFFFFFFFF;
|
|
|
|
return ($ipLong & $mask) === ($subnetLong & $mask);
|
|
}
|
|
|
|
function isGeoBypassTrustedIp(string $ip): bool
|
|
{
|
|
$ip = normalizeClientIp($ip);
|
|
if ($ip === '') {
|
|
return false;
|
|
}
|
|
|
|
if (in_array($ip, getGeoBypassTrustedIps(), true)) {
|
|
return true;
|
|
}
|
|
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
foreach (getGeoBypassTrustedCidrs() as $cidr) {
|
|
if (ipv4InCidr($ip, $cidr)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|