self::getIPv4($force), 'ipv6' => self::getIPv6($force), ]; } public static function getIPv4(bool $force = false): ?string { // 1) ENV zuerst $env = trim((string) env('SERVER_PUBLIC_IPV4', '')); if ($env !== '' && filter_var($env, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return $env; } // 2) Cache if (!$force) { $c = Cache::get('netprobe:ipv4'); if ($c) return $c === 'none' ? null : $c; } // 3) Probe (einmalig) $ip = self::probeIPv4(); Cache::put('netprobe:ipv4', $ip ?: 'none', now()->addDay()); return $ip; } public static function getIPv6(bool $force = false): ?string { // 1) ENV zuerst $env = trim((string) env('SERVER_PUBLIC_IPV6', '')); if ($env !== '' && filter_var($env, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return $env; } // 2) Cache mit Sentinel „none“ (verhindert Endlossuche) if (!$force) { $c = Cache::get('netprobe:ipv6'); if ($c) return $c === 'none' ? null : $c; } // 3) Probe (einmalig) $ip = self::probeIPv6(); Cache::put('netprobe:ipv6', $ip ?: 'none', now()->addDay()); return $ip; } // — intern — protected static function probeIPv4(): ?string { $out = @shell_exec("ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'"); $ip = trim((string) $out); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) return $ip; $ip = trim($_SERVER['SERVER_ADDR'] ?? ''); return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? $ip : null; } protected static function probeIPv6(): ?string { // Variante 1: „Standard“-Weg über Routing $out = @shell_exec("ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'"); $ip = trim((string) $out); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return $ip; // Variante 2: irgendeine globale v6 vom Interface nehmen (keine ::1, keine link-local fe80:) $out = @shell_exec("ip -6 addr show scope global 2>/dev/null | awk '/inet6/ && $2 !~ /::1/ && $2 !~ /^fe80:/ {print $2; exit}'"); $ip = trim((string) $out); if ($ip !== '') $ip = strtok($ip, '/'); // Prefix entfernen return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $ip : null; } }