PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.15.3
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.15.3
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
← All changes | includes/Admin/Form/Helpers.php +56 -524 3.1.12.15.3 View file →
@@ -3,21 +3,17 @@
3 3 namespace BitCode\BitForm\Admin\Form;
4 4
5 5 use BitCode\BitForm\Core\Cryptography\Cryptography;
6 6 use BitCode\BitForm\Core\Database\FormEntryModel;
7 -use BitCode\BitForm\Core\Util\FileHandler;
8 7 use BitCode\BitForm\Core\Util\Log;
9 8 use Exception;
10 -use WP_Error;
11 9
12 10 class Helpers
13 11 {
14 - private static $encryptEntryIds = [];
15 12
16 13 public static $file_upload_types = ['file-up', 'advanced-file-up'];
17 14
18 15 public static $repeated_array_type_data_fields = ['check', 'image-select'];
19 -
20 16 public static function filterNullEntries($entries)
21 17 {
22 18 $filteredEntries = [];
23 19 foreach ($entries as $entry) {
@@ -37,50 +33,39 @@
37 33 {
38 34 $attributes = wp_json_encode($attrs);
39 35 $instObj = '';
40 36 if ($instanceObj) {
41 - $instObj .= sprintf(
42 - '
43 - script.onload = function () {
44 - bfSelect("#{%1$s}").querySelectorAll("{%2$s}").forEach(function(fld){
45 - %3$s;
46 - });
47 - }
48 - ',
49 - $contentId,
50 - $selector,
51 - $instanceObj
52 - );
37 + $instObj .= <<<INST
38 +script.onload = function () {
39 + bfSelect('#{$contentId}').querySelectorAll('{$selector}').forEach(function(fld){
40 + $instanceObj;
41 + });
42 +}
43 +INST;
53 44 }
54 - return sprintf(
55 - '
56 - var script = document.createElement("script"), integrity = "%1$s", attrs = %2$s, id = "%3$s";
57 - script.src = "%4$s";
58 - script.id = id;
59 - if(integrity){
60 - script.integrity = integrity;
61 - script.crossOrigin = "anonymous";
62 - }
63 - if(attrs){
64 - Object.entries(attrs).forEach(function([key, val]){
65 - script.setAttribute(key,val);
66 - })
67 - }
68 - $instObj;
69 - var bodyElm = document.body;
70 - var alreadyExistScriptElm = bodyElm ? bodyElm.querySelector("script#$id"):null;
71 - if(alreadyExistScriptElm){
72 - bodyElm.removeChild(alreadyExistScriptElm)
73 - }
74 - if(!(window.recaptcha && id === "g-recaptcha-script")){
75 - bodyElm.appendChild(script);
76 - }
77 - ',
78 - $integrity,
79 - $attributes,
80 - $id,
81 - $src,
82 - );
45 + return <<<LOAD_SECRIPT
46 +var script = document.createElement('script'), integrity = '$integrity', attrs = $attributes, id = '$id';
47 +script.src = '$src';
48 +script.id = id;
49 +if(integrity){
50 + script.integrity = integrity;
51 + script.crossOrigin = 'anonymous';
52 +}
53 +if(attrs){
54 + Object.entries(attrs).forEach(function([key, val]){
55 + script.setAttribute(key,val);
56 + })
57 +}
58 +$instObj;
59 +var bodyElm = document.body;
60 +var alreadyExistScriptElm = bodyElm ? bodyElm.querySelector('script#$id'):null;
61 +if(alreadyExistScriptElm){
62 + bodyElm.removeChild(alreadyExistScriptElm)
63 +}
64 +if(!(window.recaptcha && id === 'g-recaptcha-script')){
65 + bodyElm.appendChild(script);
66 +}
67 +LOAD_SECRIPT;
83 68 }
84 69
85 70 public static function minifyJs($input)
86 71 {
@@ -98,79 +83,8 @@
98 83 $input
99 84 );
100 85 }
101 86
102 - public static function removeJsSingleLineComments($code)
103 - {
104 - $length = strlen($code);
105 - $result = '';
106 - $inString = false;
107 - $inTemplate = false;
108 - $inRegex = false;
109 - $escapeNext = false;
110 - $stringDelimiter = '';
111 - $i = 0;
112 -
113 - while ($i < $length) {
114 - $char = $code[$i];
115 - $nextChar = $i + 1 < $length ? $code[$i + 1] : '';
116 -
117 - if ($escapeNext) {
118 - $result .= $char;
119 - $escapeNext = false;
120 - } elseif ($inString) {
121 - $result .= $char;
122 - if ('\\' === $char) {
123 - $escapeNext = true;
124 - } elseif ($char === $stringDelimiter) {
125 - $inString = false;
126 - }
127 - } elseif ($inTemplate) {
128 - $result .= $char;
129 - if ('\\' === $char) {
130 - $escapeNext = true;
131 - } elseif ('`' === $char) {
132 - $inTemplate = false;
133 - }
134 - } elseif ($inRegex) {
135 - $result .= $char;
136 - if ('\\' === $char) {
137 - $escapeNext = true;
138 - } elseif ('/' === $char) {
139 - $inRegex = false;
140 - }
141 - } else {
142 - if ('"' === $char || "'" === $char) {
143 - $inString = true;
144 - $stringDelimiter = $char;
145 - $result .= $char;
146 - } elseif ('`' === $char) {
147 - $inTemplate = true;
148 - $result .= $char;
149 - } elseif ('/' === $char) {
150 - if ('/' === $nextChar) {
151 - // Single-line comment found
152 - while ($i < $length && "\n" !== $code[$i]) {
153 - $i++;
154 - }
155 - continue; // skip until newline
156 - } elseif ('*' === $nextChar) {
157 - // Block comment start, just copy it (optional, depending on need)
158 - $result .= $char;
159 - } else {
160 - // Assume division or regex
161 - $result .= $char;
162 - }
163 - } else {
164 - $result .= $char;
165 - }
166 - }
167 - $i++;
168 - }
169 -
170 - return $result;
171 - }
172 -
173 87 /**
174 88 * @method name : saveFile
175 89 * @description : save js/css field to disk
176 90 * @param : $path => like(dirName/css), $fileName => main.css, $script
@@ -184,20 +98,22 @@
184 98 $pathArr = explode('/', $path); // like "fieldname/user => [Fieldname, user]
185 99 foreach ($pathArr as $d) {
186 100 $rootDir .= $d . DIRECTORY_SEPARATOR;
187 101 if (!realpath($rootDir)) {
188 - wp_mkdir_p($rootDir);
102 + mkdir($rootDir);
189 103 }
190 104 }
191 105 $fullPath = $rootDir . $fileName;
192 - if ('a' === $fileOpenMode) {
193 - $result = FileHandler::appendFile($fullPath, $script);
194 - } else {
195 - $result = FileHandler::writeFile($fullPath, $script);
106 + $file = fopen($fullPath, $fileOpenMode);
107 + if (false === $file) {
108 + throw new Exception("Failed to open file: $fullPath");
196 109 }
197 - if (false === $result) {
110 + if (false === fwrite($file, $script)) {
198 111 throw new Exception("Failed to write to file: $fullPath");
199 112 }
113 + if (false === fclose($file)) {
114 + throw new Exception("Failed to close file: $fullPath");
115 + }
200 116 return true;
201 117 } catch (\Exception $e) {
202 118 Log::debug_log($e->getMessage());
203 119 return false;
@@ -222,9 +138,15 @@
222 138 }
223 139
224 140 public static function fileRead($filePath)
225 141 {
226 - return FileHandler::readFile($filePath);
142 + $fileContent = '';
143 + if (file_exists($filePath)) {
144 + $file = fopen($filePath, 'r');
145 + $fileContent .= fread($file, filesize($filePath));
146 + fclose($file);
147 + }
148 + return $fileContent;
227 149 }
228 150
229 151 public static function getDataFromNestedPath($data, $key)
230 152 {
@@ -271,8 +193,9 @@
271 193 }
272 194 $data = $data->$k;
273 195 }
274 196 $data->$lastKey = json_decode(wp_json_encode($value));
197 + ;
275 198 return $data;
276 199 }
277 200
278 201 public static function property_exists_nested($obj, $path = '', $valToCheck = null, $checkNegativeVal = 0)
@@ -320,9 +243,9 @@
320 243 }
321 244 }
322 245 // check if the entry token is valid
323 246 if (isset($entryToken) && $entryToken) {
324 - $decryptEntryId = Cryptography::decrypt($entryToken, self::getBitformSalt());
247 + $decryptEntryId = Cryptography::decrypt($entryToken, AUTH_SALT);
325 248 if ($decryptEntryId === $entryId) {
326 249 return true;
327 250 }
328 251 }
@@ -329,139 +252,20 @@
329 252
330 253 return false;
331 254 }
332 255
333 - /**
334 - * Validate workflow trigger token with proper input sanitization
335 - *
336 - * @param object $request The AJAX request object
337 - * @param string $formID The form ID (already sanitized)
338 - * @return array ['valid' => bool, 'error' => string, 'triggerData' => object|null, 'isAdminBypass' => bool]
339 - */
340 - public static function validateWorkflowTriggerToken($request, $formID)
256 + public static function validateEormEntryEditPermission($formId, $entryId)
341 257 {
342 - // Sanitize and validate cronNotOk array
343 - if (!isset($request->cronNotOk) || !is_array($request->cronNotOk)) {
344 - return [
345 - 'valid' => false,
346 - 'error' => 'Missing or invalid cronNotOk data',
347 - 'triggerData' => null,
348 - 'isAdminBypass' => false
349 - ];
350 - }
351 -
352 - // Validate and sanitize entry ID and log ID (must be integers)
353 - if (!isset($request->cronNotOk[0]) || !is_numeric($request->cronNotOk[0])) {
354 - Log::debug_log('Invalid entry ID in cronNotOk[0]');
355 - return ['valid' => false, 'error' => 'Invalid entry ID', 'triggerData' => null, 'isAdminBypass' => false];
356 - }
357 -
358 - if (!isset($request->cronNotOk[1]) || !is_numeric($request->cronNotOk[1])) {
359 - Log::debug_log('Invalid log ID in cronNotOk[1]');
360 - return ['valid' => false, 'error' => 'Invalid log ID', 'triggerData' => null, 'isAdminBypass' => false];
361 - }
362 -
363 - $entryID = absint($request->cronNotOk[0]);
364 - $logID = absint($request->cronNotOk[1]);
365 -
366 - // Check for administrator bypass
367 - $isAdminBypass = false;
368 258 if (is_user_logged_in()) {
369 - $user = wp_get_current_user();
370 - if (in_array('administrator', $user->roles) || current_user_can('manage_bitform')) {
371 - Log::debug_log('Admin bypass: Workflow triggered by ' . $user->user_login . ' for entryID=' . $entryID);
372 - return [
373 - 'valid' => true,
374 - 'error' => '',
375 - 'triggerData' => null,
376 - 'isAdminBypass' => true
377 - ];
259 + if(current_user_can('prevent_bitform_entry_edit')){
260 + return false;
378 261 }
379 262
380 - // For logged-in non-admin users: verify nonce
381 - if (isset($request->token, $request->id)) {
382 - if (!wp_verify_nonce($request->token, $request->id)) {
383 - Log::debug_log('Nonce verification failed for logged-in user. FormID=' . $formID);
384 - return [
385 - 'valid' => false,
386 - 'error' => 'Invalid nonce for logged-in user',
387 - 'triggerData' => null,
388 - 'isAdminBypass' => false
389 - ];
390 - }
391 - } else {
392 - Log::debug_log('Missing nonce for logged-in user. FormID=' . $formID);
393 - return [
394 - 'valid' => false,
395 - 'error' => 'Missing nonce',
396 - 'triggerData' => null,
397 - 'isAdminBypass' => false
398 - ];
263 + if(current_user_can('manage_bitform')||current_user_can('bitform_entry_edit') || current_user_can('edit_post')){
264 + return true;
399 265 }
400 - }
401 266
402 - // For non-admin users (both logged-in and anonymous): validate one-time trigger token
403 - if (!isset($request->cronNotOk[3]) || empty($request->cronNotOk[3])) {
404 - Log::debug_log('Missing trigger token for formID=' . $formID . ', entryID=' . $entryID);
405 - return [
406 - 'valid' => false,
407 - 'error' => 'Missing trigger token',
408 - 'triggerData' => null,
409 - 'isAdminBypass' => false
410 - ];
411 267 }
412 -
413 - $submittedToken = sanitize_text_field($request->cronNotOk[3]);
414 -
415 - // Validate trigger token from transient
416 - $transientData = get_transient("bitform_trigger_transient_{$entryID}");
417 -
418 - if (empty($transientData)) {
419 - Log::debug_log('Trigger token transient missing for entryID=' . $entryID . ', logID=' . $logID);
420 - return [
421 - 'valid' => false,
422 - 'error' => 'Trigger token expired or missing',
423 - 'triggerData' => null,
424 - 'isAdminBypass' => false
425 - ];
426 - }
427 -
428 - $triggerData = is_string($transientData) ? json_decode($transientData) : $transientData;
429 - // Verify token matches and belongs to this entry/log
430 - if (
431 - !isset($triggerData['trigger_token'])
432 - || !hash_equals($triggerData['trigger_token'], $submittedToken)
433 - || (int)$triggerData['entryID'] !== $entryID
434 - || (int)$triggerData['logID'] !== $logID
435 - ) {
436 - Log::debug_log('Invalid trigger token for entryID=' . $entryID . ', logID=' . $logID);
437 - return [
438 - 'valid' => false,
439 - 'error' => 'Invalid trigger token',
440 - 'triggerData' => null,
441 - 'isAdminBypass' => false
442 - ];
443 - }
444 -
445 - // Token is valid - delete transient to prevent reuse (single-use token)
446 - delete_transient("bitform_trigger_transient_{$entryID}");
447 - Log::debug_log('Valid trigger token consumed for entryID=' . $entryID);
448 -
449 - return [
450 - 'valid' => true,
451 - 'error' => '',
452 - 'triggerData' => $triggerData,
453 - 'isAdminBypass' => false
454 - ];
455 - }
456 -
457 - public static function validateFormEntryEditPermission($formId, $entryId)
458 - {
459 - if (is_user_logged_in()) {
460 - if (current_user_can('manage_bitform') || current_user_can('bitform_entry_edit') || current_user_can('edit_post')) {
461 - return true;
462 - }
463 - }
464 268 return false;
465 269 }
466 270
467 271 public static function honeypotEncryptedToken($str)
@@ -471,14 +275,14 @@
471 275 }
472 276
473 277 public static function csrfEecrypted()
474 278 {
475 - $secretKey = get_option('bitform_csrf_secret');
279 + $secretKey = get_option('bf_csrf_secret');
476 280 if (!$secretKey) {
477 281 $secretKey = 'bf-' . time();
478 - update_option('bitform_csrf_secret', $secretKey);
282 + update_option('bf_csrf_secret', $secretKey);
479 283 }
480 - $tIdenty = base64_encode(\random_bytes(32));
284 + $tIdenty = base64_encode(random_bytes(32));
481 285 $csrf = \base64_encode(\hash_hmac('sha256', $tIdenty, $secretKey, true));
482 286 return ['csrf' => $csrf, 't_identity' => $tIdenty];
483 287 }
484 288
@@ -483,9 +287,9 @@
483 287 }
484 288
485 289 public static function csrfDecrypted($identy, $token)
486 290 {
487 - $secretKey = get_option('bitform_csrf_secret');
291 + $secretKey = get_option('bf_csrf_secret');
488 292 return \hash_equals(
489 293 \base64_encode(\hash_hmac('sha256', $identy, $secretKey, true)),
490 294 $token
491 295 );
@@ -497,278 +301,6 @@
497 301 $intArray = array_map('intval', $filteredArray);
498 302 $result = count($arr) === count($intArray);
499 303
500 304 return $result;
501 - }
502 -
503 - public static function getTruncatedEncryptToken($str, $length = 20)
504 - {
505 - $token = hash_hmac('sha256', $str, self::getBitformSalt());
506 - return substr($token, 0, $length);
507 - }
508 -
509 - public static function getAuthSaltEncryptToken($str, $length = 20)
510 - {
511 - if (!$str) {
512 - return '';
513 - }
514 - if (!defined('AUTH_SALT')) {
515 - return '';
516 - }
517 -
518 - return substr(hash_hmac('sha256', $str, AUTH_SALT), 0, $length);
519 - }
520 -
521 - public static function getEncryptedEntryId($entryId)
522 - {
523 - if (!isset(self::$encryptEntryIds[$entryId])) {
524 - self::$encryptEntryIds[$entryId] = self::getTruncatedEncryptToken($entryId);
525 - }
526 - return self::$encryptEntryIds[$entryId];
527 - }
528 -
529 - public static function getFullPathWithEncryptedEntryId($formId, $entryId)
530 - {
531 - $uploadDir = rtrim(BITFORMS_UPLOAD_DIR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $formId . DIRECTORY_SEPARATOR;
532 - $encryptDirectoryId = Helpers::getEncryptedEntryId($entryId);
533 - $encryptDirectory = $uploadDir . $encryptDirectoryId;
534 - if (is_dir($encryptDirectory)) {
535 - return $encryptDirectory;
536 - }
537 -
538 - $oldEntriesFileUploadDir = Helpers::getOldEntriesFileUploadDir($uploadDir, $entryId);
539 - if (!empty($oldEntriesFileUploadDir) && is_dir($oldEntriesFileUploadDir)) {
540 - return $oldEntriesFileUploadDir;
541 - }
542 -
543 - return $encryptDirectory;
544 - }
545 -
546 - public static function getWebPathWithEncryptedEntryId($formId, $entryId)
547 - {
548 - $serverFileUploadDir = rtrim(BITFORMS_UPLOAD_DIR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $formId . DIRECTORY_SEPARATOR;
549 - $webFileDirectory = BITFORMS_UPLOAD_BASE_URL . '/' . 'uploads' . '/' . $formId . '/';
550 - $encryptDirectoryId = Helpers::getEncryptedEntryId($entryId);
551 - $encryptDirectory = $serverFileUploadDir . $encryptDirectoryId;
552 - if (is_dir($encryptDirectory)) {
553 - return $webFileDirectory . $encryptDirectoryId;
554 - }
555 -
556 - $authSaltEncryptedEntryId = Helpers::getAuthSaltEncryptToken($entryId);
557 - $authSaltEncryptedDirectory = $serverFileUploadDir . $authSaltEncryptedEntryId;
558 - if (!empty($authSaltEncryptedEntryId) && is_dir($authSaltEncryptedDirectory)) {
559 - return $webFileDirectory . $authSaltEncryptedEntryId;
560 - }
561 - $previousEntryDirectory = $serverFileUploadDir . $entryId;
562 - if (!empty($previousEntryDirectory) && is_dir($previousEntryDirectory)) {
563 - return $webFileDirectory . $entryId;
564 - }
565 -
566 - return $webFileDirectory . $encryptDirectoryId;
567 - }
568 -
569 - public static function getOldEntriesFileUploadDir($uploadDir, $entry_id)
570 - {
571 - $authSaltEncryptedEntryId = Helpers::getAuthSaltEncryptToken($entry_id);
572 - $authSaltEncryptedDirectory = $uploadDir . $authSaltEncryptedEntryId;
573 - if (!empty($authSaltEncryptedEntryId) && is_dir($authSaltEncryptedDirectory)) {
574 - return $authSaltEncryptedDirectory;
575 - }
576 - $previousEntryDirectory = $uploadDir . $entry_id;
577 - if (!empty($previousEntryDirectory) && is_dir($previousEntryDirectory)) {
578 - return $previousEntryDirectory;
579 - }
580 - return '';
581 - }
582 -
583 - public static function PDFPassHash($entryId)
584 - {
585 - return abs(crc32($entryId));
586 - }
587 -
588 - public static function encryptBinaryData($plaintext)
589 - {
590 - $iv = openssl_random_pseudo_bytes(16);
591 - $encrypted = openssl_encrypt($plaintext, 'AES-256-CBC', BITFORMS_SECRET_KEY, OPENSSL_RAW_DATA, $iv);
592 -
593 - return bin2hex($iv . $encrypted);
594 - }
595 -
596 - public static function decryptBinaryData($encryptedHex)
597 - {
598 - $decoded = hex2bin($encryptedHex);
599 - $iv = substr($decoded, 0, 16);
600 - $cipherText = substr($decoded, 16);
601 -
602 - return openssl_decrypt($cipherText, 'AES-256-CBC', BITFORMS_SECRET_KEY, OPENSSL_RAW_DATA, $iv);
603 - }
604 -
605 - /**
606 - * Sanitize user-provided HTML content by removing dangerous JS code
607 - * while allowing all valid HTML/CSS.
608 - *
609 - * @param string $html Raw HTML from user input
610 - * @return string Sanitized safe HTML
611 - */
612 - public static function sanitizeUserHTML(string $html): string
613 - {
614 - // Remove <script> tags entirely
615 - $html = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $html);
616 -
617 - // Remove event handler attributes (like onclick, onload, etc.)
618 - $html = preg_replace_callback('/<[^>]+>/i', function ($matches) {
619 - return preg_replace('/\s*on\w+\s*=\s*"[^"]*"/i', '', $matches[0]); // on*=""
620 - }, $html);
621 -
622 - $html = preg_replace_callback('/<[^>]+>/i', function ($matches) {
623 - return preg_replace("/\s*on\w+\s*=\s*'[^']*'/i", '', $matches[0]); // on*=''
624 - }, $html);
625 -
626 - // Remove javascript: from href or src
627 - $html = preg_replace('/(href|src)\s*=\s*([\'"])\s*javascript:[^\'"]*\2/i', '', $html);
628 -
629 - return $html;
630 - }
631 -
632 - public static function sanitizeUrlParam($param)
633 - {
634 - if (preg_match('/\.\.?\//', $param)) {
635 - return new WP_Error('parameter_error', 'Invalid URL parameter');
636 - }
637 -
638 - $param = htmlspecialchars(trim($param), ENT_QUOTES, 'UTF-8');
639 - return sanitize_text_field($param);
640 - }
641 -
642 - public static function replaceFieldsDefaultErrorMsg($fields)
643 - {
644 - try {
645 - $appSettings = get_option('bitform_app_settings', (object) []);
646 - if (!isset($appSettings->globalMessages) || !isset($appSettings->globalMessages->err)) {
647 - return $fields;
648 - }
649 -
650 - $globalErrMsg = $appSettings->globalMessages->err;
651 - $templateCache = []; // [type_errKey] => compiled template
652 -
653 - foreach ($fields as $fieldKey => $field) {
654 - if (!isset($field->err) || !is_object($field->err)) {
655 - continue;
656 - }
657 -
658 - foreach ($field->err as $errKey => $errObj) {
659 - if (!isset($errObj->dflt)) {
660 - continue;
661 - }
662 -
663 - $cacheKey = $field->typ . '_' . $errKey;
664 - $template = null;
665 -
666 - // 1. Check Cache First
667 - if (isset($templateCache[$cacheKey])) {
668 - $template = $templateCache[$cacheKey];
669 - } else {
670 - // 2. Lookup from globalErrMsg
671 - if (isset($globalErrMsg->{$field->typ}->{$errKey})) {
672 - $template = $globalErrMsg->{$field->typ}->{$errKey};
673 - } elseif (isset($globalErrMsg->{$errKey}) && !is_object($globalErrMsg->{$errKey})) {
674 - $template = $globalErrMsg->{$errKey};
675 - }
676 -
677 - // 3. Cache it
678 - if ($template) {
679 - $templateCache[$cacheKey] = $template;
680 - }
681 - }
682 -
683 - // 4. Apply Template if Found
684 - if ($template) {
685 - $finalMsg = self::replaceShortcodeInErrorMsg($template, $field);
686 - // 5. Sanitize final output
687 - $field->err->{$errKey}->dflt = wp_kses_post($finalMsg);
688 - }
689 - }
690 -
691 - $fields->{$fieldKey} = $field;
692 - }
693 - } catch (Exception $e) {
694 - Log::debug_log('Error In Replacing Fields Default Error messages: ' . $e->getMessage());
695 - }
696 - return $fields;
697 - }
698 -
699 - //replace shortcode in error message
700 - public static function replaceShortcodeInErrorMsg($msg, $field)
701 - {
702 - $shortcodes = [
703 - '${field.label}' => isset($field->lbl) ? $field->lbl : '',
704 - '${field.minimum}' => isset($field->mn) ? $field->mn : '',
705 - '${field.maximum}' => isset($field->mx) ? $field->mx : '',
706 - '${field.minimum_file}' => isset($field->config->minFile) ? $field->config->minFile : '',
707 - '${field.maximum_file}' => isset($field->config->maxFile) ? $field->config->maxFile : '',
708 - '${field.maximum_size}' => isset($field->config->maxSize) ? $field->config->maxSize : '',
709 - '${field.minimum_amount}' => isset($field->config->minValue) ? $field->config->minValue : '',
710 - '${field.maximum_amount}' => isset($field->config->maxValue) ? $field->config->maxValue : '',
711 - ];
712 - $msg = str_replace(array_keys($shortcodes), array_values($shortcodes), $msg);
713 - return $msg;
714 - }
715 -
716 - public static function getDefaultGlobalMessages()
717 - {
718 - $defaultGlobalMessages = [
719 - 'err' => [
720 - 'req' => '<p style="margin:0">' . __('This field is required', 'bit-form') . '</p>',
721 - 'email' => [
722 - 'invalid' => '<p style="margin:0">' . __('Please, enter a valid email address', 'bit-form') . '</p>',
723 - ],
724 - 'url' => [
725 - 'invalid' => '<p style="margin:0">' . __('Please, enter a valid URL', 'bit-form') . '</p>',
726 - ],
727 - 'mn' => '<p style="margin:0">' . __('Minimum ${field.minimum} is required', 'bit-form') . '</p>',
728 - 'mx' => '<p style="margin:0">' . __('Maximum ${field.maximum} is allowed', 'bit-form') . '</p>',
729 - 'number' => [
730 - 'invalid' => '<p style="margin:0">' . __('Please, enter only numbers', 'bit-form') . '</p>',
731 - ],
732 - 'phone-number' => [
733 - 'invalid' => '<p style="margin:0">' . __('Please, enter a valid phone number', 'bit-form') . '</p>',
734 - ],
735 - 'check' => [
736 - 'mn' => '<p style="margin:0">' . __('Select at least ${field.minimum} option(s)', 'bit-form') . '</p>',
737 - 'mx' => '<p style="margin:0">' . __('Please, select no more than ${field.maximum} option(s)', 'bit-form') . '</p>',
738 - ],
739 - 'select' => [
740 - 'mn' => '<p style="margin:0">' . __('Select at least ${field.minimum} option(s)', 'bit-form') . '</p>',
741 - 'mx' => '<p style="margin:0">' . __('Please, select no more than ${field.maximum} option(s)', 'bit-form') . '</p>',
742 - ],
743 - 'image-select' => [
744 - 'mn' => '<p style="margin:0">' . __('Select at least ${field.minimum} option(s)', 'bit-form') . '</p>',
745 - 'mx' => '<p style="margin:0">' . __('Please, select no more than ${field.maximum} option(s)', 'bit-form') . '</p>',
746 - ],
747 - 'inputMask' => '<p style="margin:0">' . __('Input does not match the required pattern', 'bit-form') . '</p>',
748 - 'regexr' => '<p style="margin:0">' . __('Input does not match the required pattern', 'bit-form') . '</p>',
749 - 'minFile' => '<p style="margin:0">' . __('Minimum ${field.minimum_file} file(s) required', 'bit-form') . '</p>',
750 - 'maxFile' => '<p style="margin:0">' . __('Maximum ${field.maximum_file} file(s) allowed', 'bit-form') . '</p>',
751 - 'maxSize' => '<p style="margin:0">' . __('Maximum file size exceeded. (Max: ${field.maximum_size}MB)', 'bit-form') . '</p>',
752 - 'fileType' => '<p style="margin:0">' . __('File type is not supported', 'bit-form') . '</p>',
753 - 'entryUnique' => '<p style="margin:0">' . __('This value is already taken. Please, choose a different one.', 'bit-form') . '</p>',
754 - 'userUnique' => '<p style="margin:0">' . __('This username or email is already registered. Please, use another.', 'bit-form') . '</p>',
755 - 'otherOptReq' => '<p style="margin:0">' . __('Custom Option Required', 'bit-form') . '</p>',
756 - 'minValue' => '<p style="margin:0">' . __('Minimum amount of ${field.minimum_amount} is required', 'bit-form') . '</p>',
757 - 'maxValue' => '<p style="margin:0">' . __('Maximum amount of ${field.maximum_amount} is allowed', 'bit-form') . '</p>',
758 - ],
759 - ];
760 -
761 - // Convert array to object recursively
762 - return json_decode(json_encode($defaultGlobalMessages));
763 - }
764 -
765 - public static function getBitformSalt()
766 - {
767 - $salt = get_option('bitforms_salt');
768 - if (!$salt) {
769 - $salt = bin2hex(\random_bytes(32));
770 - update_option('bitforms_salt', $salt);
771 - }
772 - return $salt;
773 305 }
774 306 }