SMS-Versand (Twilio): includes/Sms.php + Option im Voucher-Formular + Settings

This commit is contained in:
Claude 2026-06-06 05:44:46 +00:00
parent 46c03d53b8
commit 976b357952
No known key found for this signature in database
3 changed files with 84 additions and 3 deletions

View file

@ -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
</div>
</div>
<div class="card">
<h2>SMS-Versand (Twilio)</h2>
<p class="muted">Voucher-Codes optional per SMS versenden. Erfordert ein Twilio-Konto.</p>
<label class="chk"><input type="checkbox" name="sms_enabled" <?= $smsEnabled ? 'checked' : '' ?>> SMS-Versand aktiv</label>
<div class="row3" style="margin-top:10px;">
<div><label>Account SID</label><input class="input" type="text" name="twilio_sid" value="<?= htmlspecialchars($twilioSid) ?>"></div>
<div><label>Auth Token<?= $twilioTokenSet ? ' (gesetzt)' : '' ?></label><input class="input" type="password" name="twilio_token" placeholder="<?= $twilioTokenSet ? '••••••• (leer = unverändert)' : '' ?>"></div>
<div><label>Absender (From)</label><input class="input" type="text" name="twilio_from" value="<?= htmlspecialchars($twilioFrom) ?>" placeholder="+49…"></div>
</div>
</div>
<div class="card">
<h2>Datenhaltung & Cleanup (DSGVO)</h2>
<p class="muted">Aufbewahrungsfristen in Tagen (0 = deaktiviert). Ausführung per <code>cron_cleanup.php</code> (täglich empfohlen).

42
includes/Sms.php Normal file
View file

@ -0,0 +1,42 @@
<?php
/**
* Sms Versand von Voucher-Codes per SMS über Twilio.
*
* Settings: sms_enabled (0/1), twilio_sid, twilio_token, twilio_from
* Reine PHP-Standardlib + cURL. Fehler werden geloggt, nie geworfen.
*/
class Sms {
public static function enabled($db) {
return (string)$db->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;
}
}

View file

@ -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 = '<div class="form-group"><label>Sicherheitsfrage: Wie viel ist ' . htmlspecialchars($captchaQuestion) . '?</label>'
@ -576,6 +583,19 @@ function buildPrintCard($template, $data, $instructionHeader, $instructionText,
</div>
<?php endif; ?>
<?php if ($smsEnabled): ?>
<div class="email-option">
<div class="email-checkbox-wrapper">
<input type="checkbox" id="send_sms" name="send_sms" onchange="document.getElementById('sms_field').style.display=this.checked?'block':'none'">
<label for="send_sms">📱 Code per SMS versenden</label>
</div>
<div id="sms_field" style="display:none;margin-top:12px;">
<label for="recipient_phone">Telefonnummer (international, z.B. +49170)</label>
<input type="tel" id="recipient_phone" name="recipient_phone" placeholder="+49170123456">
</div>
</div>
<?php endif; ?>
<button type="submit" class="btn" id="submitBtn">
<?= __('voucher_create_btn') ?>
</button>