From 976b3579527009beab916a834c026862e21ee319 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 05:44:46 +0000 Subject: [PATCH] SMS-Versand (Twilio): includes/Sms.php + Option im Voucher-Formular + Settings --- admin/integrations.php | 19 +++++++++++++++++++ includes/Sms.php | 42 ++++++++++++++++++++++++++++++++++++++++++ index.php | 26 +++++++++++++++++++++++--- 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 includes/Sms.php diff --git a/admin/integrations.php b/admin/integrations.php index f7872aa..23dde39 100644 --- a/admin/integrations.php +++ b/admin/integrations.php @@ -28,6 +28,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save'])) { $db->setSetting('captcha_mode', $cm); $db->setSetting('captcha_site_key', trim($_POST['captcha_site_key'] ?? '')); if (!empty($_POST['captcha_secret'])) { $db->setSetting('captcha_secret', trim($_POST['captcha_secret'])); } + $db->setSetting('sms_enabled', isset($_POST['sms_enabled']) ? '1' : '0'); + $db->setSetting('twilio_sid', trim($_POST['twilio_sid'] ?? '')); + $db->setSetting('twilio_from', trim($_POST['twilio_from'] ?? '')); + if (!empty($_POST['twilio_token'])) { $db->setSetting('twilio_token', trim($_POST['twilio_token'])); } $db->setSetting('user_daily_voucher_limit', max(0, (int)($_POST['user_daily_voucher_limit'] ?? 0))); $db->setSetting('trusted_proxy', trim($_POST['trusted_proxy'] ?? '')); $db->setSetting('webhook_enabled', isset($_POST['webhook_enabled']) ? '1' : '0'); @@ -49,6 +53,10 @@ $enforce2fa = $db->getSetting('enforce_2fa_admins', '0') === '1'; $captchaMode = $db->getSetting('captcha_mode', 'off'); $captchaSiteKey = $db->getSetting('captcha_site_key', ''); $captchaSecretSet = $db->getSetting('captcha_secret', '') !== ''; +$smsEnabled = $db->getSetting('sms_enabled', '0') === '1'; +$twilioSid = $db->getSetting('twilio_sid', ''); +$twilioFrom = $db->getSetting('twilio_from', ''); +$twilioTokenSet = $db->getSetting('twilio_token', '') !== ''; $dailyLimit = (int)$db->getSetting('user_daily_voucher_limit', 0); $trustedProxy = $db->getSetting('trusted_proxy', ''); $webhookEnabled = $db->getSetting('webhook_enabled', '0') === '1'; @@ -126,6 +134,17 @@ label { display:block; font-size:14px; color:var(--text-secondary); margin:14px +
+

SMS-Versand (Twilio)

+

Voucher-Codes optional per SMS versenden. Erfordert ein Twilio-Konto.

+ +
+
+
+
+
+
+

Datenhaltung & Cleanup (DSGVO)

Aufbewahrungsfristen in Tagen (0 = deaktiviert). Ausführung per cron_cleanup.php (täglich empfohlen). diff --git a/includes/Sms.php b/includes/Sms.php new file mode 100644 index 0000000..c055c71 --- /dev/null +++ b/includes/Sms.php @@ -0,0 +1,42 @@ +getSetting('sms_enabled', '0') === '1' + && $db->getSetting('twilio_sid', '') !== '' + && $db->getSetting('twilio_token', '') !== '' + && $db->getSetting('twilio_from', '') !== ''; + } + + /** Sendet eine SMS. Gibt true bei Erfolg zurück. */ + public static function send($db, $to, $text) { + if (!self::enabled($db)) { + return false; + } + $sid = (string)$db->getSetting('twilio_sid', ''); + $token = (string)$db->getSetting('twilio_token', ''); + $from = (string)$db->getSetting('twilio_from', ''); + + $ch = curl_init("https://api.twilio.com/2010-04-01/Accounts/" . rawurlencode($sid) . "/Messages.json"); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_USERPWD => $sid . ':' . $token, + CURLOPT_POSTFIELDS => http_build_query(['From' => $from, 'To' => $to, 'Body' => $text]), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 10, + ]); + $out = curl_exec($ch); + $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300) { + return true; + } + error_log("Sms(Twilio) Fehler HTTP $code: " . substr((string)$out, 0, 200)); + return false; + } +} diff --git a/index.php b/index.php index 58d3036..2cfafc0 100644 --- a/index.php +++ b/index.php @@ -18,6 +18,7 @@ require_once __DIR__ . '/includes/UniFiController.php'; require_once __DIR__ . '/includes/Mailer.php'; require_once __DIR__ . '/includes/Notifier.php'; require_once __DIR__ . '/includes/Captcha.php'; +require_once __DIR__ . '/includes/Sms.php'; require_once __DIR__ . '/includes/I18n.php'; $auth = new Auth(); @@ -185,11 +186,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_voucher'])) { $voucherCreated = true; Notifier::voucherCreated(1, $site['name'], $_SESSION['user_name'] ?? null); + $success = 'Voucher erfolgreich erstellt!'; if ($sendEmail && !empty($recipientEmail)) { $mailer->sendVoucherEmail($recipientEmail, $voucherCode, $site['name'], $maxUses); - $success = 'Voucher erstellt. E-Mail versendet.'; - } else { - $success = 'Voucher erfolgreich erstellt!'; + $success .= ' E-Mail versendet.'; + } + // Optional: Code per SMS (Twilio) + $recipientPhone = trim((string)($_POST['recipient_phone'] ?? '')); + if (isset($_POST['send_sms']) && $recipientPhone !== '' && Sms::enabled($db)) { + $smsText = ($appTitle ? $appTitle . ': ' : '') . 'WLAN-Code ' . $voucherCode; + $success .= Sms::send($db, $recipientPhone, $smsText) ? ' SMS versendet.' : ' (SMS fehlgeschlagen)'; } } catch (Exception $e) { $error = 'Fehler: ' . $e->getMessage(); @@ -251,6 +257,7 @@ $currentUser = $auth->isLoggedIn() ? $auth->getCurrentUser() : null; $captchaMode = !$auth->isLoggedIn() ? Captcha::mode($db) : 'off'; $captchaQuestion = $captchaMode === 'math' ? Captcha::newMathChallenge() : ''; $hcaptchaSiteKey = $captchaMode === 'hcaptcha' ? $db->getSetting('captcha_site_key', '') : ''; +$smsEnabled = Sms::enabled($db); $captchaHtml = ''; if ($captchaMode === 'math') { $captchaHtml = '

' @@ -576,6 +583,19 @@ function buildPrintCard($template, $data, $instructionHeader, $instructionText,
+ + + +