trim((string)($_POST['tenant_name'] ?? '')), 'tenant_slug' => trim((string)($_POST['tenant_slug'] ?? '')), 'display_name' => trim((string)($_POST['display_name'] ?? '')), 'email' => trim((string)($_POST['email'] ?? '')), 'customer_type' => (string)($_POST['customer_type'] ?? ''), ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { app_require_csrf(); // Reihenfolge mit Absicht: erst die billigen Bot-Merkmale, dann die // Rate-Limits, erst danach die DNS-Abfrage. Alle Abweisungen bis // einschliesslich Rate-Limit nennen denselben generischen Text, damit die // Antwort nicht verraet, welche Huerde angeschlagen hat. $genericRejection = 'Zu viele Registrierungsversuche. Bitte versuche es später erneut.'; if (app_spam_guard_honeypot_tripped()) { app_spam_guard_log('register', 'honeypot'); $errors = [$genericRejection]; } elseif (app_spam_guard_submitted_too_fast('register')) { app_spam_guard_log('register', 'zu schnell abgesendet'); $errors = [$genericRejection]; } elseif (!app_rate_limit_check($pdo, 'register_ip:' . app_client_ip(), 5, 3600)) { $errors = [$genericRejection]; } elseif (!app_rate_limit_check($pdo, 'register_global', APP_SPAM_GUARD_GLOBAL_MAX, APP_SPAM_GUARD_GLOBAL_WINDOW)) { // Notbremse gegen verteilte Bots: die kommen je ueber eine eigene IP, // an der das IP-Limit nie anschlaegt. app_spam_guard_log('register', 'globales Limit'); $errors = [$genericRejection]; } elseif (filter_var($values['email'], FILTER_VALIDATE_EMAIL) !== false && !app_spam_guard_email_domain_resolves($values['email'])) { // Hier bewusst konkret: das ist typischerweise ein Tippfehler in der // Domain, und der Hinweis hilft einem echten Nutzer weiter. $errors = ['Zu dieser E-Mail-Adresse gibt es keine erreichbare Mail-Domain. Bitte prüfe die Schreibweise.']; } else { $result = saas_register_tenant_owner($pdo, [ 'tenant_name' => $values['tenant_name'], 'tenant_slug' => $values['tenant_slug'], 'display_name' => $values['display_name'], 'email' => $values['email'], 'password' => (string)($_POST['password'] ?? ''), 'password_confirm' => (string)($_POST['password_confirm'] ?? ''), 'customer_type' => $values['customer_type'], 'accept_terms' => !empty($_POST['accept_terms']), 'acknowledge_privacy' => !empty($_POST['acknowledge_privacy']), 'accept_dpa' => !empty($_POST['accept_dpa']), ]); if ($result['ok']) { $contractMail = saas_send_registration_contract_mail( $values['email'], $values['tenant_name'], (string)$result['identity']['tenant_slug'], $values['customer_type'] ); $verificationMail = ['ok' => true]; if (!empty($result['email_verification_token'])) { $verificationMail = saas_send_email_verification_mail($values['email'], (string)$result['email_verification_token']); } // Betreiber-Push ueber die Neuanmeldung. Bewusst hier statt in // saas_register_tenant_owner(), damit die check-*-Skripte in // scripts/ keine Pushes ausloesen. Das Ergebnis wird nicht // ausgewertet: ein fehlgeschlagener Push darf die Registrierung // nie stoppen, er landet nur im PHP-Error-Log. pushover_notify_new_tenant( $values['tenant_name'], (string)$result['identity']['tenant_slug'], $values['email'], $values['customer_type'] ); saas_session_login($result['identity']); if (empty($contractMail['ok'])) { $_SESSION['saas_contract_mail_failed'] = true; } if (empty($verificationMail['ok'])) { $_SESSION['saas_verification_mail_failed'] = true; } if (saas_should_show_auth_links() && !empty($result['email_verification_token'])) { $_SESSION['saas_dev_email_verification_token'] = (string)$result['email_verification_token']; } header('Location: konto.php?registered=1'); exit; } $errors = $result['errors']; } } ?>
Lege kostenlos einen neuen Kundenbereich an. Das Angebot kann privat oder geschäftlich genutzt werden.