1 Commits
v1.4.7 ... main

Author SHA1 Message Date
126b063e78 feat: Math-CAPTCHA (serverseitig, kein externer Dienst) – v1.5.0
- kgv_cf_generate_captcha(): Rechenaufgabe (+/-/×) mit WordPress-Transient
- kgv_cf_verify_captcha(): serverseitige Prüfung + einmaliger Token-Verbrauch
- Formular: CAPTCHA-Feld mit verstecktem Token
- Submit-Handler: Abweisung bei falscher/abgelaufener Antwort
- CSS: CAPTCHA-Feld gestylt
- Version 1.4.7 → 1.5.0
2026-04-21 22:12:20 +02:00
4 changed files with 70 additions and 3 deletions

0
.gitignore vendored Normal file → Executable file
View File

View File

@@ -43,4 +43,6 @@ display: inline-flex;
.kgv-cf-alert-success{border:1px solid #c6e1c6;background:#ecf7ed} .kgv-cf-alert-success{border:1px solid #c6e1c6;background:#ecf7ed}
.kgv-cf-alert-error{border:1px solid #e5b3b3;background:#fff2f2} .kgv-cf-alert-error{border:1px solid #e5b3b3;background:#fff2f2}
.kgv-cf-hp{position:absolute !important;left:-9999px !important;opacity:0 !important;pointer-events:none !important} .kgv-cf-hp{position:absolute !important;left:-9999px !important;opacity:0 !important;pointer-events:none !important}
.kgv-cf-captcha label{font-weight:600;margin-bottom:8px;display:block}
.kgv-cf-captcha input[type="text"]{max-width:120px}
@media (max-width:700px){.kgv-cf-grid{grid-template-columns:1fr}.kgv-contact-form{padding:18px;border-radius:14px}} @media (max-width:700px){.kgv-cf-grid{grid-template-columns:1fr}.kgv-contact-form{padding:18px;border-radius:14px}}

View File

@@ -2,7 +2,7 @@
/** /**
* Plugin Name: KGV Kontakt Form * Plugin Name: KGV Kontakt Form
* Description: Kontaktformular mit Nachrichtenbereich, Kategorien, Routing je Kategorie, Datenschutz-Checkbox, gelesen/ungelesen, Mehrfach-E-Mail und Rollenfreigabe für Kontaktanfragen. * Description: Kontaktformular mit Nachrichtenbereich, Kategorien, Routing je Kategorie, Datenschutz-Checkbox, gelesen/ungelesen, Mehrfach-E-Mail und Rollenfreigabe für Kontaktanfragen.
* Version: 1.4.7 * Version: 1.5.0
* Author: Ronny Grobel * Author: Ronny Grobel
* Author URI: https://apex-project.de/ * Author URI: https://apex-project.de/
* Plugin URI: https://wordpress.apex-project.de/ * Plugin URI: https://wordpress.apex-project.de/
@@ -13,7 +13,7 @@
if (!defined('ABSPATH')) exit; if (!defined('ABSPATH')) exit;
define('KGV_CF_VERSION', '1.4.7'); define('KGV_CF_VERSION', '1.5.0');
define('KGV_CF_VIEW_CAP', 'kgv_view_contact_requests'); define('KGV_CF_VIEW_CAP', 'kgv_view_contact_requests');
define('KGV_CF_MANAGE_CAP', 'manage_options'); define('KGV_CF_MANAGE_CAP', 'manage_options');
@@ -110,6 +110,55 @@ function kgv_cf_run_schema_update() {
} }
} }
// --- CAPTCHA (serverseitig, kein externer Dienst) ---
function kgv_cf_generate_captcha() {
$a = wp_rand(1, 12);
$b = wp_rand(1, 12);
$ops = ['+', '-', '×'];
$op = $ops[array_rand($ops)];
switch ($op) {
case '-':
if ($b > $a) { [$a, $b] = [$b, $a]; }
$answer = $a - $b;
break;
case '×':
$a = wp_rand(1, 9);
$b = wp_rand(1, 9);
$answer = $a * $b;
break;
default:
$answer = $a + $b;
}
$token = bin2hex(random_bytes(16));
set_transient('kgv_cf_cap_' . $token, (string) $answer, HOUR_IN_SECONDS);
return [
'token' => $token,
'question' => sprintf('Sicherheitsfrage: Wie viel ist %d %s %d?', $a, $op, $b),
];
}
function kgv_cf_verify_captcha($token, $given) {
if (empty($token) || !ctype_xdigit($token) || strlen($token) !== 32) {
return false;
}
$key = 'kgv_cf_cap_' . sanitize_text_field($token);
$stored = get_transient($key);
delete_transient($key);
if ($stored === false) {
return false;
}
return trim((string) $given) === $stored;
}
// --- Ende CAPTCHA ---
function kgv_cf_enqueue_assets() { function kgv_cf_enqueue_assets() {
wp_enqueue_style( wp_enqueue_style(
'kgv-contact-form-style', 'kgv-contact-form-style',
@@ -336,6 +385,15 @@ function kgv_cf_render_form() {
<input type="text" name="kgv_hp" value="" autocomplete="off" tabindex="-1" class="kgv-cf-hp"> <input type="text" name="kgv_hp" value="" autocomplete="off" tabindex="-1" class="kgv-cf-hp">
<?php
$captcha = kgv_cf_generate_captcha();
?>
<p class="kgv-cf-field kgv-cf-captcha">
<label for="kgv_captcha_answer"><?php echo esc_html($captcha['question']); ?> *</label>
<input type="text" id="kgv_captcha_answer" name="kgv_captcha_answer" inputmode="numeric" pattern="-?[0-9]+" autocomplete="off" required>
<input type="hidden" name="kgv_captcha_token" value="<?php echo esc_attr($captcha['token']); ?>">
</p>
<?php wp_nonce_field('kgv_contact_form_submit', 'kgv_nonce'); ?> <?php wp_nonce_field('kgv_contact_form_submit', 'kgv_nonce'); ?>
<p class="kgv-cf-submit"> <p class="kgv-cf-submit">
@@ -360,6 +418,13 @@ function kgv_cf_handle_form_submit() {
return; return;
} }
$captcha_token = isset($_POST['kgv_captcha_token']) ? sanitize_text_field(wp_unslash($_POST['kgv_captcha_token'])) : '';
$captcha_answer = isset($_POST['kgv_captcha_answer']) ? sanitize_text_field(wp_unslash($_POST['kgv_captcha_answer'])) : '';
if (!kgv_cf_verify_captcha($captcha_token, $captcha_answer)) {
kgv_cf_redirect_with_flag('kgv_error', '1');
}
$name = sanitize_text_field($_POST['kgv_name'] ?? ''); $name = sanitize_text_field($_POST['kgv_name'] ?? '');
$email = sanitize_email($_POST['kgv_email'] ?? ''); $email = sanitize_email($_POST['kgv_email'] ?? '');
$category_id = absint($_POST['kgv_category'] ?? 0); $category_id = absint($_POST['kgv_category'] ?? 0);

View File

@@ -3,7 +3,7 @@ Contributors: ronnygrobel
Tags: contact form, kontaktformular, vereinswebseite, kategorien, datenschutz Tags: contact form, kontaktformular, vereinswebseite, kategorien, datenschutz
Requires at least: 6.0 Requires at least: 6.0
Tested up to: 6.8 Tested up to: 6.8
Stable tag: 1.4.7 Stable tag: 1.5.0
Requires PHP: 7.2 Requires PHP: 7.2
License: GPLv2 or later License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html License URI: https://www.gnu.org/licenses/gpl-2.0.html