$msg]); exit; } // ------------------------------------------------------- // Client IP (respects proxy headers cautiously) // ------------------------------------------------------- function client_ip(): string { // Only trust X-Forwarded-For if behind a known proxy if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); return trim($ips[0]); } return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } // ------------------------------------------------------- // File-based rate limiting // ------------------------------------------------------- function rate_limit(string $key, int $maxRequests, int $window): void { $dir = defined('RATE_LIMIT_DIR') ? RATE_LIMIT_DIR : sys_get_temp_dir() . '/sf_rl'; if (!is_dir($dir)) { @mkdir($dir, 0700, true); } $file = $dir . '/' . hash('sha256', $key) . '.json'; $now = time(); $data = ['count' => 0, 'reset' => $now + $window]; if (file_exists($file)) { $stored = json_decode(file_get_contents($file), true); if (is_array($stored) && $stored['reset'] > $now) { $data = $stored; } } $data['count']++; file_put_contents($file, json_encode($data), LOCK_EX); if ($data['count'] > $maxRequests) { http_response_code(429); echo json_encode(['error' => 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.']); exit; } } // ------------------------------------------------------- // Haversine distance (km) // ------------------------------------------------------- function haversine(float $lat1, float $lon1, float $lat2, float $lon2): int { $R = 6371; $dLat = deg2rad($lat2 - $lat1); $dLon = deg2rad($lon2 - $lon1); $a = sin($dLat / 2) ** 2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) ** 2; $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return (int) round($R * $c); } // ------------------------------------------------------- // SMTP send (basic, without PHPMailer) // For production, install PHPMailer via Composer and // replace this function body accordingly. // ------------------------------------------------------- function send_smtp(string $subject, string $body, string $headers): void { // Placeholder – integrate PHPMailer here: // // require __DIR__ . '/../vendor/autoload.php'; // $mail = new PHPMailer\PHPMailer\PHPMailer(true); // $mail->isSMTP(); // $mail->Host = SMTP_HOST; // $mail->SMTPAuth = true; // $mail->Username = SMTP_USER; // $mail->Password = SMTP_PASS; // $mail->SMTPSecure = SMTP_SECURE; // $mail->Port = SMTP_PORT; // $mail->setFrom(MAIL_FROM, MAIL_FROM_NAME); // $mail->addAddress(MAIL_TO); // $mail->Subject = $subject; // $mail->Body = $body; // $mail->send(); // Fallback to mail() until PHPMailer is integrated $sent = @mail(MAIL_TO, $subject, $body, $headers); if (!$sent) { error_log('Superfice SMTP fallback mail() failed'); json_error('Beim Senden ist ein Fehler aufgetreten. Bitte schreiben Sie uns direkt.'); } }