PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.10.0
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.10.0
3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 All 138 releases
bit-form / includes / Frontend / Form / FrontendFormManager.php

FrontendFormManager.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 2.10.0, at includes/Frontend/Form/FrontendFormManager.php

908 lines 35.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Get set Form,fields
5 */
6
7 namespace BitCode\BitForm\Frontend\Form;
8
9 /**
10 * FrontendFormManager class
11 */
12
13 use BitCode\BitForm\Admin\Form\Helpers;
14 use BitCode\BitForm\Core\Database\FormEntryModel;
15 use BitCode\BitForm\Core\Form\FormManager;
16 use BitCode\BitForm\Core\Form\Validator\FormFieldValidator;
17 use BitCode\BitForm\Core\Integration\IntegrationHandler;
18 use BitCode\BitForm\Core\Messages\SuccessMessageHandler;
19 use BitCode\BitForm\Core\Util\ApiResponse as UtilApiResponse;
20 use BitCode\BitForm\Core\Util\DateTimeHelper;
21 use BitCode\BitForm\Core\Util\HttpHelper;
22 use BitCode\BitForm\Core\Util\IpTool;
23 use BitCode\BitForm\Core\WorkFlow\WorkFlow;
24 use BitCode\BitForm\Core\WorkFlow\WorkFlowHandler;
25 use BitCode\BitForm\Frontend\Form\View\FormViewer;
26 use BitCode\BitFormPro\Admin\FormSettings\FormAbandonment;
27 use WP_Error;
28
29 final class FrontendFormManager extends FormManager
30 {
31 private $_form_identifier;
32 private $_form_token;
33 private $_form_id;
34 private $_work_flows;
35 private $_conf_messages;
36
37 // private $_has_upload = false;
38 public function __construct($form_id, $shortCodeCounter = null)
39 {
40 parent::__construct($form_id);
41 $this->_form_identifier = 'bitforms_' . $form_id;
42 $this->_form_identifier .= !empty(get_post()->ID) ? '_' . get_post()->ID : '';
43 $this->_form_identifier .= !empty($shortCodeCounter) ? "_$shortCodeCounter" : '';
44 $this->_form_token = wp_create_nonce('bitforms_' . $form_id);
45 $this->_form_id = $form_id;
46 }
47
48 public function getFormIdentifier()
49 {
50 return $this->_form_identifier;
51 }
52
53 public function getFormID()
54 {
55 return $this->_form_id;
56 }
57
58 public function getFormToken()
59 {
60 return $this->_form_token;
61 }
62
63 public function isSubmitted()
64 {
65 // return isset($_POST[$this->_form_identifier]) ? true : false;
66 return (isset($_POST['bitforms_id']) && $_POST['bitforms_id'] === $this->_form_identifier) ? true : false;
67 }
68
69 public function getSubmittedFields($submitted_data)
70 {
71 unset($submitted_data[$this->_form_identifier]);
72 // unset($submitted_data['bit-form-submit-btn']);
73 return array_keys($submitted_data);
74 }
75
76 public function formView($fields = null, $hasFile = false, $errorMessages = null, $previousValue = null)
77 {
78 $formContents = $this->getFormContent();
79 $formAtomicClsMap = $this->getAtomicClsMap();
80 if (!empty($fields)) {
81 $formContents->fields = is_string($fields) ? json_decode($fields) : $fields;
82 } else {
83 $workFlowRunHelper = new WorkFlow($this->form_id);
84 $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
85 'create',
86 $formContents->fields
87 );
88 $formContents->fields = empty($workFlowreturnedOnLoad['fields']) ? $formContents->fields : $workFlowreturnedOnLoad['fields'];
89 }
90 $formViewer = new FormViewer($this, $formContents, $formAtomicClsMap, $errorMessages, $previousValue);
91 $isRestricted = $this->checkSubmissionRestriction(false);
92 $msg = !empty($isRestricted) ? $isRestricted[0] : '';
93 return $formViewer->getView($hasFile, $msg);
94 }
95
96 public function conversationalFormView($fields = null, $hasFile = false, $errorMessages = null, $previousValue = null)
97 {
98 $formContents = $this->getFormContent();
99 $formAtomicClsMap = $this->getAtomicClsMap();
100 if (!empty($fields)) {
101 $formContents->fields = is_string($fields) ? json_decode($fields) : $fields;
102 } else {
103 $workFlowRunHelper = new WorkFlow($this->form_id);
104 $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
105 'create',
106 $formContents->fields
107 );
108 $formContents->fields = empty($workFlowreturnedOnLoad['fields']) ? $formContents->fields : $workFlowreturnedOnLoad['fields'];
109 }
110 $formViewer = new FormViewer($this, $formContents, $formAtomicClsMap, $errorMessages, $previousValue);
111 $isRestricted = $this->checkSubmissionRestriction(false);
112 $msg = !empty($isRestricted) ? $isRestricted[0] : '';
113 return $formViewer->getConversationalView($hasFile, $msg);
114 }
115
116 private function checkEmptySubmission($data, $file)
117 {
118 $formFields = $this->getFields();
119 foreach ($formFields as $key => $field) {
120 $fieldType = $field['type'];
121 $fileUploadFieldTypes = ['file-up', 'advanced-file-up'];
122 if ('decision-box' === $fieldType) {
123 continue;
124 }
125 $isFileType = in_array($fieldType, $fileUploadFieldTypes);
126 if ($this->isRepeatedField($key)) {
127 $fileData = !empty($file[$key]) ? $file[$key] : [];
128 $dataVal = !empty($data[$key]) ? $data[$key] : [];
129 if (!$this->checkRepeatedFieldEmptySubmission($isFileType, $dataVal, $fileData)) {
130 return false;
131 }
132 continue;
133 }
134 if (!$isFileType && (!empty($data[$key]) || (isset($data[$key]) && is_numeric($data[$key])))) {
135 return false;
136 }
137 if ($isFileType && !empty($file[$key]['name']) && is_string($file[$key]['name'])) {
138 return false;
139 }
140 if ($isFileType && !empty($file[$key]['name'][0])) {
141 return false;
142 }
143 }
144 return true;
145 }
146
147 private function checkRepeatedFieldEmptySubmission($isFileType, $data, $file = [])
148 {
149 if (!$isFileType) {
150 foreach ($data as $value) {
151 if (!empty($value)) {
152 return false;
153 }
154 }
155 }
156 if ($isFileType) {
157 foreach ($file['name'] as $value) {
158 if (!empty($value) && is_string($value)) {
159 return false;
160 }
161 if (is_array($value) && !empty($value[0])) {
162 return false;
163 }
164 }
165 }
166 return true;
167 }
168
169 private function getParams()
170 {
171 $url = wp_parse_url(wp_get_referer());
172 $parameter = [];
173 if (isset($url['query'])) {
174 $queries = explode('&', $url['query']);
175 foreach ($queries as $query) {
176 list($field, $value) = explode('=', $query);
177 $parameter[$field] = $value;
178 }
179 }
180 return $parameter;
181 }
182
183 public function handleSubmission()
184 {
185 $this->fieldNameReplaceOfPost();
186
187 $validated = $this->beforeSubmittedValidate();
188
189 if (true === $validated) {
190 unset($_POST['hidden_fields']);
191
192 $redirectPage = '';
193 $regSuccMsg = '';
194
195 $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
196 if (!is_wp_error($existAuth) && count($existAuth) > 0) {
197 $parameter = $this->getParams();
198 $existAuthFilter = has_filter('bf_wp_user_auth');
199
200 if (true === $existAuthFilter) {
201 $result = apply_filters('bf_wp_user_auth', $existAuth[0], $_POST, $parameter);
202
203 if (isset($result['auth_type']) && 'register' === $result['auth_type']) {
204 if (!$result['success']) {
205 return new WP_Error('errors', __($result['message'], 'bit-form'));
206 } elseif (isset($result['success'])) {
207 $redirectPage = $result['redirect_url'];
208 $regSuccMsg = $result['message'];
209 $newNonce = wp_create_nonce('bitforms_' . $this->_form_id);
210 }
211 } else {
212 if (!$result['success']) {
213 return new WP_Error('errors', __($result['message'], 'bit-form'));
214 } else {
215 return $result;
216 }
217 }
218 }
219 }
220
221 $saveResponse = $this->saveFormEntry($_POST);
222 if (is_wp_error($saveResponse)) {
223 return $saveResponse;
224 }
225
226 $entryID = $saveResponse['entry_id'];
227 do_action('bitform_submit_success', $this->_form_id, $entryID, $_POST);
228
229 // check and replace signature field value
230 $formFields = $this->getFields();
231 $uploadPath = BITFORMS_UPLOAD_BASE_URL . "/uploads/{$this->_form_id}/{$entryID}";
232
233 foreach ($formFields as $key => $field) {
234 if ('signature' === $field['type']) {
235 $saveResponse['fields'][$key] = $uploadPath . '/' . $saveResponse['fields'][$key];
236 break;
237 }
238 }
239
240 $captchaV3Settings = $this->getCaptchaV3Settings();
241 if ($captchaV3Settings) {
242 $token = $_POST['g-recaptcha-response'];
243 $integrationHandler = new IntegrationHandler(0);
244 $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
245 if (!is_wp_error($allFormIntegrations)) {
246 foreach ($allFormIntegrations as $integration) {
247 if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
248 $integrationDetails = json_decode($integration->integration_details);
249 $integrationDetails->id = $integration->id;
250 $reCAPTCHA = $integrationDetails;
251 }
252 }
253 }
254 if (!empty($reCAPTCHA->secretKey)) {
255 $gRecaptchaResponse = HttpHelper::post(
256 'https://www.google.com/recaptcha/api/siteverify',
257 ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
258 );
259 if ($captchaV3Settings && !empty($saveResponse['triggerData'])) {
260 $logID = $saveResponse['triggerData']['logID'];
261 $integId = $reCAPTCHA->id;
262 $saveApiResponse = new UtilApiResponse();
263 $saveApiResponse->apiResponse($logID, $integId, ['type_name' => 'ReCaptcha', 'type' => 'v3'], 'success', $gRecaptchaResponse);
264 }
265 }
266 unset($_POST['g-recaptcha-response']);
267 }
268 if (!empty($redirectPage) && empty($saveResponse['redirectPage']) || null === $saveResponse['redirectPage']) {
269 $saveResponse['redirectPage'] = $redirectPage;
270 }
271 if (!empty($regSuccMsg) && isset($saveResponse['dflt_message'])) {
272 $saveResponse['message'] = $regSuccMsg;
273 }
274 $saveResponse = IntegrationHandler::maybeSetCronForIntegration($saveResponse, 'create');
275 $entryId = $saveResponse['entry_id'];
276
277 $responseMsg = is_array($saveResponse) && !empty($saveResponse) ? $saveResponse : __('Form Submitted Successfully', 'bit-form');
278 if (isset($newNonce)) {
279 $responseMsg['new_nonce'] = $newNonce;
280 }
281 $_POST = [];
282 $responseMsg['entry_id'] = $entryId;
283 return $responseMsg;
284 }
285 do_action('bitform_validation_error', $this->_form_id, $validated);
286 return $validated;
287 }
288
289 public function handleUpdateEntry()
290 {
291 $this->fieldNameReplaceOfPost();
292 $validated = $this->beforeSubmittedValidate();
293
294 $entryID = $_REQUEST['entryID'];
295 if (is_null($entryID)) {
296 return new WP_Error('empty_form', __('Entries id is invalid', 'bit-form'));
297 }
298 if (true === $validated) {
299 unset($_POST['hidden_fields'], $_POST['entryID']);
300
301 $redirectPage = '';
302 $regSuccMsg = '';
303
304 $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
305 if (!is_wp_error($existAuth) && count($existAuth) > 0) {
306 $parameter = $this->getParams();
307 $existAuthFilter = has_filter('bf_wp_user_auth');
308
309 if (true === $existAuthFilter) {
310 $result = apply_filters('bf_wp_user_auth', $existAuth[0], $_POST, $parameter);
311
312 if (isset($result['auth_type']) && 'register' === $result['auth_type']) {
313 if (!$result['success']) {
314 return new WP_Error('errors', __($result['message'], 'bit-form'));
315 } elseif (isset($result['success'])) {
316 $redirectPage = $result['redirect_url'];
317 $regSuccMsg = $result['message'];
318 $newNonce = wp_create_nonce('bitforms_' . $this->_form_id);
319 }
320 } else {
321 if (!$result['success']) {
322 return new WP_Error('errors', __($result['message'], 'bit-form'));
323 } else {
324 return $result;
325 }
326 }
327 }
328 }
329
330 $updateResponse = $this->updateFormEntry($_POST, $this->getFormID(), $entryID);
331 if (is_wp_error($updateResponse)) {
332 return $updateResponse;
333 }
334
335 do_action('bitform_submit_success', $this->_form_id, $entryID, $_POST);
336
337 $captchaV3Settings = $this->getCaptchaV3Settings();
338 if ($captchaV3Settings) {
339 $token = $_POST['g-recaptcha-response'];
340 $integrationHandler = new IntegrationHandler(0);
341 $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
342 if (!is_wp_error($allFormIntegrations)) {
343 foreach ($allFormIntegrations as $integration) {
344 if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
345 $integrationDetails = json_decode($integration->integration_details);
346 $integrationDetails->id = $integration->id;
347 $reCAPTCHA = $integrationDetails;
348 }
349 }
350 }
351 if (!empty($reCAPTCHA->secretKey)) {
352 $gRecaptchaResponse = HttpHelper::post(
353 'https://www.google.com/recaptcha/api/siteverify',
354 ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
355 );
356 if ($captchaV3Settings && !empty($updateResponse['triggerData'])) {
357 $logID = $updateResponse['triggerData']['logID'];
358 $integId = $reCAPTCHA->id;
359 $saveApiResponse = new UtilApiResponse();
360 $saveApiResponse->apiResponse($logID, $integId, ['type_name' => 'ReCaptcha', 'type' => 'v3'], 'success', $gRecaptchaResponse);
361 }
362 }
363 unset($_POST['g-recaptcha-response']);
364 }
365 if (!empty($redirectPage) && empty($updateResponse['redirectPage']) || null === $updateResponse['redirectPage']) {
366 $updateResponse['redirectPage'] = $redirectPage;
367 }
368 if (!empty($regSuccMsg) && isset($updateResponse['dflt_message'])) {
369 $updateResponse['message'] = $regSuccMsg;
370 }
371 $updateResponse = IntegrationHandler::maybeSetCronForIntegration($updateResponse, 'create');
372 $entryId = $updateResponse['entry_id'];
373
374 $responseMsg = is_array($updateResponse) && !empty($updateResponse) ? $updateResponse : __('Entry Update Successfully', 'bit-form');
375 if (isset($newNonce)) {
376 $responseMsg['new_nonce'] = $newNonce;
377 }
378 $_POST = [];
379 $responseMsg['entry_id'] = $entryId;
380 return $responseMsg;
381 }
382 do_action('bitform_validation_error', $this->_form_id, $validated);
383 return $validated;
384 }
385
386 public function validateFormSubmission($submitted_data)
387 {
388 $hidden_fields = isset($submitted_data['hidden_fields']) ? $submitted_data['hidden_fields'] : '';
389 $submitted_fields = $this->getSubmittedFields($submitted_data);
390 $form_fields = $this->getFields();
391 $form_fields_names = array_keys($form_fields);
392 if ($this->isGCLIDEnabled()) {
393 array_push($form_fields_names, 'GCLID');
394 }
395 foreach ($submitted_fields as $field) {
396 if ('hidden_fields' !== $field && !in_array($field, $form_fields_names) || false !== strpos($hidden_fields, $field)) {
397 unset($submitted_data[$field]);
398 }
399 }
400 return $submitted_data;
401 }
402
403 public function beforeSubmittedValidate()
404 {
405 if ($this->verifySubmissionNonce()) {
406 if ($this->isExist()) {
407 $isRestricted = $this->checkSubmissionRestriction();
408 if ($isRestricted && !empty($isRestricted)) {
409 return new WP_Error('spam_detection', $isRestricted[0]);
410 }
411 if ($this->isTrappedInHoneypot()) {
412 return new WP_Error('spam_detection', __('Token verification failed', 'bit-form'));
413 }
414 $captchaSettings = $this->getCaptchaSettings();
415 $captchaV3Settings = $this->getCaptchaV3Settings();
416 if ($captchaSettings || $captchaV3Settings) {
417 $token = $_POST['g-recaptcha-response'];
418 if (!isset($_POST['g-recaptcha-response'])) {
419 return new WP_Error('spam_detection', __('Please verify reCAPTCHA', 'bit-form'));
420 }
421 $integrationHandler = new IntegrationHandler(0);
422 $allFormIntegrations = $integrationHandler->getAllIntegration('app', $captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3');
423 if (!is_wp_error($allFormIntegrations)) {
424 foreach ($allFormIntegrations as $integration) {
425 if (!is_null($integration->integration_type) && $integration->integration_type === ($captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3')) {
426 $integrationDetails = json_decode($integration->integration_details);
427 $integrationDetails->id = $integration->id;
428 $reCAPTCHA = $integrationDetails;
429 }
430 }
431 }
432 if (!empty($reCAPTCHA->secretKey)) {
433 $gRecaptchaResponse = HttpHelper::post(
434 'https://www.google.com/recaptcha/api/siteverify',
435 ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
436 );
437 $isgReCaptchaVerified = false;
438 if (!is_wp_error($gRecaptchaResponse)) {
439 if (
440 $captchaV3Settings
441 && !empty($gRecaptchaResponse->score)
442 && ((float) $gRecaptchaResponse->score < (float) $captchaV3Settings->score)
443 ) {
444 wp_send_json_error(
445 __(
446 $captchaV3Settings->message,
447 'bit-form'
448 )
449 );
450 }
451
452 $isgReCaptchaVerified = $gRecaptchaResponse->success;
453 }
454 if (!$isgReCaptchaVerified) {
455 return new WP_Error('spam_detection', __('Please verify reCAPTCHA', 'bit-form'));
456 }
457 }
458 }
459
460 /* Implement Turnstile Captcha start */
461 $turnstileSetting = $this->getTurnstileSettings();
462 if ($turnstileSetting) {
463 if (!isset($_POST['cf-turnstile-response'])) {
464 return new WP_Error('spam_detection', __('Please verify Cloudflare Turnstile Captcha', 'bit-form'));
465 }
466 $token = $_POST['cf-turnstile-response'];
467 $turnstileCaptcha = null;
468 $integrationHandler = new IntegrationHandler(0);
469 $turnstileIntegration = $integrationHandler->getAllIntegration('app', 'turnstileCaptcha')[0];
470 if (!is_wp_error($turnstileIntegration && !is_null($turnstileIntegration->integration_type))) {
471 $turnstileCaptcha = json_decode($turnstileIntegration->integration_details);
472 // $integrationDetails->id = $turnstileIntegration->id;
473 // $turnstileCaptcha = $integrationDetails;
474 }
475 if (!is_null($turnstileCaptcha)) {
476 $isTurnstileCaptchaVerified = false;
477 $turnstileRecaptchaResponse = HttpHelper::post(
478 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
479 ['secret' => $turnstileCaptcha->secretKey, 'response' => $token]
480 );
481 if (!is_wp_error($turnstileRecaptchaResponse)) {
482 if (!$turnstileRecaptchaResponse->success) {
483 wp_send_json_error(
484 __(
485 'Cloudflare Turnstile Validation Error: ' . implode(', ', $turnstileRecaptchaResponse->{'error-codes'}),
486 'bit-form'
487 )
488 );
489 }
490
491 $isTurnstileCaptchaVerified = $turnstileRecaptchaResponse->success;
492 }
493 if (!$isTurnstileCaptchaVerified) {
494 return new WP_Error('spam_detection', __('Please verify Cloudflare Turnstile Captcha', 'bit-form'));
495 }
496 }
497 }
498
499 /* Implement Turnstile Captcha end */
500 $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
501
502 // check if user is already logged in and form has auth integration
503 do_action('bitform_checked_exist_auth', $this->_form_id, $existAuth);
504 if (!is_wp_error($existAuth) && count($existAuth) > 0 && is_user_logged_in()) {
505 return new WP_Error('auth_error', __('You are already logged in', 'bit-form'));
506 }
507 $validateForm = $this->validateFormSubmission($_POST);
508 $validateFormFiles = $this->validateFormSubmission($_FILES);
509 $validateForm = array_merge($validateForm, $validateFormFiles);
510 $form_fields = $this->getFields();
511 // check if form-current-step is set and form is multi-step
512 $formCurrentStep = isset($_POST['form-current-step']) ? $_POST['form-current-step'] : null;
513 if (!is_null($formCurrentStep)) {
514 $formContents = $this->getFormContent();
515 $layout = $formContents->layout;
516 $stepIndex = (int) $formCurrentStep - 1;
517 $stepLayout = $layout[$stepIndex]->layout->lg;
518 $nestedLayout = $formContents->nestedLayout;
519 $step_fields = [];
520 foreach ($stepLayout as $lay) {
521 $fk = $lay->i;
522 if (isset($nestedLayout->{$fk})) {
523 $nestedLg = $nestedLayout->{$fk}->lg;
524 foreach ($nestedLg as $nestedLay) {
525 $nestedFk = $nestedLay->i;
526 $step_fields[$nestedFk] = $form_fields[$nestedFk];
527 }
528 }
529 $step_fields[$fk] = $form_fields[$fk];
530 }
531 $form_fields = $step_fields;
532 }
533 $formFieldValidator = new FormFieldValidator($form_fields, $_POST, $_FILES);
534 $validUniuqFields = [];
535 $existFilter = has_filter('bf_check_duplicate_entry');
536 if (true === $existFilter) {
537 $validUniuqFields = apply_filters('bf_check_duplicate_entry', $form_fields, $_POST);
538
539 $fieldKeys = array_keys($validUniuqFields);
540 $form_fields_keys = array_keys($form_fields);
541 $uniqueFields = [];
542 foreach ($fieldKeys as $key) {
543 if (in_array($key, $form_fields_keys)) {
544 $uniqueFields[] = $form_fields[$key];
545 }
546 }
547 do_action('bitform_Unique_entry', $uniqueFields, $validUniuqFields, $this->_form_id, $_POST);
548 }
549 $validateField = $formFieldValidator->validate('create', $this->_form_id);
550
551 if ($validateForm && $validateField && 0 === count($validUniuqFields)) {
552 return true;
553 } else {
554 $error = __('Please submit form with valid fields', 'bit-form');
555 if (!$validateForm) {
556 $errorMessages = $error;
557 } elseif (count($formFieldValidator->getMessage()) > 0) {
558 $errorMessages = $formFieldValidator->getMessage();
559 } else {
560 $errorMessages = 0 === count($validUniuqFields) ? $error : $validUniuqFields;
561 }
562 return new WP_Error('validation_error', $errorMessages);
563 }
564 }
565 return new WP_Error('unknown_form', __('Form does not exist', 'bit-form'));
566 } else {
567 return new WP_Error('token_expired', __('Token expired', 'bit-form'));
568 }
569 }
570
571 public function verifySubmissionNonce()
572 {
573 if (!isset($_POST['t_identity']) && !isset($_POST['csrf'])) {
574 return false;
575 }
576 $tIdenty = sanitize_text_field($_POST['t_identity']);
577 $csrf = sanitize_text_field($_POST['csrf']);
578 unset($_POST['t_identity'], $_POST['action'], $_POST['bitforms_id'], $_POST['csrf']);
579 return Helpers::csrfDecrypted($tIdenty, $csrf);
580 }
581
582 public function setViewCount()
583 {
584 if (!current_user_can('manage_options')) {
585 $update_status = $this->formModel->update(
586 [
587 'views' => intval(static::$form[0]->views) + 1
588 ],
589 [
590 'id' => $this->form_id
591 ]
592 );
593 }
594 }
595
596 public function checkSubmissionRestriction($checkedEmptySubmitted = true)
597 {
598 $formContents = $this->getFormContent();
599 $fromRestrictionSetitingsEnabled = empty($formContents->additional->enabled) ? [] : $formContents->additional->enabled;
600 $fromRestrictionSetitings = empty($formContents->additional->settings) ? null : $formContents->additional->settings;
601 if (is_null($formContents->additional->enabled) || is_null($formContents->additional->settings)) {
602 return false;
603 }
604 $restrictionMessage = [];
605 $ipTool = new IpTool();
606 $ipAddress = $ipTool->getIP();
607 foreach ($fromRestrictionSetitingsEnabled as $restrictionKey => $isEnabled) {
608 if ($isEnabled) {
609 if ('entry_limit' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
610 $formEntry = new FormEntryModel();
611 $countResult = $formEntry->count(
612 [
613 'form_id' => $this->form_id
614 ]
615 );
616 $count = !empty($countResult[0]) && !empty($countResult[0]->count) ? $countResult[0]->count : false;
617 if ($count && $count >= intval($fromRestrictionSetitings->{$restrictionKey})) {
618 $restrictionMessage[] = __('Sorry!! Entry limit exceeded', 'bit-form');
619 }
620 }
621 if ('onePerIp' === $restrictionKey) {
622 $formEntry = new FormEntryModel();
623 $countResult = $formEntry->count(
624 [
625 'form_id' => $this->form_id,
626 'user_ip' => ip2long($ipAddress)
627 ]
628 );
629 $count = !empty($countResult[0]) && !empty($countResult[0]->count) ? $countResult[0]->count : false;
630
631 if ($count && $count > 0) {
632 $restrictionMessage[] = __('Sorry!! You have already submitted', 'bit-form');
633 }
634 }
635 if ('is_login' === $restrictionKey && 0 === get_current_user_id()) {
636 $restrictionMessage[] = __($fromRestrictionSetitings->is_login->message, 'bit-form');
637 }
638 if ($checkedEmptySubmitted && 'empty_submission' === $restrictionKey) {
639 $isEmpty = $this->checkEmptySubmission($_POST, $_FILES);
640 if ($isEmpty) {
641 $restrictionMessage[] = __($fromRestrictionSetitings->empty_submission->message, 'bit-form');
642 }
643 }
644 if ('restrict_form' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
645 $day = empty($fromRestrictionSetitings->{$restrictionKey}->day) ? null : $fromRestrictionSetitings->{$restrictionKey}->day;
646 $date = empty($fromRestrictionSetitings->{$restrictionKey}->date) ? null : $fromRestrictionSetitings->{$restrictionKey}->date;
647 $time = empty($fromRestrictionSetitings->{$restrictionKey}->time) ? null : $fromRestrictionSetitings->{$restrictionKey}->time;
648
649 $isdayOk = $isdateOk = $istimeOk = true;
650 $dayNotOkMsg = $dateNotOkMsg = $timeNotOkMsg = '';
651 $dateTimeHelper = new DateTimeHelper();
652 if (
653 !empty($day)
654 && is_array($day)
655 && (in_array('Friday', $day)
656 || in_array('Saturday', $day)
657 || in_array('Sunday', $day)
658 || in_array('Monday', $day)
659 || in_array('Tuesday', $day)
660 || in_array('Wednesday', $day)
661 || in_array('Thursday', $day))
662 && (!in_array($dateTimeHelper->getDay('full-name'), $day))
663 ) {
664 $isdayOk = false;
665 $dayMsgVarsFormat = '';
666 foreach ($day as $dayIndex => $dayValue) {
667 if ($dayIndex > 0) {
668 $dayMsgVarsFormat .= ', ';
669 }
670 $dayMsgVarsFormat .= '%s';
671 }
672 $dayNotOkMsg = vsprintf(__("in $dayMsgVarsFormat", 'bit-form'), $day);
673 }
674 if (
675 !empty($day)
676 && is_array($day)
677 && (in_array('Custom', $day))
678 ) {
679 $startDate = empty($date->from) ? '00-00-0000' : $date->from;
680 $endDate = empty($date->to) ? '00-00-0000' : $date->to;
681 $dateFormat = preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $startDate) ? 'Y-m-d' : 'm-d-Y';
682 if (!empty($date->from) && false !== strpos($startDate, 'T')) {
683 $startDate = $dateTimeHelper->getDate($startDate, false, null, $dateFormat);
684 }
685 if (!empty($date->to) && false !== strpos($endDate, 'T')) {
686 $endDate = $dateTimeHelper->getDate($endDate, false, null, $dateFormat);
687 }
688 $currentDate = $dateTimeHelper->getDate(null, null, null, $dateFormat);
689 if (!($currentDate >= $startDate && $currentDate <= $endDate)) {
690 $isdateOk = false;
691 $dateNotOkMsg = sprintf(__('within %s to %s', 'bit-form'), $startDate, $endDate);
692 }
693 }
694
695 if (!empty($time)) {
696 $startTime = empty($time->from) ? '00:00' : $time->from;
697 $endTime = empty($time->to) ? '23:59.999' : $time->to;
698 $currentTime = $dateTimeHelper->getTime(null, null, null, 'H:i');
699 if (!($currentTime >= $startTime && $currentTime <= $endTime)) {
700 $istimeOk = false;
701 $startTime = $dateTimeHelper->getTime($startTime, 'H:i', null);
702 $endTime = $dateTimeHelper->getTime($endTime, 'H:i', null);
703 $isTimeOk = false;
704 $timeNotOkMsg = sprintf(__('%s to %s', 'bit-form'), $startTime, $endTime);
705 }
706 }
707
708 if (!($isdateOk && $isdayOk && $istimeOk)) {
709 if (!$isdayOk) {
710 $restrictionMessage[] = !empty($timeNotOkMsg) ? sprintf(__('Form is available %s From %s', 'bit-form'), $dayNotOkMsg, $timeNotOkMsg) :
711 sprintf(__('Form is available %s', 'bit-form'), $dayNotOkMsg, $timeNotOkMsg);
712 } elseif (!$isdateOk) {
713 $restrictionMessage[] = !empty($timeNotOkMsg) ? sprintf(__('Form is available %s From %s', 'bit-form'), $dateNotOkMsg, $timeNotOkMsg) :
714 sprintf(__('Form is available %s', 'bit-form'), $dateNotOkMsg, $timeNotOkMsg);
715 } elseif (!$istimeOk) {
716 $restrictionMessage[] = sprintf(__('Form is available on %s', 'bit-form'), $timeNotOkMsg);
717 }
718 }
719 }
720 if ('blocked_ip' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
721 $isIpBlocked = false;
722 foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
723 if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
724 $isIpBlocked = true;
725 break;
726 }
727 }
728 if ($isIpBlocked) {
729 $restrictionMessage[] = sprintf(__('Sorry!! Your IP address is %s, Blocked from submitting the form', 'bit-form'), $ipAddress);
730 }
731 }
732 if ('private_ip' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
733 $isIpWhiteListed = false;
734 foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
735 if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
736 $isIpWhiteListed = true;
737 break;
738 }
739 }
740 if (!$isIpWhiteListed) {
741 $restrictionMessage[] = sprintf(__('Sorry!! Your IP address is %s, Blocked from submitting the form', 'bit-form'), $ipAddress);
742 }
743 }
744 }
745 }
746 return $restrictionMessage;
747 }
748
749 /**
750 * Will check if form is submitted by a bot
751 *
752 * @return Boolean true - if submitted by bot else false
753 */
754 public function isTrappedInHoneypot()
755 {
756 $isHoneyPot = false;
757
758 if (!$this->isHoneypotActive()) {
759 return false;
760 }
761
762 $token = $_POST['b_h_t'];
763 $pattern = '/^([a-zA-Z0-9]*_[a-zA-Z0-9]*){4}$/';
764 $decryptedToken = base64_decode(base64_decode($token));
765
766 preg_match($pattern, $decryptedToken, $validToken);
767
768 if ($validToken) {
769 if (isset($_POST[$token]) && empty($_POST[$token])) {
770 $isHoneyPot = false;
771 } else {
772 $isHoneyPot = true;
773 }
774 } else {
775 $isHoneyPot = true;
776 }
777
778 if (isset($_POST[$token])) {
779 unset($_POST[$token]);
780 }
781 unset($_POST['b_h_t']);
782 return $isHoneyPot;
783 }
784
785 public function isHoneypotActive()
786 {
787 $formContents = $this->getFormContent();
788 $enabled = empty($formContents->additional->enabled) ? null : $formContents->additional->enabled;
789 if (!empty($enabled->honeypot) && $enabled->honeypot) {
790 return true;
791 }
792 return false;
793 }
794
795 public function checkPaymentFields()
796 {
797 $formContents = $this->getFormContent();
798 $fields = $formContents->fields;
799
800 $payments = [];
801 foreach ($fields as $fldData) {
802 if ('paypal' === $fldData->typ && property_exists($fldData, 'payIntegID')) {
803 $payments['paypalKey'] = $this->getClientKey($fldData->payIntegID, 'clientID');
804 } elseif ('razorpay' === $fldData->typ && property_exists($fldData->options, 'payIntegID')) {
805 $payments['razorpayKey'] = $this->getClientKey($fldData->options->payIntegID, 'apiKey');
806 }
807 }
808
809 return $payments;
810 }
811
812 private function getClientKey($integID, $keyName)
813 {
814 $client = '';
815 if (!empty($integID)) {
816 $integrationHandler = new IntegrationHandler(0);
817 $integration = $integrationHandler->getAIntegration($integID, 'app', 'payments');
818 if (!is_wp_error($integration)) {
819 $integration_details = json_decode($integration[0]->integration_details);
820 $client = base64_encode($integration_details->{$keyName});
821 }
822 }
823 return $client;
824 }
825
826 public function getSuccessMessageMarkups()
827 {
828 if (is_null($this->_work_flows)) {
829 $workFlowManager = new WorkFlowHandler($this->form_id);
830 $this->_work_flows = $workFlowManager->getAllworkFlow();
831 }
832
833 $ids = [];
834 foreach ($this->_work_flows as $msgItem) {
835 foreach ($msgItem['conditions'] as $condition) {
836 if (isset($condition->actions->success)) {
837 foreach ($condition->actions->success as $msg) {
838 if ('successMsg' === $msg->type && isset($msg->details->id)) {
839 $idObj = json_decode(stripslashes($msg->details->id));
840 if (is_object($idObj) && !empty($idObj->id)) {
841 array_push($ids, $idObj->id);
842 }
843 }
844 }
845 }
846 if (isset($condition->actions->failure)) {
847 $idObj = json_decode(stripslashes($condition->actions->failure));
848 if (is_object($idObj) && !empty($idObj->id)) {
849 array_push($ids, $idObj->id);
850 }
851 }
852 }
853 }
854 $ids = array_unique($ids);
855 if (is_null($this->_conf_messages)) {
856 $successMsgHandler = new SuccessMessageHandler($this->form_id);
857 $this->_conf_messages = $successMsgHandler->getMessages($ids);
858 }
859
860 $messageMarkups = '';
861 if (is_wp_error($this->_conf_messages)) {
862 return $messageMarkups;
863 }
864
865 foreach ($this->_conf_messages as $msgItem) {
866 $messageMarkups .= $this->messageMarkup($msgItem);
867 }
868
869 return $messageMarkups;
870 }
871
872 public function getFormAbandonmentMessage()
873 {
874 if (class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
875 $formAbandonmentSettings = FormAbandonment::getFormAbandonmentSettings($this->form_id);
876 $msg = '';
877 if (isset($formAbandonmentSettings->showWarningMsg) && $formAbandonmentSettings->showWarningMsg && !empty($formAbandonmentSettings->warningMsg)) {
878 $msg = $formAbandonmentSettings->warningMsg;
879 $msg = '<div class="bf-form-msg active warning">' . wp_kses_post($msg) . '</div>';
880 }
881 return $msg;
882 }
883 }
884
885 private function messageMarkup($msg)
886 {
887 $msgId = $msg->id;
888 $msgConfig = json_decode($msg->message_config);
889 $scrollClass = 'below' === $msgConfig->msgType ? 'scroll' : '';
890
891 return <<<SUCCESSMSG
892 <div role="dialog" aria-hidden="true" data-modal-backdrop="true" class="{$this->getAtomicCls("msg-container-{$msgId}")} deactive {$scrollClass}">
893 <div data-contentid="{$this->getFormIdentifier()}" data-msgid="{$msgId}" role="button" class="{$this->getAtomicCls("msg-background-{$msgId}")} msg-backdrop">
894 <div class="bf-msg-content {$this->getAtomicCls("msg-content-{$msgId}")}">
895 <button data-contentid="{$this->getFormIdentifier()}" data-msgid="{$msgId}" class="{$this->getAtomicCls("close-{$msgId}")} bf-msg-close" type="button">
896 <svg class="{$this->getAtomicCls("close-icn-{$msgId}")}" viewBox="0 0 30 30">
897 <line fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" x1="4" y1="3.88" x2="26" y2="26.12"></line>
898 <line fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" x1="26" y1="3.88" x2="4" y2="26.12"></line>
899 </svg>
900 </button>
901 <div class="msg-content"></div>
902 </div>
903 </div>
904 </div>
905 SUCCESSMSG;
906 }
907 }
908