How to add SliderCaptcha to "form_with_ajax.php"

Asynchronous Form Submission (with Ajax)

Asynchronous request: The Ajax post runs in the background. The current page remains unchanged and the user can continue to interact while the data is being transferred.

OldNew
1<?php1<?php
2/**2/**
3 * =========================3 * =========================
4 * BACKEND (AJAX REQUEST)4 * BACKEND (AJAX REQUEST)
5 * =========================5 * =========================
6 */6 */
7if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax'])) {7if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax'])) {
8 8
9 header('Content-Type: application/json; charset=UTF-8');9 header('Content-Type: application/json; charset=UTF-8');
10 10
11 function respond(bool $success, string $message = '', array $errors = []): void11 function respond(bool $success, string $message = '', array $errors = []): void
12 {12 {
13 echo json_encode([13 echo json_encode([
14 'success' => $success,14 'success' => $success,
15 'message' => $message,15 'message' => $message,
16 'errors' => $errors16 'errors' => $errors
17 ], JSON_UNESCAPED_UNICODE);17 ], JSON_UNESCAPED_UNICODE);
18 exit;18 exit;
19 }19 }
20 20
21 $email = trim($_POST['email'] ?? '');21 $email = trim($_POST['email'] ?? '');
22 $errors = [];22 $errors = [];
23 23
24 // Validate Email24 // Step 1: Validate Email
25 if ($email === '') {25 if ($email === '') {
26 $errors['email'] = 'Required field';26 $errors['email'] = 'Required field';
27 } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {27 } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
28 $errors['email'] = 'Please enter a valid email address';28 $errors['email'] = 'Please enter a valid email address';
29 }29 }
30 30
31 if (!empty($errors)) {31 if (!empty($errors)) {
32 respond(false, 'Please correct the highlighted fields.', $errors);32 respond(false, 'Please correct the highlighted fields.', $errors);
33 }33 }
34 34
35 // Process form35 // Step 2: Check if CAPTCHA-Token exists
36 if (empty($_POST['slidercaptcha_token'])) {
37 // CAPTCHA required
38 respond(true, 'captcha_required');
39 }
40
41 // Step 3: Verify CAPTCHA Token
42 $captchaToken = (string)($_POST['slidercaptcha_token'] ?? '');
43 $captchaServiceAvailable = true;
44
45 if ($captchaToken === 'CAPTCHA_UNAVAILABLE') {
46 // Special Token: Check if service is really down
47 $ch = curl_init('https://slidercaptcha.net/api/v1/verify.php');
48 curl_setopt_array($ch, [
49 CURLOPT_POST => true,
50 CURLOPT_RETURNTRANSFER => true,
51 CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
52 CURLOPT_POSTFIELDS => json_encode(['token' => 'test', 'secret_key' => 'test']),
53 CURLOPT_TIMEOUT => 3,
54 CURLOPT_CONNECTTIMEOUT => 3
55 ]);
56
57 $testResponse = curl_exec($ch);
58 $testHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
59 curl_close($ch);
60
61 if ($testResponse === false || $testHttpCode === 0) {
62 // Service is down → Allow Bypass
63 error_log('SliderCaptcha service unavailable - allowing bypass for email: ' . $email);
64 $captchaVerified = true;
65 $captchaServiceAvailable = false;
66 } else {
67 // Service is available → Bot attack!
68 error_log('SECURITY WARNING: Attempted CAPTCHA bypass for email: ' . $email);
69 respond(false, 'Invalid CAPTCHA token. Please try again.');
70 }
71
72 } else {
73 // Normal Token → Verify
74 $verifyPayload = json_encode([
75 'token' => $captchaToken,
76 'secret_key' => 'sk_live_26918...provided by DSLM IT-CONSULTING'
77 ]);
78
79 $ch = curl_init('https://slidercaptcha.net/api/v1/verify.php');
80 curl_setopt_array($ch, [
81 CURLOPT_POST => true,
82 CURLOPT_RETURNTRANSFER => true,
83 CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
84 CURLOPT_POSTFIELDS => $verifyPayload,
85 CURLOPT_TIMEOUT => 5,
86 CURLOPT_CONNECTTIMEOUT => 5
87 ]);
88
89 $verifyResponse = curl_exec($ch);
90 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
91 curl_close($ch);
92
93 if ($verifyResponse === false || $httpCode === 0) {
94 // Service down → Allow
95 error_log('SliderCaptcha service unavailable during verification - allowing bypass for email: ' . $email);
96 $captchaVerified = true;
97 $captchaServiceAvailable = false;
98 } elseif ($httpCode !== 200) {
99 respond(false, 'SliderCaptcha verification failed. Please try again.');
100 } else {
101 $data = json_decode($verifyResponse, true);
102 if (!is_array($data) || empty($data['success'])) {
103 respond(false, 'SliderCaptcha verification failed. Please try again.');
104 } elseif (isset($data['score']) && $data['score'] < 0.5) {
105 respond(false, 'SliderCaptcha verification failed. Please try again.');
106 } else {
107 $captchaVerified = true;
108 }
109 }
110 }
111
112 // Step 4: Process form if CAPTCHA verified
113 if ($captchaVerified) {
36 /*114 /*
37 *** put your code here to check Email against database ***115 *** put your code here to check Email against database ***
38 */116 */
39 117
40 // Check if email already exists118 // Check if email already exists
41 if ($email == "joe.doe@example.com") {119 if ($email == "joe.doe@example.com") {
42 //respond(false, 'This email-address already exists in our database', ['email' => 'This email-address already exists in our database']);120 //respond(false, 'This email-address already exists in our database', ['email' => 'This email-address already exists in our database']);
43 respond(false, '', ['email' => 'This email-address already exists in our database']);121 respond(false, '', ['email' => 'This email-address already exists in our database']);
44 }122 }
45 123
46 // Success124 // Success
47 /*125 /*
48 *** put your code here to store the email-address in your database ***126 *** put your code here to store the email-address in your database ***
49 */127 */
50 $successMessage = 'Thank you for your subscription!';128 $successMessage = 'Thank you for your subscription!';
129 if (!$captchaServiceAvailable) {
130 $successMessage .= ' (Note: CAPTCHA service was unavailable)';
131 }
51 respond(true, $successMessage);132 respond(true, $successMessage);
133 }
134
135 respond(false, 'An unexpected error occurred.');
52}136}
53?>137?>
54<!DOCTYPE html>138<!DOCTYPE html>
55<html lang="en">139<html lang="en">
56<head>140<head>
57 <meta charset="utf-8">141 <meta charset="utf-8">
58 <meta name="viewport" content="width=device-width, initial-scale=1">142 <meta name="viewport" content="width=device-width, initial-scale=1">
59 <title>Form with Ajax</title>143 <title>Form with Ajax plus SliderCaptcha - Secure Fallback</title>
60 <style>144 <style>
61 body { 145 body {
62 font-family: sans-serif; 146 font-family: sans-serif;
63 font-size: 14px;147 font-size: 14px;
64 }148 }
65 .error { 149 .error {
66 color: red; 150 color: red;
67 font-size: 12px; 151 font-size: 12px;
68 margin-top: 5px;152 margin-top: 5px;
69 }153 }
70 .success { 154 .success {
71 color: green; 155 color: green;
72 padding: 10px; 156 padding: 10px;
73 margin: 10px 0; 157 margin: 10px 0;
74 border: 1px solid green; 158 border: 1px solid green;
75 background: #e8f5e9;159 background: #e8f5e9;
76 }160 }
77 .loading {161 .loading {
78 opacity: 0.6;162 opacity: 0.6;
79 pointer-events: none;163 pointer-events: none;
80 }164 }
81 button:disabled {165 button:disabled {
82 opacity: 0.5;166 opacity: 0.5;
83 cursor: not-allowed;167 cursor: not-allowed;
84 }168 }
85 </style>169 </style>
86 <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>170 <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
87</head>171</head>
88172
89<body>173<body>
90<h1>Form with Ajax and no SliderCaptcha</h1>174<h1>SliderCaptcha Example with Secure Fallback</h1>
91<h2>Asynchronous Form Submission (with Ajax)</h2>175<h2>Asynchronous Form Submission (with Ajax)</h2>
92<h3>Asynchronous request: The Ajax post runs in the background. The current page remains unchanged and the user can continue to interact while the data is being transferred.</h3>176<h3>Asynchronous request: The Ajax post runs in the background. The current page remains unchanged and the user can continue to interact while the data is being transferred.</h3>
93<h4>Hints:</h4>177<h4>Hints:</h4>
94<ul>178<ul>
95<li>Leave the email field empty to see backend validation</li>179<li>Leave the email field empty to see backend validation</li>
96<li>Enter invalid email to see backend validation</li>180<li>Enter invalid email to see backend validation</li>
97<li>Try <b>joe.doe@example.com</b> to see backend validation error</li>181<li>Try <b>joe.doe@example.com</b> to see backend validation error <b>after</b> passing SliderCaptcha</li>
98<li>Try any other valid email-address to see final form submission</li>182<li>Try any other valid email-address to see final form submission <b>after</b> passing SliderCaptcha</li>
183<li><b>SECURITY:</b> If SliderCaptcha service is unavailable, you can continue BUT server verifies the service is really down!</li>
99</ul>184</ul>
100185
101<div id="successMessage" class="success" style="display: none;"></div>186<div id="successMessage" class="success" style="display: none;"></div>
102<div id="errorMessage" class="error" style="display: none;"></div>187<div id="errorMessage" class="error" style="display: none;"></div>
103188
104<form id="subscriptionForm" novalidate>189<form id="subscriptionForm" novalidate>
105 <!-- Email -->190 <!-- Email -->
106 Email:<br>191 Email:<br>
107 <input type="email" name="email" id="email" autocomplete="email">192 <input type="email" name="email" id="email" autocomplete="email">
108 <div id="email-error" class="error" style="display: none;"></div>193 <div id="email-error" class="error" style="display: none;"></div>
109 <br><br>194 <br><br>
110195
111 <button type="submit" id="submitBtn">Subscribe</button>196 <button type="submit" id="submitBtn">Subscribe</button>
112 <span id="loadingIndicator" style="display: none; margin-left: 10px;">Processing...</span>197 <span id="loadingIndicator" style="display: none; margin-left: 10px;">Processing...</span>
113</form>198</form>
114199
115<script>200<script>
116$(function() {201$(function() {
117 202
118 let isSubmitting = false;203 let isSubmitting = false;
119 204
120 // Clear errors on input205 // Clear errors on input
121 $('#email').on('input', function() {206 $('#email').on('input', function() {
122 $('#email-error').hide();207 $('#email-error').hide();
123 $('#errorMessage').hide();208 $('#errorMessage').hide();
124 });209 });
125 210
126 // Form submit handler211 // Form submit handler
127 $('#subscriptionForm').on('submit', function(e) {212 $('#subscriptionForm').on('submit', function(e) {
128 e.preventDefault();213 e.preventDefault();
129 214
130 if (isSubmitting) return;215 if (isSubmitting) return;
131 216
132 // Clear previous messages217 // Clear previous messages
133 $('#successMessage').hide();218 $('#successMessage').hide();
134 $('#errorMessage').hide();219 $('#errorMessage').hide();
135 $('#email-error').hide();220 $('#email-error').hide();
136 221
137 // Show loading222 // Show loading
138 isSubmitting = true;223 isSubmitting = true;
139 $('#submitBtn').prop('disabled', true);224 $('#submitBtn').prop('disabled', true);
140 $('#loadingIndicator').show();225 $('#loadingIndicator').show();
141 $('#subscriptionForm').addClass('loading');226 $('#subscriptionForm').addClass('loading');
142 227
143 // First AJAX request: Validation228 // First AJAX request: Validation
144 $.ajax({229 $.ajax({
145 url: '',230 url: '',
146 method: 'POST',231 method: 'POST',
147 data: $(this).serialize() + '&ajax=1',232 data: $(this).serialize() + '&ajax=1',
148 dataType: 'json',233 dataType: 'json',
149 success: function(response) {234 success: function(response) {
235
236 // CAPTCHA required
237 if (response.success && response.message === 'captcha_required') {
238
239 // Check if SliderCaptcha is available
240 if (typeof SliderCaptcha === 'undefined') {
241 // Service unavailable - send special token
242 console.warn('SliderCaptcha not loaded - sending CAPTCHA_UNAVAILABLE token');
243 submitWithToken('CAPTCHA_UNAVAILABLE');
244 } else {
245 // Show CAPTCHA
246 SliderCaptcha.execute()
247 .then(function(captchaResponse) {
248 // CAPTCHA solved - submit with token
249 submitWithToken(captchaResponse.token);
250 })
251 .catch(function(error) {
252 // CAPTCHA cancelled
253 console.error('SliderCaptcha error:', error);
254 resetForm();
255 $('#errorMessage').text('CAPTCHA was cancelled. Please try again.').show();
256 });
257 }
258 return;
259 }
260
150 // Success261 // Success
151 if (response.success) {262 if (response.success) {
152 resetForm();263 resetForm();
153 $('#successMessage').text(response.message).show();264 $('#successMessage').text(response.message).show();
154 $('#subscriptionForm')[0].reset();265 $('#subscriptionForm')[0].reset();
155 return;266 return;
156 }267 }
157 268
158 // Errors269 // Errors
159 handleErrors(response);270 handleErrors(response);
160 },271 },
161 error: function() {272 error: function() {
162 resetForm();273 resetForm();
163 $('#errorMessage').text('An unexpected error occurred. Please try again.').show();274 $('#errorMessage').text('An unexpected error occurred. Please try again.').show();
164 }275 }
165 });276 });
166 });277 });
278
279 // Submit with CAPTCHA token
280 function submitWithToken(token) {
281 const formData = $('#subscriptionForm').serialize() + '&ajax=1&slidercaptcha_token=' + encodeURIComponent(token);
282
283 $.ajax({
284 url: '',
285 method: 'POST',
286 data: formData,
287 dataType: 'json',
288 success: function(response) {
289 if (response.success) {
290 resetForm();
291 $('#successMessage').text(response.message).show();
292 $('#subscriptionForm')[0].reset();
293 } else {
294 handleErrors(response);
295 }
296 },
297 error: function() {
298 resetForm();
299 $('#errorMessage').text('An unexpected error occurred. Please try again.').show();
300 }
301 });
302 }
167 303
168 // Handle error responses304 // Handle error responses
169 function handleErrors(response) {305 function handleErrors(response) {
170 resetForm();306 resetForm();
171 307
172 // Field-specific errors308 // Field-specific errors
173 if (response.errors) {309 if (response.errors) {
174 $.each(response.errors, function(field, message) {310 $.each(response.errors, function(field, message) {
175 $('#' + field + '-error').text(message).show();311 $('#' + field + '-error').text(message).show();
176 });312 });
177 }313 }
178 314
179 // General error message315 // General error message
180 if (response.message && response.message !== 'Please correct the highlighted fields.') {316 if (response.message && response.message !== 'Please correct the highlighted fields.') {
181 $('#errorMessage').text(response.message).show();317 $('#errorMessage').text(response.message).show();
182 }318 }
183 }319 }
184 320
185 // Reset form state321 // Reset form state
186 function resetForm() {322 function resetForm() {
187 isSubmitting = false;323 isSubmitting = false;
188 $('#submitBtn').prop('disabled', false);324 $('#submitBtn').prop('disabled', false);
189 $('#loadingIndicator').hide();325 $('#loadingIndicator').hide();
190 $('#subscriptionForm').removeClass('loading');326 $('#subscriptionForm').removeClass('loading');
191 }327 }
192 328
193});329});
194</script>330</script>
195331
332<!-- SliderCaptcha Embed Script -->
333<script src="https://slidercaptcha.net/embed.js"
334 data-sitekey="pk_live_b4a35...provided by DSLM IT-CONSULTING"
335 data-mode="live"
336 data-language="en">
337</script>
338
196</body>339</body>
197</html>340</html>