PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.3
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.3
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Form / Updater.php

Updater.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.3, at app/Services/Form/Updater.php

430 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\Form;
4
5 use Exception;
6 use FluentForm\App\Helpers\Helper;
7 use FluentForm\App\Models\Form;
8 use FluentForm\App\Models\FormMeta;
9 use FluentForm\App\Services\FormBuilder\RatingIcon;
10 use FluentForm\Framework\Support\Arr;
11 use FluentForm\App\Modules\Form\FormFieldsParser;
12
13 class Updater
14 {
15 public function update($attributes = [])
16 {
17 $formId = (int)Arr::get($attributes, 'form_id');
18 $formFields = Arr::get($attributes, 'formFields');
19 $status = sanitize_text_field(Arr::get($attributes, 'status', 'published'));
20 $title = sanitize_text_field(Arr::get($attributes, 'title'));
21
22 $this->validate([
23 'title' => $title,
24 'formFields' => $formFields,
25 ]);
26
27 try {
28 $form = Form::findOrFail($formId);
29 } catch (Exception $e) {
30 throw new \Exception("The form couldn't be found.");
31 }
32
33 $data = [
34 'title' => $title,
35 'status' => $status,
36 'updated_at' => current_time('mysql'),
37 ];
38
39 if ($formFields) {
40 $formFields = apply_filters_deprecated(
41 'fluentform_form_fields_update',
42 [
43 $formFields,
44 $formId
45 ],
46 FLUENTFORM_FRAMEWORK_UPGRADE,
47 'fluentform/form_fields_update',
48 'Use fluentform/form_fields_update instead of fluentform_form_fields_update.'
49 );
50 $formFields = apply_filters('fluentform/form_fields_update', $formFields, $formId);
51 $formFields = $this->sanitizeFields($formFields);
52 $data['form_fields'] = $formFields;
53 /**
54 * Fires before a Form is updated.
55 * @since 5.2.1
56 */
57 do_action('fluentform/before_updating_form', $form, $data);
58
59 $form->fill($data);
60
61 if (FormFieldsParser::hasPaymentFields($form)) {
62 $data['has_payment'] = 1;
63 } elseif ($form->has_payment) {
64 $data['has_payment'] = 0;
65 }
66
67 $this->updatePrimaryEmail($form);
68
69 }
70
71 $form->fill($data)->save();
72
73 return $form;
74 }
75
76 private function validate($attributes)
77 {
78 if ($attributes['formFields']) {
79 $duplicates = Helper::getDuplicateFieldNames($attributes['formFields']);
80
81 if ($duplicates) {
82 $duplicateString = implode(', ', $duplicates);
83
84 throw new Exception(
85 sprintf('Name attribute %s has duplicate value.', esc_html($duplicateString))
86 );
87 }
88
89 $duplicateRankingFields = Helper::getRankingFieldsWithDuplicateOptionValues($attributes['formFields']);
90
91 if ($duplicateRankingFields) {
92 $duplicateRankingFields = implode(', ', array_unique($duplicateRankingFields));
93
94 throw new Exception(
95 sprintf(
96 __('Ranking field %s has duplicate option values. Please make each option value unique.', 'fluentform'),
97 esc_html($duplicateRankingFields)
98 )
99 );
100 }
101 }
102
103 if (!$attributes['title']) {
104 throw new Exception('The title field is required.');
105 }
106 }
107
108 private function sanitizeFields($formFields)
109 {
110 if (fluentformCanUnfilteredHTML()) {
111 return $formFields;
112 }
113
114 $fieldsArray = json_decode($formFields, true);
115
116 if (isset($fieldsArray['submitButton'])) {
117 $fieldsArray['submitButton']['settings']['button_ui']['text'] = fluentform_sanitize_html(
118 $fieldsArray['submitButton']['settings']['button_ui']['text']
119 );
120
121 if (!empty($fieldsArray['submitButton']['settings']['button_ui']['img_url'])) {
122 $fieldsArray['submitButton']['settings']['button_ui']['img_url'] = sanitize_url(
123 $fieldsArray['submitButton']['settings']['button_ui']['img_url']
124 );
125 }
126 }
127 $fieldsArray['fields'] = $this->sanitizeFieldMaps($fieldsArray['fields']);
128 $fieldsArray['fields'] = $this->sanitizeCustomSubmit($fieldsArray['fields']);
129 if ($stepsWrapper = Arr::get($fieldsArray, 'stepsWrapper')) {
130 $fieldsArray['stepsWrapper'] = $this->sanitizeStepsWrapper($stepsWrapper);
131 }
132
133 return json_encode($fieldsArray);
134 }
135
136 private function sanitizeFieldMaps($fields)
137 {
138 if (!is_array($fields)) {
139 return $fields;
140 }
141
142 $attributesMap = [
143 'name' => 'sanitize_key',
144 'value' => 'sanitize_textarea_field',
145 'id' => 'sanitize_key',
146 'class' => 'sanitize_text_field',
147 'placeholder' => 'sanitize_text_field',
148 ];
149
150 $attributesKeys = array_keys($attributesMap);
151
152 $settingsMap = [
153 'container_class' => 'sanitize_text_field',
154 'label' => 'fluentform_sanitize_html',
155 'tnc_html' => 'fluentform_sanitize_html',
156 'label_placement' => 'sanitize_text_field',
157 'help_message' => 'wp_kses_post',
158 'admin_field_label' => 'sanitize_text_field',
159 'prefix_label' => 'sanitize_text_field',
160 'suffix_label' => 'sanitize_text_field',
161 'icon_source' => 'sanitize_key',
162 'icon_type' => 'sanitize_key',
163 'custom_icon_svg' => [RatingIcon::class, 'sanitizeCustomSvg'],
164 'inactive_color' => [RatingIcon::class, 'sanitizeColor'],
165 'active_color' => [RatingIcon::class, 'sanitizeColor'],
166 'unique_validation_message' => 'sanitize_text_field',
167 'advanced_options' => 'fluentform_options_sanitize',
168 'html_codes' => 'fluentform_sanitize_html',
169 'description' => 'fluentform_sanitize_html',
170 'grid_columns' => [Helper::class, 'sanitizeArrayKeysAndValues'],
171 'grid_rows' => [Helper::class, 'sanitizeArrayKeysAndValues'],
172 'enable_crop' => 'sanitize_text_field',
173 'crop_mode' => 'sanitize_text_field',
174 'crop_ratio' => 'sanitize_text_field',
175 'crop_width' => 'absint',
176 'crop_height' => 'absint',
177 'enforce_image_dimensions' => 'sanitize_text_field',
178 ];
179
180
181 $settingsKeys = array_keys($settingsMap);
182
183 $stylePrefMap = [
184 'layout' => 'sanitize_key',
185 'media' => 'sanitize_url',
186 'alt_text' => 'sanitize_text_field',
187 ];
188 $stylePrefKeys = array_keys($stylePrefMap);
189
190 foreach ($fields as $fieldIndex => &$field) {
191 $element = Arr::get($field, 'element');
192
193 if ('container' == $element) {
194 $columns = $field['columns'];
195 foreach ($columns as $columnIndex => $column) {
196 $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeFieldMaps($column['fields']);
197 }
198 continue;
199 }
200
201 if ('welcome_screen' == $element) {
202 if ($value = Arr::get($field, 'settings.button_ui.text')) {
203 $field['settings']['button_ui']['text'] = fluentform_sanitize_html($value);
204 }
205 }
206
207 if ('form_step' == $element) {
208 foreach (['next_btn', 'prev_btn'] as $buttonKey) {
209 $buttonSettings = Arr::get($field, 'settings.' . $buttonKey);
210 if (!is_array($buttonSettings)) {
211 continue;
212 }
213
214 if (isset($buttonSettings['type'])) {
215 $field['settings'][$buttonKey]['type'] = sanitize_text_field($buttonSettings['type']);
216 }
217
218 if (isset($buttonSettings['text'])) {
219 $field['settings'][$buttonKey]['text'] = fluentform_sanitize_html($buttonSettings['text']);
220 }
221
222 if (isset($buttonSettings['img_url'])) {
223 $field['settings'][$buttonKey]['img_url'] = esc_url_raw($buttonSettings['img_url']);
224 }
225
226 if (isset($buttonSettings['img_alt'])) {
227 $field['settings'][$buttonKey]['img_alt'] = sanitize_text_field($buttonSettings['img_alt']);
228 }
229 }
230 }
231
232 if ('save_progress_button' == $element) {
233 $buttonUi = Arr::get($field, 'settings.button_ui');
234 if (is_array($buttonUi)) {
235 if (isset($buttonUi['type'])) {
236 $field['settings']['button_ui']['type'] = sanitize_text_field($buttonUi['type']);
237 }
238
239 if (isset($buttonUi['text'])) {
240 $field['settings']['button_ui']['text'] = fluentform_sanitize_html($buttonUi['text']);
241 }
242
243 if (isset($buttonUi['img_url'])) {
244 $field['settings']['button_ui']['img_url'] = esc_url_raw($buttonUi['img_url']);
245 }
246 }
247 }
248
249
250 if (!empty($field['attributes'])) {
251 $attributes = array_filter(Arr::only($field['attributes'], $attributesKeys));
252
253 foreach ($attributes as $key => $value) {
254 $fields[$fieldIndex]['attributes'][$key] = call_user_func($attributesMap[$key], $value);
255 }
256 }
257
258 if (!empty($field['settings'])) {
259 $settings = array_filter(Arr::only($field['settings'], array_values($settingsKeys)));
260 foreach ($settings as $key => $value) {
261 $fields[$fieldIndex]['settings'][$key] = call_user_func($settingsMap[$key], $value);
262 }
263 }
264 /*
265 * Handle Name or address fields
266 */
267 if (!empty($field['fields'])) {
268 $fields[$fieldIndex]['fields'] = $this->sanitizeFieldMaps($field['fields']);
269 continue;
270 }
271
272 if (!empty($field['style_pref'])) {
273 $settings = array_filter(Arr::only($field['style_pref'], $stylePrefKeys));
274
275 foreach ($settings as $key => $value) {
276 $fields[$fieldIndex]['style_pref'][$key] = call_user_func($stylePrefMap[$key], $value);
277 }
278 }
279
280 $validationRules = Arr::get($field, 'settings.validation_rules');
281 if (!empty($validationRules)) {
282 foreach ($validationRules as $key => $rule) {
283 if (isset($rule['message'])) {
284 $message = $rule['message'];
285 $field['settings']['validation_rules'][$key]['message'] = wp_kses_post($message);
286 continue;
287 }
288 }
289 }
290 }
291
292 return $fields;
293 }
294
295 private function updatePrimaryEmail($form)
296 {
297 $emailInputs = FormFieldsParser::getElement($form, ['input_email'], ['element', 'attributes']);
298
299 if ($emailInputs) {
300 $emailInput = array_shift($emailInputs);
301 $emailInputName = Arr::get($emailInput, 'attributes.name');
302 } else {
303 $emailInputName = '';
304 }
305
306 FormMeta::persist($form->id, '_primary_email_field', $emailInputName);
307 }
308
309 private function sanitizeCustomSubmit($fields)
310 {
311 $customSubmitSanitizationMap = [
312 'hover_styles' => [
313 'backgroundColor' => [$this, 'sanitizeRgbColor'],
314 'borderColor' => [$this, 'sanitizeRgbColor'],
315 'color' => [$this, 'sanitizeRgbColor'],
316 'borderRadius' => 'sanitize_text_field',
317 'minWidth' => [$this, 'sanitizeMinWidth']
318 ],
319 'normal_styles' => [
320 'backgroundColor' => [$this, 'sanitizeRgbColor'],
321 'borderColor' => [$this, 'sanitizeRgbColor'],
322 'color' => [$this, 'sanitizeRgbColor'],
323 'borderRadius' => 'sanitize_text_field',
324 'minWidth' => [$this, 'sanitizeMinWidth']
325 ],
326 'button_ui' => [
327 'type' => 'sanitize_text_field',
328 'text' => 'fluentform_sanitize_html',
329 'img_url' => 'esc_url_raw',
330 ],
331 ];
332 foreach ($fields as $fieldIndex => $field) {
333 $element = Arr::get($field, 'element');
334
335 if ('custom_submit_button' == $element) {
336 $styleAttr = ['hover_styles', 'normal_styles', 'button_ui'];
337 foreach ($styleAttr as $attr) {
338 if ($styleConfigs = Arr::get($field, 'settings.' . $attr)) {
339 foreach ($styleConfigs as $key => $value) {
340 if (isset($customSubmitSanitizationMap[$attr][$key])) {
341 $sanitizeFunction = $customSubmitSanitizationMap[$attr][$key];
342 $fields[$fieldIndex]['settings'][$attr][$key] = $sanitizeFunction($value);
343 }
344 }
345 }
346 }
347 }
348 elseif ('container' == $element) {
349 $columns = $field['columns'];
350 foreach ($columns as $columnIndex => $column) {
351 $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeCustomSubmit($column['fields']);
352 }
353 return $fields;
354 }
355 }
356 return $fields;
357 }
358
359 private function sanitizeStepsWrapper($stepWrapper)
360 {
361 $stepsSanitizationMap = [
362 'prev_btn' => [
363 'type' => 'sanitize_text_field',
364 'text' => 'fluentform_sanitize_html',
365 'img_url' => 'esc_url_raw',
366 ],
367 ];
368
369 foreach ($stepWrapper as $fieldIndex => $field) {
370 $element = Arr::get($field, 'element');
371
372 if ($element === 'step_start' || $element === 'step_end') {
373 if (!empty($field['settings']['step_titles']) && is_array($field['settings']['step_titles'])) {
374 foreach ($field['settings']['step_titles'] as $index => $title) {
375 $field['settings']['step_titles'][$index] = fluentform_sanitize_html($title);
376 }
377 }
378
379 if (isset($field['settings']['tabs_show_progress_bar'])) {
380 $field['settings']['tabs_show_progress_bar'] = sanitize_text_field($field['settings']['tabs_show_progress_bar']) === 'yes' ? 'yes' : 'no';
381 }
382
383 if (isset($field['settings']['progress_layout'])) {
384 $progressLayout = sanitize_text_field($field['settings']['progress_layout']);
385 $field['settings']['progress_layout'] = in_array($progressLayout, ['top', 'left'], true) ? $progressLayout : 'top';
386 }
387
388 if (!empty($field['settings']['prev_btn']) && is_array($field['settings']['prev_btn'])) {
389 foreach ($field['settings']['prev_btn'] as $key => $value) {
390 if (isset($stepsSanitizationMap['prev_btn'][$key])) {
391 $sanitizeFunction = $stepsSanitizationMap['prev_btn'][$key];
392 $field['settings']['prev_btn'][$key] = $sanitizeFunction($value);
393 }
394 }
395 }
396
397 if (!empty($field['attributes']['class'])) {
398 $field['attributes']['class'] = sanitize_text_field($field['attributes']['class']);
399 }
400 if (!empty($field['attributes']['id'])) {
401 $field['attributes']['id'] = sanitize_text_field($field['attributes']['id']);
402 }
403 }
404
405 if ($element === 'step_start' && isset($field['fields'])) {
406 $field['fields'] = $this->sanitizeStepsWrapper($field['fields']);
407 }
408
409 $stepWrapper[$fieldIndex] = $field;
410 }
411
412 return $stepWrapper;
413 }
414
415 public function sanitizeMinWidth($value)
416 {
417 if (is_string($value) && preg_match('/^\d+%$/', $value)) {
418 return $value;
419 }
420 return '';
421 }
422
423 public function sanitizeRgbColor($value) {
424 if (preg_match('/^rgba?\((\d{1,3}\s*,\s*){2,3}(0|1|0?\.\d+)\)$/', $value)) {
425 return $value;
426 }
427 return '';
428 }
429 }
430