Files
karczma-aplikacja-stoliki/api/request_ip.php
2026-06-10 20:31:48 +02:00

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;
}