'', 'api_key' => '', 'department_id' => 0, 'topic_id' => 0, 'priority_id' => 0, 'consent_text' => '', 'accent_color' => '', 'attachments' => 1, 'success_text' => '', 'status_page_url' => '', 'min_seconds' => 3, 'rate_limit_per_hour' => 5, 'turnstile_site' => '', 'turnstile_secret' => '', ]; } /** Alle Einstellungen (mit Standardwerten). Server-Adresse und Schlüssel lassen sich zusätzlich in der wp-config.php festlegen. */ function deskhub_tickets_options(): array { $saved = get_option('deskhub_tickets_options', []); $opts = array_merge(deskhub_tickets_defaults(), is_array($saved) ? $saved : []); if (defined('DESKHUB_TICKETS_SERVER') && DESKHUB_TICKETS_SERVER !== '') { $opts['server_url'] = (string) DESKHUB_TICKETS_SERVER; } if (defined('DESKHUB_TICKETS_API_KEY') && DESKHUB_TICKETS_API_KEY !== '') { $opts['api_key'] = (string) DESKHUB_TICKETS_API_KEY; } return $opts; } function deskhub_tickets_option(string $key) { $opts = deskhub_tickets_options(); return $opts[$key] ?? null; } /** Wird der API-Schlüssel aus der wp-config.php genommen (dann ist das Feld in den Einstellungen gesperrt)? */ function deskhub_tickets_key_from_config(): bool { return defined('DESKHUB_TICKETS_API_KEY') && DESKHUB_TICKETS_API_KEY !== ''; } /** * Erkennt den Besucher für die Mengenbegrenzung. Es zählt nur REMOTE_ADDR: Header wie X-Forwarded-For kann jeder selbst setzen. * Steht die Seite hinter einem Proxy, liefert der Filter "deskhub_tickets_client_ip" die richtige Adresse. */ function deskhub_tickets_client_ip(): string { $ip = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : ''; $ip = apply_filters('deskhub_tickets_client_ip', $ip); return filter_var($ip, FILTER_VALIDATE_IP) ? (string) $ip : 'unknown'; } /** Kurzer Schlüssel für einen Besucher (nicht umkehrbar, damit keine IP-Adressen in der Datenbank stehen). */ function deskhub_tickets_visitor_key(string $scope): string { return 'dht_' . substr(hash_hmac('sha256', $scope . '|' . deskhub_tickets_client_ip(), wp_salt('auth')), 0, 32); } /** * Zählt einen Vorgang für den Besucher und sagt, ob er noch erlaubt ist. * $max Vorgänge je $window Sekunden; false = Grenze erreicht (der Vorgang wird dann nicht mehr gezählt). */ function deskhub_tickets_rate_allow(string $scope, int $max, int $window): bool { if ($max <= 0) { return true; } $key = deskhub_tickets_visitor_key($scope); $count = (int) get_transient($key); if ($count >= $max) { return false; } set_transient($key, $count + 1, $window); return true; } /** Unterschreibt Angaben, die durchs Formular laufen (Abteilung, Thema, Priorität), damit Besucher sie nicht ändern können. */ function deskhub_tickets_sign(string $payload): string { return hash_hmac('sha256', $payload, wp_salt('auth')); } function deskhub_tickets_verify_signature(string $payload, string $signature): bool { return $signature !== '' && hash_equals(deskhub_tickets_sign($payload), $signature); } /** Zeitstempel mit Unterschrift: beweist, wann das Formular angezeigt wurde (Schutz vor Robotern, die sofort absenden). */ function deskhub_tickets_timestamp_token(): string { $t = (string) time(); return $t . '.' . deskhub_tickets_sign('ts|' . $t); } /** Alter des Formulars in Sekunden; null, wenn der Wert fehlt oder gefälscht ist. */ function deskhub_tickets_timestamp_age(string $token): ?int { if (!preg_match('/^(\d{9,11})\.([a-f0-9]{64})$/', $token, $m)) { return null; } if (!deskhub_tickets_verify_signature('ts|' . $m[1], $m[2])) { return null; } return time() - (int) $m[1]; }