PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.21.4
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.21.4
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 2.10.2 All 137 releases
← All changes | includes/Frontend/Form/FrontendFormManager.php +1000 -473 1.92.21.4 View file →
@@ -9,569 +9,1096 @@
9 9 /**
10 10 * FrontendFormManager class
11 11 */
12 12
13 -use WP_Error;
14 -use BitCode\BitForm\Core\Util\IpTool;
15 -use BitCode\BitForm\Core\Util\HttpHelper;
13 +use BitCode\BitForm\Admin\Form\AdminFormHandler;
14 +use BitCode\BitForm\Admin\Form\Helpers;
15 +use BitCode\BitForm\Core\Database\FormEntryModel;
16 16 use BitCode\BitForm\Core\Form\FormManager;
17 +use BitCode\BitForm\Core\Form\Validator\FormFieldValidator;
18 +use BitCode\BitForm\Core\Integration\IntegrationHandler;
19 +use BitCode\BitForm\Core\Messages\SuccessMessageHandler;
20 +use BitCode\BitForm\Core\Util\ApiResponse as UtilApiResponse;
17 21 use BitCode\BitForm\Core\Util\DateTimeHelper;
18 -use BitCode\BitForm\Core\Database\FormEntryModel;
22 +use BitCode\BitForm\Core\Util\EntryLimitHelper;
23 +use BitCode\BitForm\Core\Util\HttpHelper;
24 +use BitCode\BitForm\Core\Util\IpTool;
25 +use BitCode\BitForm\Core\WorkFlow\WorkFlow;
26 +use BitCode\BitForm\Core\WorkFlow\WorkFlowHandler;
19 27 use BitCode\BitForm\Frontend\Form\View\FormViewer;
20 -use BitCode\BitForm\Core\WorkFlow\WorkFlowRunHelper;
21 -use BitCode\BitForm\Core\Integration\IntegrationHandler;
22 -use BitCode\BitForm\Core\Form\Validator\FormFieldValidator;
23 -use BitCode\BitForm\Core\Util\ApiResponse as UtilApiResponse;
28 +use BitCode\BitFormPro\Admin\FormSettings\FormAbandonment;
29 +use WP_Error;
24 30
25 31 final class FrontendFormManager extends FormManager
26 32 {
27 - private $_form_identifier;
28 - private $_form_token;
29 - private $_form_id;
30 - // private $_has_upload = false;
31 - public function __construct($form_id, $shortCodeCounter = null)
32 - {
33 - parent::__construct($form_id);
34 - $this->_form_identifier = 'bitforms_' . $form_id . '_submit_';
35 - $this->_form_identifier .= !empty(get_post()->ID) ? get_post()->ID : '';
36 - $this->_form_identifier .= !empty($shortCodeCounter) ? "_$shortCodeCounter" : '';
37 - $this->_form_token = wp_create_nonce('bitforms_' . $form_id);
38 - $this->_form_id = $form_id;
33 + private $_form_identifier;
34 + private $_form_token;
35 + private $_form_id;
36 + private $_work_flows;
37 + private $_conf_messages;
38 + private static $_instance = [];
39 +
40 + // private $_has_upload = false;
41 + public function __construct($form_id, $shortCodeCounter = null)
42 + {
43 + parent::__construct($form_id);
44 + $this->_form_identifier = 'bitforms_' . $form_id;
45 + $this->_form_identifier .= !empty(get_post()->ID) ? '_' . get_post()->ID : '';
46 + $this->_form_identifier .= !empty($shortCodeCounter) ? "_$shortCodeCounter" : '';
47 + $this->_form_token = wp_create_nonce('bitforms_' . $form_id);
48 + $this->_form_id = $form_id;
49 + }
50 +
51 + public static function getInstance($form_id, $shortCodeCounter = null)
52 + {
53 + $key = $form_id . ':' . ($shortCodeCounter ?? 'default');
54 +
55 + if (!isset(self::$_instance[$key])) {
56 + self::$_instance[$key] = new self($form_id, $shortCodeCounter);
39 57 }
40 58
41 - public function getFormIdentifier()
42 - {
43 - return $this->_form_identifier;
59 + return self::$_instance[$key];
60 + }
61 +
62 + public function getFormIdentifier()
63 + {
64 + return $this->_form_identifier;
65 + }
66 +
67 + public function getFormID()
68 + {
69 + return $this->_form_id;
70 + }
71 +
72 + public function getFormToken()
73 + {
74 + return $this->_form_token;
75 + }
76 +
77 + public function isSubmitted()
78 + {
79 + // return isset($_POST[$this->_form_identifier]) ? true : false;
80 + return (isset($_POST['bitforms_id']) && $_POST['bitforms_id'] === $this->_form_identifier) ? true : false;
81 + }
82 +
83 + public function getSubmittedFields($submitted_data)
84 + {
85 + unset($submitted_data[$this->_form_identifier]);
86 + // unset($submitted_data['bit-form-submit-btn']);
87 + return array_keys($submitted_data);
88 + }
89 +
90 + public function formView($fields = null, $hasFile = false, $errorMessages = null, $previousValue = null)
91 + {
92 + $formContents = $this->getFormContent();
93 + $formAtomicClsMap = $this->getAtomicClsMap();
94 + if (!empty($fields)) {
95 + $formContents->fields = is_string($fields) ? json_decode($fields) : $fields;
96 + } else {
97 + $workFlowRunHelper = new WorkFlow($this->form_id);
98 + $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
99 + 'create',
100 + $formContents->fields
101 + );
102 + $formContents->fields = empty($workFlowreturnedOnLoad['fields']) ? $formContents->fields : $workFlowreturnedOnLoad['fields'];
44 103 }
104 + $formViewer = new FormViewer($this, $formContents, $formAtomicClsMap, $errorMessages, $previousValue);
105 + $isRestricted = $this->checkSubmissionRestriction(false);
106 + $msg = !empty($isRestricted) ? $isRestricted[0] : '';
107 + return $formViewer->getView($hasFile, $msg);
108 + }
45 109
46 - public function getFormID()
47 - {
48 - return $this->_form_id;
110 + public function conversationalFormView($fields = null, $hasFile = false, $errorMessages = null, $previousValue = null)
111 + {
112 + $formContents = $this->getFormContent();
113 + $formAtomicClsMap = $this->getAtomicClsMap();
114 + if (!empty($fields)) {
115 + $formContents->fields = is_string($fields) ? json_decode($fields) : $fields;
116 + } else {
117 + $workFlowRunHelper = new WorkFlow($this->form_id);
118 + $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
119 + 'create',
120 + $formContents->fields
121 + );
122 + $formContents->fields = empty($workFlowreturnedOnLoad['fields']) ? $formContents->fields : $workFlowreturnedOnLoad['fields'];
49 123 }
124 + $formViewer = new FormViewer($this, $formContents, $formAtomicClsMap, $errorMessages, $previousValue);
125 + $isRestricted = $this->checkSubmissionRestriction(false);
126 + $msg = !empty($isRestricted) ? $isRestricted[0] : '';
127 + return $formViewer->getConversationalView($hasFile, $msg);
128 + }
50 129
51 - public function getFormToken()
52 - {
53 - return $this->_form_token;
130 + public function checkEmptySubmission($data, $file)
131 + {
132 + $formFields = $this->getFields();
133 + foreach ($formFields as $key => $field) {
134 + $fieldType = $field['type'];
135 + if ('button' === $fieldType) {
136 + continue;
137 + }
138 + $fileUploadFieldTypes = ['file-up', 'advanced-file-up'];
139 + if ('decision-box' === $fieldType || 'gdpr' === $fieldType) {
140 + continue;
141 + }
142 + $isFileType = in_array($fieldType, $fileUploadFieldTypes);
143 + if ($this->isRepeatedField($key)) {
144 + $fileData = !empty($file[$key]) ? $file[$key] : [];
145 + $dataVal = !empty($data[$key]) ? $data[$key] : [];
146 + if (!$this->checkRepeatedFieldEmptySubmission($isFileType, $dataVal, $fileData)) {
147 + return false;
148 + }
149 + continue;
150 + }
151 + if (!$isFileType && (!empty($data[$key]) || (isset($data[$key]) && is_numeric($data[$key])))) {
152 + return false;
153 + }
154 + if ($isFileType && !empty($file[$key]['name']) && is_string($file[$key]['name'])) {
155 + return false;
156 + }
157 + if ($isFileType && !empty($file[$key]['name'][0])) {
158 + return false;
159 + }
54 160 }
161 + return true;
162 + }
55 163
56 - public function isSubmitted()
57 - {
58 - return isset($_POST[$this->_form_identifier]) ? true : false;
164 + private function checkRepeatedFieldEmptySubmission($isFileType, $data, $file = [])
165 + {
166 + if (!$isFileType) {
167 + foreach ($data as $value) {
168 + if (!empty($value)) {
169 + return false;
170 + }
171 + }
59 172 }
173 + if ($isFileType) {
174 + foreach ($file['name'] as $value) {
175 + if (!empty($value) && is_string($value)) {
176 + return false;
177 + }
178 + if (is_array($value) && !empty($value[0])) {
179 + return false;
180 + }
181 + }
182 + }
183 + return true;
184 + }
60 185
61 - public function getSubmittedFields($submitted_data)
62 - {
63 - unset($submitted_data[$this->_form_identifier]);
64 - return array_keys($submitted_data);
186 + private function getParams()
187 + {
188 + $url = wp_parse_url(wp_get_referer());
189 + $parameter = [];
190 + if (isset($url['query'])) {
191 + $queries = explode('&', $url['query']);
192 + foreach ($queries as $query) {
193 + list($field, $value) = explode('=', $query);
194 + $parameter[$field] = $value;
195 + }
65 196 }
197 + return $parameter;
198 + }
66 199
67 - public function formView($fields = null, $hasFile = false, $errorMessages = null, $previousValue = null)
68 - {
69 - $formContents = $this->getFormContent();
70 - if (!empty($fields)) {
71 - $formContents->fields = is_string($fields) ? json_decode($fields) : $fields;
200 + private function getFormFields($formID)
201 + {
202 + $adminFormHandler = new AdminFormHandler();
203 + $post = new \stdClass();
204 + $post = (object) [
205 + 'id' => $formID
206 + ];
207 + $getForm = $adminFormHandler->getAForm('', $post);
208 + $formContainer = $getForm['form_content'];
209 +
210 + return $formContainer['fields'];
211 + }
212 +
213 + private function transformDrpdwnValue($post)
214 + {
215 + $formFields = $this->getFormFields($this->_form_id);
216 +
217 + foreach ($post as $key => $value) {
218 + if (!str_starts_with($key, 'repeater') && 'select' === $formFields->{$key}->typ) {
219 + if (is_array($value)) {
220 + foreach ($value as $k => $v) {
221 + $post[$key][$k] = explode(BITFORMS_BF_SEPARATOR, $v);
222 + }
72 223 } else {
73 - $workFlowRunHelper = new WorkFlowRunHelper($this->form_id);
74 - $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
75 - 'create',
76 - $formContents->fields
77 - );
78 - $formContents->fields = empty($workFlowreturnedOnLoad['fields']) ? $formContents->fields : $workFlowreturnedOnLoad['fields'];
224 + $post[$key] = explode(BITFORMS_BF_SEPARATOR, $value);
79 225 }
80 - $formViewer = new FormViewer($this, $formContents, $errorMessages, $previousValue);
81 - return $formViewer->getView($hasFile);
226 + };
82 227 }
83 228
84 - private function checkEmptySubmission($data, $file)
85 - {
86 - $form_fields = $this->getFields();
87 - $emptySubmission = true;
88 - foreach ($form_fields as $key => $field) {
89 - if (!empty($data[$key]) || !empty($file[$key]['name'])) {
90 - $emptySubmission = false;
91 - break;
229 + return $post;
230 + }
231 +
232 + public function handleSubmission()
233 + {
234 + $this->fieldNameReplaceOfPost();
235 +
236 + $validated = $this->beforeSubmittedValidate();
237 +
238 + $validated = apply_filters('bitform_filter_form_validation', $validated, $this->_form_id);
239 +
240 + if (true === $validated) {
241 + do_action('bitform_validation_success', $this->_form_id);
242 + unset($_POST['hidden_fields']);
243 +
244 + $redirectPage = '';
245 + $regSuccMsg = '';
246 +
247 + $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
248 + if (!is_wp_error($existAuth) && count($existAuth) > 0) {
249 + $parameter = $this->getParams();
250 + $existAuthFilter = has_filter('bf_wp_user_auth');
251 +
252 + if (true === $existAuthFilter) {
253 + $result = apply_filters('bf_wp_user_auth', $existAuth[0], $_POST, $parameter);
254 +
255 + $result = apply_filters('bitform_filter_wp_user_auth_response', $result, $this->_form_id, $_POST, $parameter);
256 +
257 + do_action('bitform_wp_user_auth_response', $result, $this->_form_id, $_POST, $parameter);
258 +
259 + if (isset($result['auth_type']) && 'register' === $result['auth_type']) {
260 + if (!$result['success']) {
261 + return new WP_Error('errors', __($result['message'], 'bit-form'));
262 + } elseif (isset($result['success'])) {
263 + $redirectPage = $result['redirectPage'];
264 + $regSuccMsg = $result['message'];
92 265 }
266 + } else {
267 + if (!$result['success']) {
268 + return new WP_Error('errors', __($result['message'], 'bit-form'));
269 + } else {
270 + return $result;
271 + }
272 + }
93 273 }
94 - return $emptySubmission;
95 - }
274 + }
96 275
97 - private function getParams()
98 - {
99 - $url = parse_url(wp_get_referer());
100 - $parameter = [];
101 - if (isset($url['query'])) {
102 - $queries = explode('&', $url['query']);
103 - foreach ($queries as $query) {
104 - list($field, $value) = explode('=', $query);
105 - $parameter[$field] = $value;
276 + $saveResponse = $this->saveFormEntry($_POST);
277 + if (is_wp_error($saveResponse)) {
278 + return $saveResponse;
279 + }
280 +
281 + $entryID = $saveResponse['entry_id'];
282 +
283 + // transformed dropdown value from string to array
284 + $newPost = $this->transformDrpdwnValue($_POST);
285 +
286 + do_action('bitform_submit_success', $this->_form_id, $entryID, $newPost, $_FILES);
287 +
288 + $captchaV3Settings = $this->getCaptchaV3Settings();
289 + if ($captchaV3Settings) {
290 + $token = $_POST['g-recaptcha-response'];
291 + $integrationHandler = new IntegrationHandler(0);
292 + $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
293 + if (!is_wp_error($allFormIntegrations)) {
294 + foreach ($allFormIntegrations as $integration) {
295 + if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
296 + $integrationDetails = json_decode($integration->integration_details);
297 + $integrationDetails->id = $integration->id;
298 + $reCAPTCHA = $integrationDetails;
106 299 }
300 + }
107 301 }
108 - return $parameter;
302 + if (!empty($reCAPTCHA->secretKey)) {
303 + $gRecaptchaResponse = HttpHelper::post(
304 + 'https://www.google.com/recaptcha/api/siteverify',
305 + ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
306 + );
307 + if ($captchaV3Settings && !empty($saveResponse['triggerData'])) {
308 + $logID = $saveResponse['triggerData']['logID'];
309 + $integId = $reCAPTCHA->id;
310 + $saveApiResponse = new UtilApiResponse();
311 + $saveApiResponse->apiResponse($logID, $integId, ['type_name' => 'ReCaptcha', 'type' => 'v3'], 'success', $gRecaptchaResponse);
312 + }
313 + }
314 + unset($_POST['g-recaptcha-response']);
315 + }
316 + if (!empty($redirectPage) && empty($saveResponse['redirectPage']) || null === $saveResponse['redirectPage']) {
317 + $saveResponse['redirectPage'] = $redirectPage;
318 + }
319 + if (!empty($regSuccMsg) && isset($saveResponse['dflt_message'])) {
320 + $saveResponse['message'] = $regSuccMsg;
321 + }
322 + $saveResponse['new_nonce'] = wp_create_nonce('bitforms_' . $this->_form_id);
323 +
324 + $saveResponse = IntegrationHandler::maybeSetCronForIntegration($saveResponse, 'create');
325 + $entryId = $saveResponse['entry_id'];
326 +
327 + $responseMsg = is_array($saveResponse) && !empty($saveResponse) ? $saveResponse : __('Form Submitted Successfully', 'bit-form');
328 + $_POST = [];
329 + $responseMsg['entry_id'] = $entryId;
330 + return $responseMsg;
109 331 }
332 + do_action('bitform_validation_error', $this->_form_id, $validated);
333 + return $validated;
334 + }
110 335
336 + public function handleUpdateEntry()
337 + {
338 + $this->fieldNameReplaceOfPost();
339 + $validated = $this->beforeSubmittedValidate();
340 + $validated = apply_filters('bitform_filter_form_validation', $validated, $this->_form_id);
111 341
112 - public function handleSubmission()
113 - {
114 - $validated = $this->beforeSubmittedValidate();
342 + $entryID = $_REQUEST['entryID'];
343 + $GLOBALS['bf_entry_id'] = $entryID;
344 + if (is_null($entryID)) {
345 + return new WP_Error('empty_form', __('Entries id is invalid', 'bit-form'));
346 + }
347 + if (true === $validated) {
348 + do_action('bitform_validation_success', $this->_form_id);
349 + unset($_POST['hidden_fields'], $_POST['entryID']);
115 350
116 - if ($validated === true) {
117 - unset($_POST['hidden_fields']);
351 + $redirectPage = '';
352 + $regSuccMsg = '';
118 353
119 - $redirectPage = '';
120 - $regSuccMsg = '';
354 + $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
355 + if (!is_wp_error($existAuth) && count($existAuth) > 0) {
356 + $parameter = $this->getParams();
357 + $existAuthFilter = has_filter('bf_wp_user_auth');
121 358
122 - $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
123 - if (!is_wp_error($existAuth) && count($existAuth) > 0) {
359 + if (true === $existAuthFilter) {
360 + $result = apply_filters('bf_wp_user_auth', $existAuth[0], $_POST, $parameter);
124 361
125 - $parameter = $this->getParams();
126 - $existAuthFilter = has_filter('bf_wp_user_auth');
362 + if (isset($result['auth_type']) && 'register' === $result['auth_type']) {
363 + if (!$result['success']) {
364 + return new WP_Error('errors', __($result['message'], 'bit-form'));
365 + } elseif (isset($result['success'])) {
366 + $redirectPage = $result['redirectPage'];
367 + $regSuccMsg = $result['message'];
368 + }
369 + } else {
370 + if (!$result['success']) {
371 + return new WP_Error('errors', __($result['message'], 'bit-form'));
372 + } else {
373 + return $result;
374 + }
375 + }
376 + }
377 + }
127 378
128 - if ($existAuthFilter === true) {
129 - $result = apply_filters('bf_wp_user_auth', $existAuth[0], $_POST, $parameter);
379 + $updateResponse = $this->updateFormEntry($_POST, $this->getFormID(), $entryID);
380 + if (is_wp_error($updateResponse)) {
381 + return $updateResponse;
382 + }
130 383
131 - if (isset($result['auth_type']) && $result['auth_type'] === 'register') {
132 - if (!$result['success']) {
133 - return new WP_Error('errors', __($result['message'], 'bit-form'));
134 - } elseif (isset($result['success'])) {
135 - $redirectPage = $result['redirect_url'];
136 - $regSuccMsg = $result['message'];
137 - $newNonce = wp_create_nonce('bitforms_' . $this->_form_id);
138 - }
139 - } else {
140 - if (!$result['success']) {
141 - return new WP_Error('errors', __($result['message'], 'bit-form'));
142 - } else {
143 - return $result;
144 - }
145 - }
146 - }
384 + // transformed dropdown value from string to array
385 + $newPost = $this->transformDrpdwnValue($_POST);
386 +
387 + //TO DO:: submit success action temporarily added for solution of a issue
388 + do_action('bitform_submit_success', $this->_form_id, $entryID, $newPost, $_FILES);
389 + do_action('bitform_update_success', $this->_form_id, $entryID, $newPost, $_FILES);
390 +
391 + $captchaV3Settings = $this->getCaptchaV3Settings();
392 + if ($captchaV3Settings) {
393 + $token = $_POST['g-recaptcha-response'];
394 + $integrationHandler = new IntegrationHandler(0);
395 + $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
396 + if (!is_wp_error($allFormIntegrations)) {
397 + foreach ($allFormIntegrations as $integration) {
398 + if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
399 + $integrationDetails = json_decode($integration->integration_details);
400 + $integrationDetails->id = $integration->id;
401 + $reCAPTCHA = $integrationDetails;
147 402 }
403 + }
404 + }
405 + if (!empty($reCAPTCHA->secretKey)) {
406 + $gRecaptchaResponse = HttpHelper::post(
407 + 'https://www.google.com/recaptcha/api/siteverify',
408 + ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
409 + );
410 + if ($captchaV3Settings && !empty($updateResponse['triggerData'])) {
411 + $logID = $updateResponse['triggerData']['logID'];
412 + $integId = $reCAPTCHA->id;
413 + $saveApiResponse = new UtilApiResponse();
414 + $saveApiResponse->apiResponse($logID, $integId, ['type_name' => 'ReCaptcha', 'type' => 'v3'], 'success', $gRecaptchaResponse);
415 + }
416 + }
417 + unset($_POST['g-recaptcha-response']);
418 + }
419 + if (!empty($redirectPage) && empty($updateResponse['redirectPage']) || null === $updateResponse['redirectPage']) {
420 + $updateResponse['redirectPage'] = $redirectPage;
421 + }
422 + if (!empty($regSuccMsg) && isset($updateResponse['dflt_message'])) {
423 + $updateResponse['message'] = $regSuccMsg;
424 + }
425 + $updateResponse['new_nonce'] = wp_create_nonce('bitforms_' . $this->_form_id);
426 + $updateResponse = IntegrationHandler::maybeSetCronForIntegration($updateResponse, 'create');
427 + $entryId = $updateResponse['entry_id'];
148 428
149 - $saveResponse = $this->saveFormEntry($_POST);
150 - if (is_wp_error($saveResponse)) {
151 - return $saveResponse;
152 - }
153 - $captchaV3Settings = $this->getCaptchaV3Settings();
154 - if ($captchaV3Settings) {
155 - $token = $_POST['g-recaptcha-response'];
156 - $integrationHandler = new IntegrationHandler(0);
157 - $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'gReCaptchaV3');
158 - if (!is_wp_error($allFormIntegrations)) {
159 - foreach ($allFormIntegrations as $integration) {
160 - if (!is_null($integration->integration_type) && $integration->integration_type === 'gReCaptchaV3') {
161 - $integrationDetails = json_decode($integration->integration_details);
162 - $integrationDetails->id = $integration->id;
163 - $reCAPTCHA = $integrationDetails;
164 - }
165 - }
166 - }
167 - if (!empty($reCAPTCHA->secretKey)) {
168 - $gRecaptchaResponse = HttpHelper::post(
169 - 'https://www.google.com/recaptcha/api/siteverify',
170 - ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
171 - );
172 - if ($captchaV3Settings && !empty($saveResponse['triggerData'])) {
173 - $logID = $saveResponse['triggerData']['logID'];
174 - $integId = $reCAPTCHA->id;
175 - $saveApiResponse = new UtilApiResponse();
176 - $saveApiResponse->apiResponse($logID, $integId, ['type_name' => 'ReCaptcha', 'type' => 'v3'], 'success', $gRecaptchaResponse);
177 - }
178 - }
179 - unset($_POST['g-recaptcha-response']);
180 - }
181 - if (!empty($redirectPage) && empty($saveResponse['redirectPage']) || $saveResponse['redirectPage'] == null) {
182 - $saveResponse['redirectPage'] = $redirectPage;
183 - }
184 - if (!empty($regSuccMsg) && isset($saveResponse['dflt_message'])) {
185 - $saveResponse['message'] = $regSuccMsg;
186 - }
187 - $saveResponse = IntegrationHandler::maybeSetCronForIntegration($saveResponse, 'create');
429 + $responseMsg = is_array($updateResponse) && !empty($updateResponse) ? $updateResponse : __('Entry Update Successfully', 'bit-form');
188 430
189 - $responseMsg = is_array($saveResponse) && !empty($saveResponse) ? $saveResponse : __('Form Submitted Successfully', 'bit-form');
190 - if (isset($newNonce)) {
191 - $responseMsg['new_nonce'] = $newNonce;
192 - }
193 - $_POST = array();
431 + $_POST = [];
432 + $responseMsg['entry_id'] = $entryId;
433 + return $responseMsg;
434 + }
435 + do_action('bitform_validation_error', $this->_form_id, $validated);
436 + return $validated;
437 + }
194 438
195 - return $responseMsg;
439 + public function validateFormSubmission($submitted_data)
440 + {
441 + $hidden_fields = isset($submitted_data['hidden_fields']) ? $submitted_data['hidden_fields'] : '';
442 + $submitted_fields = $this->getSubmittedFields($submitted_data);
443 + $form_fields = $this->getFields();
444 + $form_fields_names = array_keys($form_fields);
445 + if ($this->isGCLIDEnabled()) {
446 + array_push($form_fields_names, 'GCLID');
447 + }
448 + foreach ($submitted_fields as $field) {
449 + if ('hidden_fields' !== $field && !in_array($field, $form_fields_names) || false !== strpos($hidden_fields, $field)) {
450 + unset($submitted_data[$field]);
451 + }
452 + }
453 + return $submitted_data;
454 + }
455 +
456 + public function beforeSubmittedValidate()
457 + {
458 + if ($this->verifySubmissionNonce()) {
459 + if ($this->isExist()) {
460 + $isRestricted = $this->checkSubmissionRestriction();
461 + if ($isRestricted && !empty($isRestricted)) {
462 + return new WP_Error('spam_detection', $isRestricted[0]);
196 463 }
464 + if ($this->isTrappedInHoneypot()) {
465 + return new WP_Error('spam_detection', __('Token verification failed', 'bit-form'));
466 + }
467 + $formCurrentStep = isset($_POST['form-current-step']) ? $_POST['form-current-step'] : null;
197 468
198 - return $validated;
199 - }
469 + $verifyGRecaptchaResult = $this->verifyGRecaptcha();
470 + if (is_wp_error($verifyGRecaptchaResult)) {
471 + return $verifyGRecaptchaResult;
472 + }
200 473
201 - public function validateFormSubmission($submitted_data)
202 - {
203 - $hidden_fields = isset($submitted_data['hidden_fields']) ? $submitted_data['hidden_fields'] : '';
204 - $submitted_fields = $this->getSubmittedFields($submitted_data);
474 + $verifyHCaptchaResult = $this->verifyHCaptcha();
475 + if (is_wp_error($verifyHCaptchaResult)) {
476 + return $verifyHCaptchaResult;
477 + }
478 +
479 + /* Implement Turnstile Captcha start */
480 + $verifyTurnstileCaptchaResult = $this->verifyTurnstileCaptcha();
481 + if (is_wp_error($verifyTurnstileCaptchaResult)) {
482 + return $verifyTurnstileCaptchaResult;
483 + }
484 + /* Implement Turnstile Captcha end */
485 +
486 + $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
487 +
488 + // check if user is already logged in and form has auth integration
489 + do_action('bitform_checked_exist_auth', $this->_form_id, $existAuth);
490 + if (!is_wp_error($existAuth) && count($existAuth) > 0 && is_user_logged_in()) {
491 + return new WP_Error('auth_error', __('You are already logged in', 'bit-form'));
492 + }
493 + $validateForm = $this->validateFormSubmission($_POST);
494 + $validateFormFiles = $this->validateFormSubmission($_FILES);
495 + $validateForm = array_merge($validateForm, $validateFormFiles);
205 496 $form_fields = $this->getFields();
206 - $form_fields_names = array_keys($form_fields);
207 - if ($this->isGCLIDEnabled()) {
208 - array_push($form_fields_names, 'GCLID');
497 + // check if form-current-step is set and form is multi-step
498 + $formCurrentStep = isset($_POST['form-current-step']) ? $_POST['form-current-step'] : null;
499 + if (!is_null($formCurrentStep)) {
500 + $formContents = $this->getFormContent();
501 + $layout = $formContents->layout;
502 + $stepIndex = (int) $formCurrentStep - 1;
503 + $stepLayout = $layout[$stepIndex]->layout->lg;
504 + $nestedLayout = $formContents->nestedLayout;
505 + $step_fields = [];
506 + foreach ($stepLayout as $lay) {
507 + $fk = $lay->i;
508 + if (isset($nestedLayout->{$fk})) {
509 + $nestedLg = $nestedLayout->{$fk}->lg;
510 + foreach ($nestedLg as $nestedLay) {
511 + $nestedFk = $nestedLay->i;
512 + $step_fields[$nestedFk] = $form_fields[$nestedFk];
513 + }
514 + }
515 + $step_fields[$fk] = $form_fields[$fk];
516 + }
517 + $form_fields = $step_fields;
209 518 }
210 - foreach ($submitted_fields as $key => $field) {
211 - if ($field !== 'hidden_fields' && !in_array($field, $form_fields_names) || strpos($hidden_fields, $field) !== false) {
212 - unset($submitted_data[$field]);
519 + $formFieldValidator = new FormFieldValidator($form_fields, $_POST, $_FILES);
520 + $validUniuqFields = [];
521 + $existFilter = has_filter('bf_check_duplicate_entry');
522 + if (true === $existFilter) {
523 + $validUniuqFields = apply_filters('bf_check_duplicate_entry', $form_fields, $_POST);
524 +
525 + $fieldKeys = array_keys($validUniuqFields);
526 + $form_fields_keys = array_keys($form_fields);
527 + $uniqueFields = [];
528 + foreach ($fieldKeys as $key) {
529 + if (in_array($key, $form_fields_keys)) {
530 + $uniqueFields[] = $form_fields[$key];
213 531 }
532 + }
533 + do_action('bitform_Unique_entry', $uniqueFields, $validUniuqFields, $this->_form_id, $_POST);
214 534 }
215 - return $submitted_data;
535 + $validateField = $formFieldValidator->validate('create', $this->_form_id);
536 +
537 + if ($validateForm && $validateField && 0 === count($validUniuqFields)) {
538 + return true;
539 + } else {
540 + $error = __('Please submit form with valid fields', 'bit-form');
541 + if (!$validateForm) {
542 + $errorMessages = $error;
543 + } elseif (count($formFieldValidator->getMessage()) > 0) {
544 + $errorMessages = $formFieldValidator->getMessage();
545 + } else {
546 + $errorMessages = 0 === count($validUniuqFields) ? $error : $validUniuqFields;
547 + }
548 + return new WP_Error('validation_error', $errorMessages);
549 + }
550 + }
551 + return new WP_Error('unknown_form', __('Form does not exist', 'bit-form'));
552 + } else {
553 + return new WP_Error('token_expired', __('Token expired', 'bit-form'));
216 554 }
555 + }
217 556
218 - public function beforeSubmittedValidate()
219 - {
220 - if ($this->verifySubmissionNonce()) {
221 - if ($this->isExist()) {
222 - $isRestricted = $this->checkSubmissionRestriction();
223 - if ($isRestricted && !empty($isRestricted)) {
224 - return new WP_Error('spam_detection', $isRestricted[0]);
225 - }
226 - if ($this->isTrappedInHoneypot()) {
227 - return new WP_Error('spam_detection', __('Token verification failed', 'bit-form'));
228 - }
229 - $captchaSettings = $this->getCaptchaSettings();
230 - $captchaV3Settings = $this->getCaptchaV3Settings();
231 - if ($captchaSettings || $captchaV3Settings) {
232 - $token = $_POST['g-recaptcha-response'];
233 - if (!isset($_POST['g-recaptcha-response'])) {
234 - return new WP_Error('spam_detection', __('Please verify reCAPTCHA', 'bit-form'));
235 - }
236 - $integrationHandler = new IntegrationHandler(0);
237 - $allFormIntegrations = $integrationHandler->getAllIntegration('app', $captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3');
238 - if (!is_wp_error($allFormIntegrations)) {
239 - foreach ($allFormIntegrations as $integration) {
240 - if (!is_null($integration->integration_type) && $integration->integration_type === ($captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3')) {
241 - $integrationDetails = json_decode($integration->integration_details);
242 - $integrationDetails->id = $integration->id;
243 - $reCAPTCHA = $integrationDetails;
244 - }
245 - }
246 - }
247 - if (!empty($reCAPTCHA->secretKey)) {
248 - $gRecaptchaResponse = HttpHelper::post(
249 - 'https://www.google.com/recaptcha/api/siteverify',
250 - ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
251 - );
252 - $isgReCaptchaVerified = false;
253 - if (!is_wp_error($gRecaptchaResponse)) {
254 - if (
255 - $captchaV3Settings
256 - && !empty($gRecaptchaResponse->score)
257 - && ((float) $gRecaptchaResponse->score < (float) $captchaV3Settings->score)
258 - ) {
259 - wp_send_json_error(
260 - __(
261 - $captchaV3Settings->message,
262 - 'bit-form'
263 - )
264 - );
265 - }
557 + private function verifyGRecaptcha()
558 + {
559 + $captchaSettings = $this->getCaptchaSettings();
560 + $captchaV3Settings = $this->getCaptchaV3Settings();
561 + if ($captchaSettings || $captchaV3Settings) {
562 + $token = $_POST['g-recaptcha-response'];
563 + if (!isset($_POST['g-recaptcha-response'])) {
564 + return new WP_Error('spam_detection', __('Please recheck your reCaptcha Configuration', 'bit-form'));
565 + }
566 + $integrationHandler = new IntegrationHandler(0);
567 + $allFormIntegrations = $integrationHandler->getAllIntegration('app', $captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3');
568 + if (!is_wp_error($allFormIntegrations)) {
569 + foreach ($allFormIntegrations as $integration) {
570 + if (!is_null($integration->integration_type) && $integration->integration_type === ($captchaSettings ? 'gReCaptcha' : 'gReCaptchaV3')) {
571 + $integrationDetails = json_decode($integration->integration_details);
572 + $integrationDetails->id = $integration->id;
573 + $reCAPTCHA = $integrationDetails;
574 + }
575 + }
576 + }
577 + if (!empty($reCAPTCHA->secretKey)) {
578 + $gRecaptchaResponse = HttpHelper::post(
579 + 'https://www.google.com/recaptcha/api/siteverify',
580 + ['secret' => $reCAPTCHA->secretKey, 'response' => $token]
581 + );
582 + $isgReCaptchaVerified = false;
583 + if (!is_wp_error($gRecaptchaResponse)) {
584 + if (
585 + $captchaV3Settings
586 + && !empty($gRecaptchaResponse->score)
587 + && ((float) $gRecaptchaResponse->score < (float) $captchaV3Settings->score)
588 + ) {
589 + wp_send_json_error(
590 + __(
591 + $captchaV3Settings->message,
592 + 'bit-form'
593 + )
594 + );
595 + }
266 596
267 - $isgReCaptchaVerified = $gRecaptchaResponse->success;
268 - }
269 - if (!$isgReCaptchaVerified) {
270 - return new WP_Error('spam_detection', __('Please verify reCAPTCHA', 'bit-form'));
271 - }
272 - }
273 - }
274 - $existAuth = (new IntegrationHandler($this->_form_id))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
275 - if (!is_wp_error($existAuth) && count($existAuth) > 0 && is_user_logged_in()) {
276 - return new WP_Error('auth_error', __('You are already logged in', 'bit-form'));
277 - }
278 - $validateForm = $this->validateFormSubmission($_POST);
279 - $form_fields = $this->getFields();
280 - $formFieldValidator = new FormFieldValidator($form_fields, $_POST, $_FILES);
281 - $validUniuqFields = [];
597 + $isgReCaptchaVerified = $gRecaptchaResponse->success;
598 + }
599 + if (!$isgReCaptchaVerified) {
600 + return new WP_Error('spam_detection', __('Please verify reCAPTCHA', 'bit-form'));
601 + }
602 + }
603 + }
604 + }
282 605
283 - $existFilter = has_filter('bf_check_duplicate_entry');
284 - if ($existFilter === true) {
285 - $validUniuqFields = apply_filters('bf_check_duplicate_entry', $form_fields, $_POST);
286 - }
606 + private function verifyHCaptcha()
607 + {
608 + $hCaptchaExist = $this->isFieldTypeExist('hcaptcha'); // You can rename this to getHCaptchaSettings() if needed
609 + if ($hCaptchaExist) {
610 + if (!isset($_POST['h-captcha-response'])) {
611 + return new WP_Error('spam_detection', __('Please verify hCaptcha', 'bit-form'));
612 + }
287 613
288 - $validateField = $formFieldValidator->validate('create', $this->_form_id);
289 - if ($validateForm && $validateField && count($validUniuqFields) == 0) {
614 + $token = sanitize_text_field($_POST['h-captcha-response']);
290 615
291 - return true;
292 - } else {
293 - $error = __('Please submit form with valid fields', 'bit-form');
294 - if (!$validateForm) {
295 - $errorMessages = $error;
296 - } else if (count($formFieldValidator->getMessage()) > 0) {
297 - $errorMessages = $formFieldValidator->getMessage();
298 - } else {
299 - $errorMessages = count($validUniuqFields) == 0 ? $error : $validUniuqFields;
300 - }
301 - return new WP_Error('validation_error', $errorMessages);
302 - }
303 - }
304 - return new WP_Error('unknown_form', __('Form does not exist', 'bit-form'));
305 - } else {
306 - return new WP_Error('token_expired', __('Token expired', 'bit-form'));
616 + $integrationHandler = new IntegrationHandler(0);
617 + $allFormIntegrations = $integrationHandler->getAllIntegration('app', 'hcaptcha');
618 +
619 + if (!is_wp_error($allFormIntegrations)) {
620 + foreach ($allFormIntegrations as $integration) {
621 + if (!is_null($integration->integration_type) && 'hcaptcha' === $integration->integration_type) {
622 + $integrationDetails = json_decode($integration->integration_details);
623 + $integrationDetails->id = $integration->id;
624 + $hCaptcha = $integrationDetails;
625 + }
307 626 }
308 - }
627 + }
309 628
310 - public function verifySubmissionNonce()
311 - {
312 - if (!isset($_POST['bitforms_token'])) {
313 - return false;
629 + if (!empty($hCaptcha->secretKey)) {
630 + $hCaptchaResponse = HttpHelper::post(
631 + 'https://api.hcaptcha.com/siteverify',
632 + [
633 + 'secret' => $hCaptcha->secretKey,
634 + 'response' => $token,
635 + 'remoteip' => $_SERVER['REMOTE_ADDR'] ?? ''
636 + ]
637 + );
638 +
639 + $isVerified = false;
640 + if (!is_wp_error($hCaptchaResponse)) {
641 + $isVerified = $hCaptchaResponse->success;
314 642 }
315 - $token = sanitize_text_field($_POST['bitforms_token']);
316 - unset($_POST['_ajax_nonce'], $_POST['action'], $_POST['bitforms_id'], $_POST['bitforms_token']);
317 - if (!is_user_logged_in()) {
318 - return true;
643 +
644 + if (!$isVerified) {
645 + return new WP_Error('spam_detection', __('hCaptcha verification failed', 'bit-form'));
319 646 }
320 - return wp_verify_nonce($token, "bitforms_{$this->form_id}");
647 + }
321 648 }
649 + }
322 650
323 - public function setViewCount()
324 - {
325 - if (!current_user_can('manage_options')) {
326 - $update_status = $this->formModel->update(
327 - array(
328 - 'views' => intval(static::$form[0]->views) + 1
329 - ),
330 - array(
331 - 'id' => $this->form_id
332 - )
651 + private function verifyTurnstileCaptcha()
652 + {
653 + $turnstileExist = $this->isFieldTypeExist('turnstile');
654 + if ($turnstileExist) {
655 + if (!isset($_POST['cf-turnstile-response'])) {
656 + return new WP_Error('spam_detection', __('Please verify Cloudflare Turnstile Captcha', 'bit-form'));
657 + }
658 + $token = sanitize_text_field($_POST['cf-turnstile-response']);
659 + $turnstileCaptcha = null;
660 + $integrationHandler = new IntegrationHandler(0);
661 + $turnstileIntegration = $integrationHandler->getAllIntegration('app', 'turnstileCaptcha')[0];
662 + if (!is_wp_error($turnstileIntegration && !is_null($turnstileIntegration->integration_type))) {
663 + $turnstileCaptcha = json_decode($turnstileIntegration->integration_details);
664 + // $integrationDetails->id = $turnstileIntegration->id;
665 + // $turnstileCaptcha = $integrationDetails;
666 + }
667 + if (!is_null($turnstileCaptcha)) {
668 + $isTurnstileCaptchaVerified = false;
669 + $turnstileRecaptchaResponse = HttpHelper::post(
670 + 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
671 + ['secret' => $turnstileCaptcha->secretKey, 'response' => $token]
672 + );
673 + if (!is_wp_error($turnstileRecaptchaResponse)) {
674 + if (!$turnstileRecaptchaResponse->success) {
675 + wp_send_json_error(
676 + __(
677 + 'Cloudflare Turnstile Validation Error: ' . implode(', ', $turnstileRecaptchaResponse->{'error-codes'}),
678 + 'bit-form'
679 + )
333 680 );
681 + }
682 +
683 + $isTurnstileCaptchaVerified = $turnstileRecaptchaResponse->success;
334 684 }
685 + if (!$isTurnstileCaptchaVerified) {
686 + return new WP_Error('spam_detection', __('Please verify Cloudflare Turnstile Captcha', 'bit-form'));
687 + }
688 + }
335 689 }
690 + }
336 691
337 - public function checkSubmissionRestriction()
338 - {
339 - $formContents = $this->getFormContent();
340 - $fromRestrictionSetitingsEnabled = empty($formContents->additional->enabled) ? [] : $formContents->additional->enabled;
341 - $fromRestrictionSetitings = empty($formContents->additional->settings) ? null : $formContents->additional->settings;
342 - if (is_null($formContents->additional->enabled) || is_null($formContents->additional->settings)) {
343 - return false;
692 + public function verifySubmissionNonce()
693 + {
694 + if (!isset($_POST['t_identity']) && !isset($_POST['csrf'])) {
695 + return false;
696 + }
697 + $tIdenty = sanitize_text_field($_POST['t_identity']);
698 + $csrf = sanitize_text_field($_POST['csrf']);
699 + unset($_POST['t_identity'], $_POST['action'], $_POST['bitforms_id'], $_POST['csrf']);
700 + return Helpers::csrfDecrypted($tIdenty, $csrf);
701 + }
702 +
703 + public function setViewCount()
704 + {
705 + if (!current_user_can('manage_options')) {
706 + $update_status = $this->formModel->update(
707 + [
708 + 'views' => intval(static::$form[0]->views) + 1
709 + ],
710 + [
711 + 'id' => $this->form_id
712 + ]
713 + );
714 + }
715 + }
716 +
717 + public function checkSubmissionRestriction($checkedEmptySubmitted = true)
718 + {
719 + $formContents = $this->getFormContent();
720 + $fromRestrictionSetitingsEnabled = empty($formContents->additional->enabled) ? [] : $formContents->additional->enabled;
721 + $fromRestrictionSetitings = empty($formContents->additional->settings) ? null : $formContents->additional->settings;
722 + if (is_null($formContents->additional->enabled) || is_null($formContents->additional->settings)) {
723 + return false;
724 + }
725 + $restrictionMessage = [];
726 + $ipTool = new IpTool();
727 + $ipAddress = $ipTool->getIP();
728 + $currentUserId = get_current_user_id();
729 + foreach ($fromRestrictionSetitingsEnabled as $restrictionKey => $isEnabled) {
730 + if ($isEnabled) {
731 + if (('entry_limit' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) || ('entry_limit_by_user' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey}))) {
732 + $entryLimitHelper = new EntryLimitHelper($this->form_id, $fromRestrictionSetitings, $fromRestrictionSetitingsEnabled);
733 + $advancedLimitMessages = $entryLimitHelper->checkAllLimits($ipAddress, $currentUserId);
734 + $restrictionMessage = array_merge($restrictionMessage, $advancedLimitMessages);
344 735 }
345 - $restrictionMessage = array();
346 - $ipTool = new IpTool();
347 - $ipAddress = $ipTool->getIP();
348 - foreach ($fromRestrictionSetitingsEnabled as $restrictionKey => $isEnabled) {
349 - if ($isEnabled) {
350 - if ($restrictionKey === 'entry_limit' && isset($fromRestrictionSetitings->{$restrictionKey})) {
351 - $formEntry = new FormEntryModel();
352 - $countResult = $formEntry->count(
353 - array(
354 - 'form_id' => $this->form_id
355 - )
356 - );
357 - $count = !empty($countResult[0]) && !empty($countResult[0]->count) ? $countResult[0]->count : false;
358 - if ($count && $count >= intval($fromRestrictionSetitings->{$restrictionKey})) {
359 - $restrictionMessage[] = __('Sorry!! Entry limit exceeded', "bit-form");
360 - }
361 - }
362 - if ($restrictionKey === 'onePerIp') {
363 - $formEntry = new FormEntryModel();
364 - $countResult = $formEntry->count(
365 - array(
366 - 'form_id' => $this->form_id,
367 - 'user_ip' => ip2long($ipAddress)
368 - )
369 - );
370 - $count = !empty($countResult[0]) && !empty($countResult[0]->count) ? $countResult[0]->count : false;
371 736
372 - if ($count && $count > 0) {
373 - $restrictionMessage[] = __('Sorry!! You have already submitted', "bit-form");
374 - }
375 - }
376 - if ($restrictionKey === 'is_login' && get_current_user_id() === 0) {
377 - $restrictionMessage[] = __($fromRestrictionSetitings->is_login->message, "bit-form");
378 - }
379 - if ($restrictionKey === 'empty_submission') {
380 - $isEmpty = $this->checkEmptySubmission($_POST, $_FILES);
381 - if ($isEmpty) {
382 - $restrictionMessage[] = __($fromRestrictionSetitings->empty_submission->message, "bit-form");
383 - }
384 - }
385 - if ($restrictionKey === 'restrict_form' && isset($fromRestrictionSetitings->{$restrictionKey})) {
386 - $day = empty($fromRestrictionSetitings->{$restrictionKey}->day) ? null : $fromRestrictionSetitings->{$restrictionKey}->day;
387 - $date = empty($fromRestrictionSetitings->{$restrictionKey}->date) ? null : $fromRestrictionSetitings->{$restrictionKey}->date;
388 - $time = empty($fromRestrictionSetitings->{$restrictionKey}->time) ? null : $fromRestrictionSetitings->{$restrictionKey}->time;
737 + if ('onePerIp' === $restrictionKey) {
738 + $formEntry = new FormEntryModel();
389 739
390 - $isdayOk = $isdateOk = $istimeOk = true;
391 - $dayNotOkMsg = $dateNotOkMsg = $timeNotOkMsg = '';
392 - $dateTimeHelper = new DateTimeHelper();
393 - if (
394 - !empty($day)
395 - && is_array($day)
396 - && (in_array("Friday", $day)
397 - || in_array("Saturday", $day)
398 - || in_array("Sunday", $day)
399 - || in_array("Monday", $day)
400 - || in_array("Tuesday", $day)
401 - || in_array("Wednesday", $day)
402 - || in_array("Thursday", $day))
403 - && (!in_array($dateTimeHelper->getDay('full-name'), $day))
404 - ) {
405 - $isdayOk = false;
406 - $dayMsgVarsFormat = '';
407 - foreach ($day as $dayIndex => $dayValue) {
408 - if ($dayIndex > 0) {
409 - $dayMsgVarsFormat .= ', ';
410 - }
411 - $dayMsgVarsFormat .= '%s';
412 - }
413 - $dayNotOkMsg = vsprintf(__("in $dayMsgVarsFormat", 'bit-form'), $day);
414 - }
415 - if (
416 - !empty($day)
417 - && is_array($day)
418 - && (in_array("Custom", $day))
419 - ) {
420 - $startDate = empty($date->from) ? '00-00-0000' : $date->from;
421 - $endDate = empty($date->to) ? '00-00-0000' : $date->to;
422 - if (!empty($date->from) && strpos($startDate, 'T') !== false) {
423 - $startDate = $dateTimeHelper->getDate($startDate, false, null, 'm-d-Y');
424 - }
425 - if (!empty($date->to) && strpos($endDate, 'T') !== false) {
426 - $endDate = $dateTimeHelper->getDate($endDate, false, null, 'm-d-Y');
427 - }
428 - $currentDate = $dateTimeHelper->getDate(null, null, null, 'm-d-Y');
429 - if (!($currentDate >= $startDate && $currentDate <= $endDate)) {
430 - $isdateOk = false;
431 - $dateNotOkMsg = sprintf(__("within %s to %s", 'bit-form'), $startDate, $endDate);
432 - }
433 - }
740 + $getResult = $formEntry->get(
741 + ['user_ip', 'status'],
742 + [
743 + 'form_id' => $this->form_id,
744 + 'user_ip' => ip2long($ipAddress)
745 + ],
746 + );
434 747
435 - if (!empty($time)) {
436 - $startTime = empty($time->from) ? '00:00' : $time->from;
437 - $endTime = empty($time->to) ? '23:59.999' : $time->to;
438 - $currentTime = $dateTimeHelper->getTime(null, null, null, 'H:i');
439 - if (!($currentTime >= $startTime && $currentTime <= $endTime)) {
440 - $istimeOk = false;
441 - $startTime = $dateTimeHelper->getTime($startTime, 'H:i', null);
442 - $endTime = $dateTimeHelper->getTime($endTime, 'H:i', null);
443 - $isTimeOk = false;
444 - $timeNotOkMsg = sprintf(__("%s to %s", 'bit-form'), $startTime, $endTime);
445 - }
446 - }
748 + $count = 0;
749 + $status = 0;
447 750
448 - if (!($isdateOk && $isdayOk && $istimeOk)) {
449 - if (!$isdayOk) {
450 - $restrictionMessage[] = !empty($timeNotOkMsg) ? sprintf(__("Form is available %s From %s", 'bit-form'), $dayNotOkMsg, $timeNotOkMsg) :
451 - sprintf(__("Form is available %s", 'bit-form'), $dayNotOkMsg, $timeNotOkMsg);
452 - } elseif (!$isdateOk) {
453 - $restrictionMessage[] = !empty($timeNotOkMsg) ? sprintf(__("Form is available %s From %s", 'bit-form'), $dateNotOkMsg, $timeNotOkMsg) :
454 - sprintf(__("Form is available %s", 'bit-form'), $dateNotOkMsg, $timeNotOkMsg);
455 - } elseif (!$istimeOk) {
456 - $restrictionMessage[] = sprintf(__("Form is available on %s", 'bit-form'), $timeNotOkMsg);
457 - }
458 - }
459 - }
460 - if ($restrictionKey === 'blocked_ip' && isset($fromRestrictionSetitings->{$restrictionKey})) {
461 - $isIpBlocked = false;
462 - foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
463 - if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
464 - $isIpBlocked = true;
465 - break;
466 - }
467 - }
468 - if ($isIpBlocked) {
469 - $restrictionMessage[] = sprintf(__("Sorry!! Your IP address is %s, Blocked from submitting the form", 'bit-form'), $ipAddress);
470 - }
471 - }
472 - if ($restrictionKey === 'private_ip' && isset($fromRestrictionSetitings->{$restrictionKey})) {
473 - $isIpWhiteListed = false;
474 - foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
475 - if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
476 - $isIpWhiteListed = true;
477 - break;
478 - }
479 - }
480 - if (!$isIpWhiteListed) {
481 - $restrictionMessage[] = sprintf(__("Sorry!! Your IP address is %s, Blocked from submitting the form", 'bit-form'), $ipAddress);
482 - }
483 - }
751 + if (!is_wp_error($getResult) && count($getResult) > 0) {
752 + $count = count($getResult);
753 +
754 + foreach ($getResult as $row) {
755 + if (9 === (int) $row->status) {
756 + $status = 9;
757 + break;
758 + }
484 759 }
760 + }
761 +
762 + if ($count > 0 && 9 !== (int) $status) {
763 + $onePerIp = __('Sorry!! You have already submitted from this IP address', 'bit-form');
764 +
765 + $onePerIp = apply_filters(
766 + 'bitform_filter_restriction_one_per_ip_message',
767 + $onePerIp,
768 + $this->form_id
769 + );
770 +
771 + $restrictionMessage[] = $onePerIp;
772 + }
485 773 }
486 - return $restrictionMessage;
487 - }
774 + if ('is_login' === $restrictionKey && 0 === get_current_user_id()) {
775 + $is_login_messages = $fromRestrictionSetitings->is_login->message;
488 776
489 - public function honeypotTrap()
490 - {
491 - if ($this->isHoneypotActive()) {
492 - $time = \time();
493 - $token = base64_encode(base64_encode($time . "." . wp_hash(wp_get_session_token() . $time)));
494 - $script = "document.addEventListener('DOMContentLoaded',(event)=>{ let frm=document.getElementById('form-{$this->_form_identifier}'),token=document.createElement('input');token.type='hidden',token.name='token',token.value='$token',frm.prepend(token);let nam=document.createElement('input');nam.type='text',nam.className='vis-n',nam.name='{$token}.name',frm.prepend(nam);let em=document.createElement('input');em.type='email',em.className='vis-n',em.name='{$token}.email',frm.prepend(em);let msg=document.createElement('textarea');msg.className='vis-n',msg.name='{$token}.message',frm.prepend(msg);})";
495 - wp_add_inline_script('bitforms-frontend-script', $script, 'after');
777 + $is_login_messages = apply_filters(
778 + 'bitform_filter_restriction_is_login_message',
779 + $is_login_messages,
780 + $this->form_id
781 + );
782 +
783 + $restrictionMessage[] = $is_login_messages;
496 784 }
497 - return;
498 - }
785 + if ($checkedEmptySubmitted && 'empty_submission' === $restrictionKey) {
786 + $isEmpty = $this->checkEmptySubmission($_POST, $_FILES);
787 + if ($isEmpty) {
788 + $restriction = $fromRestrictionSetitings->empty_submission->message;
499 789
500 - /**
501 - * Will check if form is submitted by a bot
502 - *
503 - * @return Boolean true - if submitted by bot else false
504 - */
505 - public function isTrappedInHoneypot()
506 - {
507 - if (!$this->isHoneypotActive()) {
508 - return false;
790 + $restriction = apply_filters(
791 + 'bitform_filter_restriction_empty_submission_message',
792 + $restriction,
793 + $this->form_id
794 + );
795 +
796 + $restrictionMessage[] = $restriction;
797 + }
509 798 }
799 + if ('restrict_form' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
800 + $day = empty($fromRestrictionSetitings->{$restrictionKey}->day) ? null : $fromRestrictionSetitings->{$restrictionKey}->day;
801 + $date = empty($fromRestrictionSetitings->{$restrictionKey}->date) ? null : $fromRestrictionSetitings->{$restrictionKey}->date;
802 + $time = empty($fromRestrictionSetitings->{$restrictionKey}->time) ? null : $fromRestrictionSetitings->{$restrictionKey}->time;
510 803
511 - if (empty($_POST['token'])) {
512 - return true;
513 - } else {
514 - $token = $_POST['token'];
804 + $isdayOk = $isdateOk = $istimeOk = true;
805 + $dayNotOkMsg = $dateNotOkMsg = $timeNotOkMsg = '';
806 + $dateTimeHelper = new DateTimeHelper();
807 + if (
808 + !empty($day)
809 + && is_array($day)
810 + && (in_array('Friday', $day)
811 + || in_array('Saturday', $day)
812 + || in_array('Sunday', $day)
813 + || in_array('Monday', $day)
814 + || in_array('Tuesday', $day)
815 + || in_array('Wednesday', $day)
816 + || in_array('Thursday', $day))
817 + && (!in_array($dateTimeHelper->getDay('full-name'), $day))
818 + ) {
819 + $isdayOk = false;
820 + $dayMsgVarsFormat = '';
821 + foreach ($day as $dayIndex => $dayValue) {
822 + if ($dayIndex > 0) {
823 + $dayMsgVarsFormat .= ', ';
824 + }
825 + $dayMsgVarsFormat .= '%s';
826 + }
827 + $dayNotOkMsg = vsprintf(__("in $dayMsgVarsFormat", 'bit-form'), $day);
828 + }
829 + if (
830 + !empty($day)
831 + && is_array($day)
832 + && (in_array('Custom', $day))
833 + ) {
834 + $startDate = empty($date->from) ? '00-00-0000' : $date->from;
835 + $endDate = empty($date->to) ? '00-00-0000' : $date->to;
836 + $dateFormat = preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $startDate) ? 'Y-m-d' : 'm-d-Y';
837 + if (!empty($date->from) && false !== strpos($startDate, 'T')) {
838 + $startDate = $dateTimeHelper->getDate($startDate, false, null, $dateFormat);
839 + }
840 + if (!empty($date->to) && false !== strpos($endDate, 'T')) {
841 + $endDate = $dateTimeHelper->getDate($endDate, false, null, $dateFormat);
842 + }
843 + $currentDate = $dateTimeHelper->getDate(null, null, null, $dateFormat);
844 + if (!($currentDate >= $startDate && $currentDate <= $endDate)) {
845 + $isdateOk = false;
846 + $dateNotOkMsg = sprintf(__('within %s to %s', 'bit-form'), $startDate, $endDate);
847 + }
848 + }
849 +
850 + if (!empty($time)) {
851 + $startTime = empty($time->from) ? '00:00' : $time->from;
852 + $endTime = empty($time->to) ? '23:59.999' : $time->to;
853 + $currentTime = $dateTimeHelper->getTime(null, null, null, 'H:i');
854 + if (!($currentTime >= $startTime && $currentTime <= $endTime)) {
855 + $istimeOk = false;
856 + $startTime = $dateTimeHelper->getTime($startTime, 'H:i', null);
857 + $endTime = $dateTimeHelper->getTime($endTime, 'H:i', null);
858 + $isTimeOk = false;
859 + $timeNotOkMsg = sprintf(__('%s to %s', 'bit-form'), $startTime, $endTime);
860 + }
861 + }
862 +
863 + if (!($isdateOk && $isdayOk && $istimeOk)) {
864 + $restrict_form_message = null;
865 + if (!$isdayOk) {
866 + $restrict_form_message = !empty($timeNotOkMsg) ? sprintf(__('Form is available %s From %s', 'bit-form'), $dayNotOkMsg, $timeNotOkMsg) :
867 + sprintf(__('Form is available %s', 'bit-form'), $dayNotOkMsg, $timeNotOkMsg);
868 + } elseif (!$isdateOk) {
869 + $restrict_form_message = !empty($timeNotOkMsg) ? sprintf(__('Form is available %s From %s', 'bit-form'), $dateNotOkMsg, $timeNotOkMsg) :
870 + sprintf(__('Form is available %s', 'bit-form'), $dateNotOkMsg, $timeNotOkMsg);
871 + } elseif (!$istimeOk) {
872 + $restrict_form_message = sprintf(__('Form is available on %s', 'bit-form'), $timeNotOkMsg);
873 + }
874 +
875 + if ($restrict_form_message) {
876 + $restrict_form_message = apply_filters(
877 + 'bitform_filter_restrict_form_message',
878 + $restrict_form_message,
879 + $this->form_id
880 + );
881 +
882 + $restrictionMessage[] = $restrict_form_message;
883 + }
884 + }
515 885 }
886 + if ('blocked_ip' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
887 + $isIpBlocked = false;
888 + foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
889 + if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
890 + $isIpBlocked = true;
891 + break;
892 + }
893 + }
894 + if ($isIpBlocked) {
895 + $blocked_ip_message = sprintf(
896 + __('Sorry!! Your IP address is %s, Blocked from submitting the form', 'bit-form'),
897 + $ipAddress
898 + );
516 899
517 - $dtoken = explode('.', base64_decode(base64_decode($token)))[1];
518 - $time = explode('.', base64_decode(base64_decode($token)))[0];
900 + $blocked_ip_message = apply_filters(
901 + 'bitform_filter_restricted_ip_message',
902 + $blocked_ip_message,
903 + $this->form_id
904 + );
519 905
520 - if (time() - $time < 6 || hash_equals($dtoken, wp_hash(wp_get_session_token() . $time)) === false) {
521 - return true;
906 + $restrictionMessage[] = $blocked_ip_message;
907 + }
522 908 }
523 - if (
524 - !empty($_POST[$token . '.name'])
525 - || !empty($_POST[$token . '_name'])
526 - || !empty($_POST[$token . '.email'])
527 - || !empty($_POST[$token . '_email'])
528 - || !empty($_POST[$token . '.message'])
529 - || !empty($_POST[$token . '_message'])
530 - ) {
531 - return true;
909 + if ('private_ip' === $restrictionKey && isset($fromRestrictionSetitings->{$restrictionKey})) {
910 + $isIpWhiteListed = false;
911 + foreach ($fromRestrictionSetitings->{$restrictionKey} as $ipIndex => $ipDetails) {
912 + if (!empty($ipDetails->status) && $ipDetails->status && !empty($ipDetails->ip) && $ipDetails->ip === $ipAddress) {
913 + $isIpWhiteListed = true;
914 + break;
915 + }
916 + }
917 + if (!$isIpWhiteListed) {
918 + $private_ip = sprintf(
919 + __('Sorry!! Your IP address is %s, Blocked from submitting the form', 'bit-form'),
920 + $ipAddress
921 + );
922 +
923 + $private_ip = apply_filters(
924 + 'bitform_filter_private_ip_message',
925 + $private_ip,
926 + $this->form_id
927 + );
928 +
929 + $restrictionMessage[] = $private_ip;
930 + }
532 931 }
533 - unset($_POST['token'], $_POST[$token . 'name'], $_POST[$token . 'email'], $_POST[$token . 'message']);
534 - return false;
932 + }
535 933 }
934 + return $restrictionMessage;
935 + }
536 936
537 - public function isHoneypotActive()
538 - {
539 - $formContents = $this->getFormContent();
540 - $enabled = empty($formContents->additional->enabled) ? null : $formContents->additional->enabled;
541 - if (!empty($enabled->honeypot) && $enabled->honeypot) {
542 - return true;
543 - }
544 - return false;
937 + /**
938 + * Will check if form is submitted by a bot
939 + *
940 + * @return Boolean true - if submitted by bot else false
941 + */
942 + public function isTrappedInHoneypot()
943 + {
944 + $isHoneyPot = false;
945 +
946 + if (!$this->isHoneypotActive()) {
947 + return false;
545 948 }
546 949
547 - public function checkPaymentFields()
548 - {
549 - $formContents = $this->getFormContent();
550 - $fields = $formContents->fields;
950 + $token = $_POST['b_h_t'];
951 + $pattern = '/^([a-zA-Z0-9]*_[a-zA-Z0-9]*){4}$/';
952 + $decryptedToken = base64_decode(base64_decode($token));
551 953
552 - $payments = [];
553 - foreach ($fields as $fldData) {
554 - if ($fldData->typ === 'paypal' && property_exists($fldData, 'payIntegID')) {
555 - $payments['paypalKey'] = $this->getClientKey($fldData->payIntegID, 'clientID');
556 - } else if ($fldData->typ === 'razorpay' && property_exists($fldData->options, 'payIntegID')) {
557 - $payments['razorpayKey'] = $this->getClientKey($fldData->options->payIntegID, 'apiKey');
954 + preg_match($pattern, $decryptedToken, $validToken);
955 +
956 + if ($validToken) {
957 + if (isset($_POST[$token]) && empty($_POST[$token])) {
958 + $isHoneyPot = false;
959 + } else {
960 + $isHoneyPot = true;
961 + }
962 + } else {
963 + $isHoneyPot = true;
964 + }
965 +
966 + if (isset($_POST[$token])) {
967 + unset($_POST[$token]);
968 + }
969 + unset($_POST['b_h_t']);
970 + return $isHoneyPot;
971 + }
972 +
973 + public function isHoneypotActive()
974 + {
975 + $formContents = $this->getFormContent();
976 + $enabled = empty($formContents->additional->enabled) ? null : $formContents->additional->enabled;
977 + if (!empty($enabled->honeypot) && $enabled->honeypot) {
978 + return true;
979 + }
980 + return false;
981 + }
982 +
983 + public function checkPaymentFields()
984 + {
985 + $formContents = $this->getFormContent();
986 + $fields = $formContents->fields;
987 +
988 + $payments = [];
989 + foreach ($fields as $fldData) {
990 + if ('paypal' === $fldData->typ && property_exists($fldData, 'payIntegID')) {
991 + $payments['paypalKey'] = $this->getClientKey($fldData->payIntegID, 'clientID');
992 + } elseif ('razorpay' === $fldData->typ && property_exists($fldData->options, 'payIntegID')) {
993 + $payments['razorpayKey'] = $this->getClientKey($fldData->options->payIntegID, 'apiKey');
994 + }
995 + }
996 +
997 + return $payments;
998 + }
999 +
1000 + private function getClientKey($integID, $keyName)
1001 + {
1002 + $client = '';
1003 + if (!empty($integID)) {
1004 + $integrationHandler = new IntegrationHandler(0);
1005 + $integration = $integrationHandler->getAIntegration($integID, 'app', 'payments');
1006 + if (!is_wp_error($integration)) {
1007 + $integration_details = json_decode($integration[0]->integration_details);
1008 + $client = base64_encode($integration_details->{$keyName});
1009 + }
1010 + }
1011 + return $client;
1012 + }
1013 +
1014 + public function getSuccessMessageMarkups()
1015 + {
1016 + if (is_null($this->_work_flows)) {
1017 + $workFlowManager = new WorkFlowHandler($this->form_id);
1018 + $this->_work_flows = $workFlowManager->getAllworkFlow();
1019 + }
1020 +
1021 + $ids = [];
1022 + foreach ($this->_work_flows as $msgItem) {
1023 + foreach ($msgItem['conditions'] as $condition) {
1024 + if (isset($condition->actions->success)) {
1025 + foreach ($condition->actions->success as $msg) {
1026 + if ('successMsg' === $msg->type && isset($msg->details->id)) {
1027 + $idObj = json_decode(stripslashes($msg->details->id));
1028 + if (is_object($idObj) && !empty($idObj->id)) {
1029 + array_push($ids, $idObj->id);
1030 + }
558 1031 }
1032 + }
559 1033 }
1034 + if (isset($condition->actions->failure)) {
1035 + $idObj = json_decode(stripslashes($condition->actions->failure));
1036 + if (is_object($idObj) && !empty($idObj->id)) {
1037 + array_push($ids, $idObj->id);
1038 + }
1039 + }
1040 + }
1041 + }
1042 + $ids = array_unique($ids);
1043 + if (is_null($this->_conf_messages)) {
1044 + $successMsgHandler = new SuccessMessageHandler($this->form_id);
1045 + $this->_conf_messages = $successMsgHandler->getMessages($ids);
1046 + }
560 1047
561 - return $payments;
1048 + $messageMarkups = '';
1049 + if (is_wp_error($this->_conf_messages)) {
1050 + return $messageMarkups;
562 1051 }
563 1052
564 - private function getClientKey($integID, $keyName)
565 - {
566 - $client = '';
567 - if (!empty($integID)) {
568 - $integrationHandler = new IntegrationHandler(0);
569 - $integration = $integrationHandler->getAIntegration($integID, 'app', 'payments');
570 - if (!is_wp_error($integration)) {
571 - $integration_details = json_decode($integration[0]->integration_details);
572 - $client = base64_encode($integration_details->{$keyName});
573 - }
574 - }
575 - return $client;
1053 + foreach ($this->_conf_messages as $msgItem) {
1054 + $messageMarkups .= $this->messageMarkup($msgItem);
576 1055 }
1056 +
1057 + return $messageMarkups;
1058 + }
1059 +
1060 + public function getFormAbandonmentMessage()
1061 + {
1062 + if (class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
1063 + $formAbandonmentSettings = FormAbandonment::getFormAbandonmentSettings($this->form_id);
1064 + $msg = '';
1065 + if (isset($formAbandonmentSettings->showWarningMsg) && $formAbandonmentSettings->showWarningMsg && !empty($formAbandonmentSettings->warningMsg)) {
1066 + $msg = $formAbandonmentSettings->warningMsg;
1067 + $msg = '<div class="bf-form-msg active warning">' . wp_kses_post($msg) . '</div>';
1068 + }
1069 + return $msg;
1070 + }
1071 + }
1072 +
1073 + public function getFormAbandonmentSettings()
1074 + {
1075 + if (class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
1076 + $formAbandonmentSettings = FormAbandonment::getFormAbandonmentSettings($this->form_id);
1077 + return $formAbandonmentSettings;
1078 + }
1079 + return null;
1080 + }
1081 +
1082 + private function messageMarkup($msg)
1083 + {
1084 + $msgId = $msg->id;
1085 + $msgConfig = json_decode($msg->message_config);
1086 + $scrollClass = 'below' === $msgConfig->msgType ? 'scroll' : '';
1087 +
1088 + return <<<SUCCESSMSG
1089 + <div role="dialog" aria-hidden="true" data-modal-backdrop="true" class="{$this->getAtomicCls("msg-container-{$msgId}")} deactive {$scrollClass}">
1090 + <div data-contentid="{$this->getFormIdentifier()}" data-msgid="{$msgId}" role="button" class="{$this->getAtomicCls("msg-background-{$msgId}")} msg-backdrop">
1091 + <div class="bf-msg-content {$this->getAtomicCls("msg-content-{$msgId}")}">
1092 + <button data-contentid="{$this->getFormIdentifier()}" data-msgid="{$msgId}" class="{$this->getAtomicCls("close-{$msgId}")} bf-msg-close" type="button">
1093 + <svg class="{$this->getAtomicCls("close-icn-{$msgId}")}" viewBox="0 0 30 30">
1094 + <line fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" x1="4" y1="3.88" x2="26" y2="26.12"></line>
1095 + <line fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" x1="26" y1="3.88" x2="4" y2="26.12"></line>
1096 + </svg>
1097 + </button>
1098 + <div class="msg-content"></div>
1099 + </div>
1100 + </div>
1101 + </div>
1102 +SUCCESSMSG;
1103 + }
577 1104 }