, "plz": "XXXXX" } * or { "error": "" } * * Uses OpenStreetMap Nominatim for geocoding (free, no API key needed). * For production traffic, replace with Google Maps or a local PLZ dataset. */ require_once __DIR__ . '/config.php'; require_once __DIR__ . '/helpers.php'; header('Content-Type: application/json; charset=utf-8'); cors_headers(); // ------------------------------------------------------- // Input validation // ------------------------------------------------------- $plz = isset($_GET['plz']) ? preg_replace('/[^0-9]/', '', trim($_GET['plz'])) : ''; if (strlen($plz) !== 5) { json_error('Ungültige PLZ. Bitte geben Sie eine 5-stellige Postleitzahl ein.'); } // ------------------------------------------------------- // Rate limiting // ------------------------------------------------------- rate_limit('dist_' . client_ip(), RATE_LIMIT_DISTANCE, RATE_LIMIT_WINDOW); // ------------------------------------------------------- // Geocode PLZ via Nominatim // ------------------------------------------------------- $url = sprintf( 'https://nominatim.openstreetmap.org/search?postalcode=%s&country=de&format=json&limit=1&addressdetails=0', urlencode($plz) ); $ctx = stream_context_create([ 'http' => [ 'header' => "User-Agent: SuperficeWebsite/1.0 (info@superfice.de)\r\n", 'timeout' => 5, 'ignore_errors' => true, ], 'ssl' => [ 'verify_peer' => true, 'verify_peer_name'=> true, ], ]); $raw = @file_get_contents($url, false, $ctx); if ($raw === false) { json_error('PLZ-Suche momentan nicht verfügbar. Bitte versuchen Sie es später erneut.'); } $data = json_decode($raw, true); if (empty($data) || !isset($data[0]['lat'], $data[0]['lon'])) { json_error('PLZ nicht gefunden. Bitte prüfen Sie Ihre Eingabe.'); } $lat = (float) $data[0]['lat']; $lon = (float) $data[0]['lon']; // ------------------------------------------------------- // Haversine distance to HQ // ------------------------------------------------------- $distance = haversine(HQ_LAT, HQ_LON, $lat, $lon); echo json_encode([ 'distance' => $distance, 'plz' => $plz, ]);