PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.3.1
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.3.1
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/AdminFormHandler.php +85 -6 3.2.03.3.1 View file →
@@ -524,8 +524,12 @@
524 524 $updated_data['form_content']['is_default'] = 1;
525 525 }
526 526 $updated_data['message'] = __('Form Saved successfully', 'bit-form');
527 527
528 + // Form and dependent rows are persisted; multilingual providers register
529 + // the form's translatable strings here.
530 + do_action('bitform_form_saved', $save_status);
531 +
528 532 return $updated_data;
529 533 }
530 534 }
531 535
@@ -664,9 +668,14 @@
664 668 $templateDetail->id = $savedID;
665 669 unset($templateDetail->clRef);
666 670 }
667 671 } else {
668 - $emailTemplateHandler->updateTemplate($templateDetail);
672 + $updated = $emailTemplateHandler->updateTemplate($templateDetail);
673 + if (is_wp_error($updated) && 'db_error' === $updated->get_error_code()) {
674 + $newData['mailTemplate'] = 2;
675 + } elseif (0 === $newData['mailTemplate']) {
676 + $newData['mailTemplate'] = 1;
677 + }
669 678 }
670 679 }
671 680 }
672 681 // return $formSettings;
@@ -792,8 +801,11 @@
792 801 }
793 802 $form_content = array_merge($form_content, ['workFlowExist' => $workFlowExist]);
794 803 //wrokFlows [end]
795 804 //reports [start] */
805 + // read unconditionally after the reports block; a save without currentReport
806 + // must not trip an undefined-variable warning
807 + $reportIsDefault = null;
796 808 if (!empty($reports)) {
797 809 $reportsModel = new ReportsModel();
798 810 $fieldNames = [];
799 811 foreach ($fields as $key => $field) {
@@ -811,9 +823,13 @@
811 823 $fieldNames['__created_at'] = __('Created Time', 'bit-form');
812 824 $fieldNames['__updated_at'] = __('Modified Time', 'bit-form');
813 825
814 826 $reportIsDefault = null;
815 - if (isset($form_content['report_id'])) {
827 + // The client posts currentReport as {} whenever its report atom has not resolved yet. That
828 + // is an empty stdClass, which empty() above treats as non-empty, so we reach here with
829 + // nothing to save — and writing the validated result would replace the stored report's
830 + // column order, hidden columns, page size and name with an empty list. Leave the row alone.
831 + if (isset($form_content['report_id']) && ReportsModel::isValidatableReport($reports)) {
816 832 $validDateReport = $reportsModel->validateReportFields($reports, $fieldNames);
817 833 if (isset($reports->isDefault)) {
818 834 $reportIsDefault = $reports->isDefault;
819 835 } else {
@@ -924,8 +940,12 @@
924 940 }
925 941 if (2 === $newData['reports']) {
926 942 $errorIN .= empty($errorIN) ? 'reports' : ', reports';
927 943 }
944 + // See createNewForm(). Fired before the partial-failure return: the rows
945 + // that did save are already persisted, so their strings still need registering.
946 + do_action('bitform_form_saved', $formId);
947 +
928 948 if (!empty($errorIN)) {
929 949 /* translators: %s: comma-separated list of areas where error occurred */
930 950 $updated_data['message'] = sprintf(__('Error Occured in saving %s', 'bit-form'), $errorIN);
931 951 return new WP_Error('Form update Error.', $updated_data);
@@ -933,8 +953,9 @@
933 953 if (null !== $reportIsDefault) {
934 954 $updated_data['form_content']['is_default'] = $reportIsDefault;
935 955 }
936 956 $updated_data['message'] = __('Form updated successfully.', 'bit-form');
957 +
937 958 return $updated_data;
938 959 }
939 960 }
940 961
@@ -1112,9 +1133,9 @@
1112 1133 'nestedLayout' => !empty($form_content->nestedLayout) ? $form_content->nestedLayout : (object) [],
1113 1134 'formInfo' => !empty($form_content->formInfo) ? $form_content->formInfo : (object) ['formName' => $formManager->getFormName()],
1114 1135 'fields' => $form_content->fields,
1115 1136 'form_name' => $formManager->getFormName(),
1116 - 'workFlowExist' => $form_content->workFlowExist,
1137 + 'workFlowExist' => isset($form_content->workFlowExist) ? $form_content->workFlowExist : [],
1117 1138 'report_id' => isset($form_content->report_id) ? $form_content->report_id : null
1118 1139 ];
1119 1140 $successMessageHandler
1120 1141 = new SuccessMessageHandler($formID);
@@ -1142,9 +1163,9 @@
1142 1163 'title' => $emailTemplatevalue->title,
1143 1164 'sub' => $emailTemplatevalue->sub,
1144 1165 'body' => $emailTemplatevalue->body,
1145 1166 'status' => isset($emailTemplatevalue->status) ? (int) $emailTemplatevalue->status : 1,
1146 - 'config' => !empty($emailTemplatevalue->config) ? json_decode($emailTemplatevalue->config) : (object) [],
1167 + 'config' => EmailTemplateHandler::normalizeConfig($emailTemplatevalue->config ?? null),
1147 1168 ];
1148 1169 }
1149 1170 }
1150 1171 // get all pdf template
@@ -1410,9 +1431,9 @@
1410 1431 $form_content_arr = [
1411 1432 'layout' => $form_content->layout,
1412 1433 'fields' => $form_content->fields,
1413 1434 'form_name' => $formManager->getFormName(),
1414 - 'workFlowExist' => $form_content->workFlowExist,
1435 + 'workFlowExist' => isset($form_content->workFlowExist) ? $form_content->workFlowExist : [],
1415 1436 'report_id' => isset($form_content->report_id) ? $form_content->report_id : null
1416 1437 ];
1417 1438 $successMessageHandler
1418 1439 = new SuccessMessageHandler($formID);
@@ -1439,9 +1460,9 @@
1439 1460 'title' => $emailTemplatevalue->title,
1440 1461 'sub' => $emailTemplatevalue->sub,
1441 1462 'body' => $emailTemplatevalue->body,
1442 1463 'status' => isset($emailTemplatevalue->status) ? (int) $emailTemplatevalue->status : 1,
1443 - 'config' => !empty($emailTemplatevalue->config) ? json_decode($emailTemplatevalue->config) : (object) [],
1464 + 'config' => EmailTemplateHandler::normalizeConfig($emailTemplatevalue->config ?? null),
1444 1465 ];
1445 1466 }
1446 1467 }
1447 1468 $integrationHandler = new IntegrationHandler($formID);
@@ -2019,8 +2040,65 @@
2019 2040 $response['fieldDetails'] = $labels;
2020 2041 return $response;
2021 2042 }
2022 2043
2044 + /**
2045 + * Sanitize a request-supplied entry query condition before it reaches the Model
2046 + * layer. Only known entry-table columns are allowed as condition keys, operators
2047 + * are restricted to a safe allow-list ['form_id' => $id] when nothing valid remains.
2048 + *
2049 + * @param mixed $queryCondition
2050 + * @param int $id
2051 + * @return array
2052 + */
2053 + private function sanitizeEntryQueryCondition($queryCondition, $id)
2054 + {
2055 + $allowedColumns = [
2056 + 'id', 'form_id', 'status', 'created_at', 'updated_at',
2057 + 'user_id', 'user_ip', 'user_device', 'user_location', 'referer',
2058 + ];
2059 + $allowedOperators = ['=', '!=', '<>', '<', '>', '<=', '>=', 'LIKE', 'IN'];
2060 +
2061 + if (!is_array($queryCondition)) {
2062 + return ['form_id' => $id];
2063 + }
2064 +
2065 + $safe = [];
2066 + foreach ($queryCondition as $key => $value) {
2067 + if (!in_array($key, $allowedColumns, true)) {
2068 + continue;
2069 + }
2070 +
2071 + if (is_array($value)) {
2072 + // Never honour a request-supplied raw SQL fragment.
2073 + unset($value['raw']);
2074 +
2075 + if (array_key_exists('operator', $value) || array_key_exists('value', $value)) {
2076 + $operator = isset($value['operator']) && is_string($value['operator'])
2077 + ? strtoupper(trim($value['operator']))
2078 + : '=';
2079 + if (!in_array($operator, $allowedOperators, true)) {
2080 + $operator = '=';
2081 + }
2082 + $condValue = isset($value['value']) ? $value['value'] : '';
2083 + if (is_scalar($condValue)) {
2084 + $safe[$key] = ['operator' => $operator, 'value' => $condValue];
2085 + }
2086 + } else {
2087 + // IN-style list: keep scalar members only (bound by the Model).
2088 + $list = array_values(array_filter($value, 'is_scalar'));
2089 + if (!empty($list)) {
2090 + $safe[$key] = $list;
2091 + }
2092 + }
2093 + } elseif (is_scalar($value)) {
2094 + $safe[$key] = $value;
2095 + }
2096 + }
2097 +
2098 + return empty($safe) ? ['form_id' => $id] : $safe;
2099 + }
2100 +
2023 2101 public function getFormEntry($Request, $post)
2024 2102 {
2025 2103 if (!empty($Request['id'])) {
2026 2104 $id = absint(wp_unslash($Request['id']));
@@ -2040,8 +2118,9 @@
2040 2118 $pageSize = isset($post->pageSize) ?
2041 2119 wp_unslash($post->pageSize) : 10;
2042 2120 $queryCondition = isset($post->queryCondition) ? wp_unslash($post->queryCondition) : ['form_id' => $id];
2043 2121 }
2122 + $queryCondition = $this->sanitizeEntryQueryCondition($queryCondition, $id);
2044 2123 if (is_null($id)) {
2045 2124 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
2046 2125 }
2047 2126 $formManager = new AdminFormManager($id);