PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.01.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.01.02
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/controllers/FrmXMLController.php +37 -255 6.34.01.02 View file →
@@ -1,29 +1,20 @@
1 1 <?php
2 -if ( ! defined( 'ABSPATH' ) ) {
3 - die( 'You are not allowed to call this page directly.' );
4 -}
5 2
6 3 class FrmXMLController {
7 4
8 - /**
9 - * @return void
10 - */
11 5 public static function menu() {
12 6 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Import/Export', 'formidable' ), __( 'Import/Export', 'formidable' ), 'frm_edit_forms', 'formidable-import', 'FrmXMLController::route' );
13 7 }
14 8
15 - /**
16 - * @return void
17 - */
18 9 public static function add_default_templates() {
19 - if ( FrmXMLHelper::check_if_libxml_disable_entity_loader_exists() ) {
10 + if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
20 11 // XML import is not enabled on your server
21 12 return;
22 13 }
23 14
24 15 $set_err = libxml_use_internal_errors( true );
25 - $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
16 + $loader = libxml_disable_entity_loader( true );
26 17
27 18 $files = apply_filters( 'frm_default_templates_files', array() );
28 19
29 20 foreach ( (array) $files as $file ) {
@@ -33,9 +24,9 @@
33 24
34 25 unset( $files );
35 26
36 27 libxml_use_internal_errors( $set_err );
37 - FrmXMLHelper::maybe_libxml_disable_entity_loader( $loader );
28 + libxml_disable_entity_loader( $loader );
38 29 }
39 30
40 31 /**
41 32 * Use the template link to install the XML template
@@ -40,34 +31,15 @@
40 31 /**
41 32 * Use the template link to install the XML template
42 33 *
43 34 * @since 3.06
44 - * @return void
45 35 */
46 36 public static function install_template() {
47 - FrmAppHelper::permission_check( 'frm_edit_forms' );
37 + FrmAppHelper::permission_check( 'frm_create_forms' );
48 38 check_ajax_referer( 'frm_ajax', 'nonce' );
49 39
50 - if ( ! function_exists( 'simplexml_load_string' ) ) {
51 - $response = array(
52 - 'message' => __( 'Your server is missing the Simple XML extension. This is required to install a template.', 'formidable' ),
53 - );
54 - echo wp_json_encode( $response );
55 - wp_die();
56 - }
40 + $url = FrmAppHelper::get_param( 'xml', '', 'post', 'esc_url_raw' );
57 41
58 - $form = self::get_posted_form();
59 - $url = FrmAppHelper::get_param( 'xml', '', 'post', 'esc_url_raw' );
60 - self::override_url( $form, $url );
61 -
62 - if ( ! self::validate_xml_url( $url ) ) {
63 - $response = array(
64 - 'message' => __( 'The template you are trying to install could not be validated.', 'formidable' ),
65 - );
66 - echo wp_json_encode( $response );
67 - wp_die();
68 - }
69 -
70 42 $response = wp_remote_get( $url );
71 43 $body = wp_remote_retrieve_body( $response );
72 44 $xml = simplexml_load_string( $body );
73 45
@@ -72,9 +44,9 @@
72 44 $xml = simplexml_load_string( $body );
73 45
74 46 if ( ! $xml ) {
75 47 $response = array(
76 - 'message' => __( 'There was an error reading the form template.', 'formidable' ),
48 + 'message' => __( 'There was an error reading the form template', 'formidable' ),
77 49 );
78 50 echo wp_json_encode( $response );
79 51 wp_die();
80 52 }
@@ -80,10 +52,10 @@
80 52 }
81 53
82 54 self::set_new_form_name( $xml );
83 55
84 - $imported = FrmXMLHelper::import_xml_now( $xml, true );
85 - if ( ! empty( $imported['form_status'] ) ) {
56 + $imported = FrmXMLHelper::import_xml_now( $xml );
57 + if ( isset( $imported['form_status'] ) && ! empty( $imported['form_status'] ) ) {
86 58 // Get the last form id in case there are child forms.
87 59 end( $imported['form_status'] );
88 60 $form_id = key( $imported['form_status'] );
89 61 $response = array(
@@ -90,153 +62,19 @@
90 62 'id' => $form_id,
91 63 'redirect' => FrmForm::get_edit_link( $form_id ),
92 64 'success' => 1,
93 65 );
94 - if ( ! empty( $imported['imported']['posts'] ) ) {
95 - // Return the link to the last page created.
96 - $pages = $imported['posts'];
97 - }
98 -
99 - if ( ! empty( $form ) ) {
100 - // Create selected pages with the correct shortcodes.
101 - $pages = self::create_pages_for_import( $form );
102 - }
103 -
104 - if ( isset( $pages ) && ! empty( $pages ) ) {
105 - $post_id = end( $pages );
106 - $response['redirect'] = get_permalink( $post_id );
107 - }
108 66 } else {
109 - if ( isset( $imported['error'] ) ) {
110 - $message = $imported['error'];
111 - } else {
112 - $message = __( 'There was an error importing form', 'formidable' );
113 - }
114 67 $response = array(
115 - 'message' => $message,
68 + 'message' => __( 'There was an error importing form', 'formidable' ),
116 69 );
117 -
118 70 }
119 71
120 - $response = apply_filters( 'frm_xml_response', $response, compact( 'form', 'imported' ) );
121 -
122 72 echo wp_json_encode( $response );
123 73 wp_die();
124 74 }
125 75
126 76 /**
127 - * Make sure that the XML file we're trying to load is in fact an XML file, and that it's coming from our S3 bucket.
128 - * This is to make sure that the URL can't be exploited for a SSRF attack.
129 - *
130 - * @since 5.5.5
131 - * @param string $url
132 - *
133 - * @return bool True on success, False on error.
134 - */
135 - private static function validate_xml_url( $url ) {
136 - return FrmAppHelper::validate_url_is_in_s3_bucket( $url, 'xml' );
137 - }
138 -
139 - /**
140 - * @since 4.06.02
141 - *
142 - * @return mixed
143 - */
144 - private static function get_posted_form() {
145 - $form = FrmAppHelper::get_param( 'form', '', 'post', 'wp_unslash' );
146 - if ( empty( $form ) ) {
147 - return $form;
148 - }
149 - $form = json_decode( $form, true );
150 - return $form;
151 - }
152 -
153 - /**
154 - * Get a different URL depending on the selection in the form.
155 - *
156 - * @since 4.06.02
157 - *
158 - * @return void
159 - */
160 - private static function override_url( $form, &$url ) {
161 - $selected_form = self::get_selected_in_form( $form, 'form' );
162 - if ( empty( $selected_form ) ) {
163 - return;
164 - }
165 -
166 - $selected_xml = isset( $form['xml'] ) && isset( $form['xml'][ $selected_form ] ) ? $form['xml'][ $selected_form ] : '';
167 - if ( empty( $selected_xml ) || strpos( $selected_xml, 'http' ) !== 0 ) {
168 - return;
169 - }
170 -
171 - $url = $selected_xml;
172 - }
173 -
174 - /**
175 - * @since 4.06.02
176 - *
177 - * @param string $value
178 - * @param array $form
179 - */
180 - private static function get_selected_in_form( $form, $value = 'form' ) {
181 - if ( ! empty( $form ) && isset( $form[ $value ] ) && ! empty( $form[ $value ] ) ) {
182 - return $form[ $value ];
183 - }
184 -
185 - return '';
186 - }
187 -
188 - /**
189 - * @since 4.06.02
190 - *
191 - * @param array $form The posted form values.
192 - *
193 - * @return array The array of created pages.
194 - */
195 - private static function create_pages_for_import( $form ) {
196 - if ( ! isset( $form['pages'] ) || empty( $form['pages'] ) ) {
197 - return;
198 - }
199 -
200 - $form_key = self::get_selected_in_form( $form, 'form' );
201 - $view_keys = self::get_selected_in_form( $form, 'view' );
202 -
203 - $page_ids = array();
204 - foreach ( (array) $form['pages'] as $for => $name ) {
205 - if ( empty( $name ) ) {
206 - // Don't create a page if no title is given.
207 - continue;
208 - }
209 -
210 - if ( $for === 'view' ) {
211 - $item_key = is_array( $view_keys ) ? $view_keys[ $form_key ] : $view_keys;
212 - $shortcode = '[display-frm-data id=%1$s filter=limited]';
213 - } elseif ( $for === 'form' ) {
214 - $item_key = $form_key;
215 - $shortcode = '[formidable id=%1$s]';
216 - } else {
217 - $item_key = self::get_selected_in_form( $form, 'form' );
218 - $shortcode = '[' . esc_html( $for ) . ' id=%1$s]';
219 - }
220 -
221 - if ( empty( $item_key ) ) {
222 - // Don't create it if the shortcode won't show anything.
223 - continue;
224 - }
225 -
226 - $page_ids[ $for ] = wp_insert_post(
227 - array(
228 - 'post_title' => $name,
229 - 'post_type' => 'page',
230 - 'post_content' => sprintf( $shortcode, $item_key ),
231 - )
232 - );
233 - }
234 -
235 - return $page_ids;
236 - }
237 -
238 - /**
239 77 * Change the name of the last form that is not a child.
240 78 * This will allow for lookup fields and embedded forms
241 79 * since we redirect to the last form.
242 80 *
@@ -242,9 +80,8 @@
242 80 *
243 81 * @since 3.06
244 82 *
245 83 * @param object $xml The values included in the XML.
246 - * @return void
247 84 */
248 85 private static function set_new_form_name( &$xml ) {
249 86 if ( ! isset( $xml->form ) ) {
250 87 return;
@@ -249,38 +86,29 @@
249 86 if ( ! isset( $xml->form ) ) {
250 87 return;
251 88 }
252 89
253 - $name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
254 - $description = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
255 - if ( ! $name && ! $description ) {
256 - return;
257 - }
258 -
259 90 // Get the main form ID.
260 91 $set_name = 0;
261 92 foreach ( $xml->form as $form ) {
262 - if ( empty( $form->parent_form_id ) ) {
263 - $set_name = (int) $form->id;
93 + if ( ! isset( $form->parent_form_id ) || empty( $form->parent_form_id ) ) {
94 + $set_name = $form->id;
264 95 }
265 96 }
266 97
267 98 foreach ( $xml->form as $form ) {
268 99 // Maybe set the form name if this isn't a child form.
269 - if ( $set_name === (int) $form->id ) {
270 - $form->name = $name;
271 - $form->description = $description;
100 + if ( $set_name == $form->id ) {
101 + $form->name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
102 + $form->description = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
272 103 }
273 104
274 105 // Use a unique key to prevent editing existing form.
275 - $sanitized_form_name = sanitize_title( $form->name );
276 - $form->form_key = FrmAppHelper::get_unique_key( $sanitized_form_name, 'frm_forms', 'form_key' );
106 + $name = sanitize_title( $form->name );
107 + $form->form_key = FrmAppHelper::get_unique_key( $name, 'frm_forms', 'form_key' );
277 108 }
278 109 }
279 110
280 - /**
281 - * @return void
282 - */
283 111 public static function route() {
284 112 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
285 113 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
286 114 FrmAppHelper::include_svg();
@@ -285,25 +113,19 @@
285 113 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
286 114 FrmAppHelper::include_svg();
287 115
288 116 if ( 'import_xml' === $action ) {
289 - self::import_xml();
117 + return self::import_xml();
290 118 } elseif ( 'export_xml' === $action ) {
291 - self::export_xml();
119 + return self::export_xml();
292 120 } elseif ( apply_filters( 'frm_xml_route', true, $action ) ) {
293 - self::form();
121 + return self::form();
294 122 }
295 123 }
296 124
297 - /**
298 - * @param string[] $errors
299 - * @param string $message
300 - *
301 - * @return void
302 - */
303 125 public static function form( $errors = array(), $message = '' ) {
304 126 $where = array(
305 - 'status' => array( null, '', 'published' ),
127 + 'status' => array( null, '', 'published' ),
306 128 );
307 129 $forms = FrmForm::getAll( $where, 'name' );
308 130
309 131 $export_types = array(
@@ -325,14 +147,11 @@
325 147 ),
326 148 );
327 149 $export_format = apply_filters( 'frm_export_formats', $export_format );
328 150
329 - include FrmAppHelper::plugin_path() . '/classes/views/xml/import_form.php';
151 + include( FrmAppHelper::plugin_path() . '/classes/views/xml/import_form.php' );
330 152 }
331 153
332 - /**
333 - * @return void
334 - */
335 154 public static function import_xml() {
336 155 $errors = array();
337 156 $message = '';
338 157
@@ -352,9 +171,9 @@
352 171 return;
353 172 }
354 173
355 174 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
356 - $file = isset( $_FILES['frm_import_file']['tmp_name'] ) ? sanitize_option( 'upload_path', $_FILES['frm_import_file']['tmp_name'] ) : '';
175 + $file = isset( $_FILES['frm_import_file']['tmp_name'] ) ? $_FILES['frm_import_file']['tmp_name'] : '';
357 176
358 177 if ( ! is_uploaded_file( $file ) ) {
359 178 unset( $file );
360 179 $errors[] = __( 'The file does not exist, please try again.', 'formidable' );
@@ -374,10 +193,9 @@
374 193 );
375 194 $export_format = apply_filters( 'frm_export_formats', $export_format );
376 195
377 196 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
378 - $file_type = sanitize_option( 'upload_path', $_FILES['frm_import_file']['name'] );
379 - $file_type = strtolower( pathinfo( $file_type, PATHINFO_EXTENSION ) );
197 + $file_type = strtolower( pathinfo( $_FILES['frm_import_file']['name'], PATHINFO_EXTENSION ) );
380 198 if ( 'xml' !== $file_type && isset( $export_format[ $file_type ] ) ) {
381 199 // allow other file types to be imported
382 200 do_action( 'frm_before_import_' . $file_type );
383 201
@@ -384,9 +202,9 @@
384 202 return;
385 203 }
386 204 unset( $file_type );
387 205
388 - if ( FrmXMLHelper::check_if_libxml_disable_entity_loader_exists() ) {
206 + if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
389 207 $errors[] = __( 'XML import is not enabled on your server with the libxml_disable_entity_loader function.', 'formidable' );
390 208 self::form( $errors );
391 209
392 210 return;
@@ -392,9 +210,9 @@
392 210 return;
393 211 }
394 212
395 213 $set_err = libxml_use_internal_errors( true );
396 - $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
214 + $loader = libxml_disable_entity_loader( true );
397 215
398 216 $result = FrmXMLHelper::import_xml( $file );
399 217 FrmXMLHelper::parse_message( $result, $message, $errors );
400 218
@@ -400,16 +218,13 @@
400 218
401 219 unset( $file );
402 220
403 221 libxml_use_internal_errors( $set_err );
404 - FrmXMLHelper::maybe_libxml_disable_entity_loader( $loader );
222 + libxml_disable_entity_loader( $loader );
405 223
406 224 self::form( $errors, $message );
407 225 }
408 226
409 - /**
410 - * @return void
411 - */
412 227 public static function export_xml() {
413 228 $error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'export-xml', 'export-xml-nonce' );
414 229 if ( ! empty( $error ) ) {
415 230 wp_die( esc_html( $error ) );
@@ -414,10 +229,10 @@
414 229 if ( ! empty( $error ) ) {
415 230 wp_die( esc_html( $error ) );
416 231 }
417 232
418 - $ids = FrmAppHelper::get_post_param( 'frm_export_forms', array(), 'sanitize_text_field' );
419 - $type = FrmAppHelper::get_post_param( 'type', array(), 'sanitize_text_field' );
233 + $ids = FrmAppHelper::get_post_param( 'frm_export_forms', array() );
234 + $type = FrmAppHelper::get_post_param( 'type', array() );
420 235 $format = FrmAppHelper::get_post_param( 'format', 'xml', 'sanitize_title' );
421 236
422 237 if ( ! headers_sent() && ! $type ) {
423 238 wp_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
@@ -434,15 +249,8 @@
434 249
435 250 wp_die();
436 251 }
437 252
438 - /**
439 - * @param array $args
440 - *
441 - * @psalm-param array{ids?: mixed} $args
442 - *
443 - * @return void
444 - */
445 253 public static function generate_xml( $type, $args = array() ) {
446 254 global $wpdb;
447 255
448 256 self::prepare_types_array( $type );
@@ -549,14 +357,11 @@
549 357 header( 'Content-Disposition: attachment; filename=' . $filename );
550 358 header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
551 359
552 360 echo '<?xml version="1.0" encoding="' . esc_attr( get_bloginfo( 'charset' ) ) . "\" ?>\n";
553 - include FrmAppHelper::plugin_path() . '/classes/views/xml/xml.php';
361 + include( FrmAppHelper::plugin_path() . '/classes/views/xml/xml.php' );
554 362 }
555 363
556 - /**
557 - * @return void
558 - */
559 364 private static function prepare_types_array( &$type ) {
560 365 $type = (array) $type;
561 366 if ( ! in_array( 'forms', $type ) && ( in_array( 'items', $type ) || in_array( 'posts', $type ) ) ) {
562 367 // make sure the form is included if there are entries
@@ -574,12 +379,8 @@
574 379 * Use the nme of the form if only one form is exported.
575 380 *
576 381 * @since 3.06
577 382 *
578 - * @param array $type
579 - * @param array $records
580 - * @param array $args
581 - *
582 383 * @return string
583 384 */
584 385 private static function get_file_name( $args, $type, $records ) {
585 386 $has_one_form = isset( $records['forms'] ) && ! empty( $records['forms'] ) && count( $args['ids'] ) === 1;
@@ -591,10 +392,9 @@
591 392 foreach ( $records['forms'] as $form_id ) {
592 393 $filename = 'form-' . $form_id . '.xml';
593 394 if ( $selected_form_id === $form_id ) {
594 395 $form = FrmForm::getOne( $form_id );
595 - $filename = $form->name !== '' ? $form->name : $form->form_key;
596 - $filename = sanitize_title( $filename ) . '-form.xml';
396 + $filename = sanitize_title( $form->name ) . '-form.xml';
597 397 break;
598 398 }
599 399 }
600 400 } else {
@@ -602,24 +402,14 @@
602 402
603 403 if ( ! empty( $sitename ) ) {
604 404 $sitename .= '.';
605 405 }
606 - $filename = $sitename . 'formidable.' . gmdate( 'Y-m-d' ) . '.xml';
406 + $filename = $sitename . 'formidable.' . date( 'Y-m-d' ) . '.xml';
607 407 }
608 408
609 - /**
610 - * @since 5.3
611 - *
612 - * @param string $filename
613 - */
614 - return apply_filters( 'frm_xml_filename', $filename );
409 + return $filename;
615 410 }
616 411
617 - /**
618 - * @param array $atts
619 - *
620 - * @return void
621 - */
622 412 public static function generate_csv( $atts ) {
623 413 $form_ids = $atts['ids'];
624 414 if ( empty( $form_ids ) ) {
625 415 wp_die( esc_html__( 'Please select a form', 'formidable' ) );
@@ -630,10 +420,8 @@
630 420 /**
631 421 * Export to CSV
632 422 *
633 423 * @since 2.0.19
634 - *
635 - * @return void
636 424 */
637 425 public static function csv( $form_id = false, $search = '', $fid = '' ) {
638 426 FrmAppHelper::permission_check( 'frm_view_entries' );
639 427
@@ -650,16 +438,11 @@
650 438 }
651 439
652 440 global $wpdb;
653 441
654 - $form = FrmForm::getOne( $form_id );
442 + $form = FrmForm::getOne( $form_id );
443 + $form_id = $form->id;
655 444
656 - if ( ! $form ) {
657 - esc_html_e( 'Form not found.', 'formidable' );
658 - wp_die();
659 - }
660 -
661 - $form_id = $form->id;
662 445 $form_cols = self::get_fields_for_csv_export( $form_id, $form );
663 446
664 447 $item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
665 448 if ( ! empty( $item_id ) ) {
@@ -697,9 +480,8 @@
697 480 /**
698 481 * Get the fields that should be included in the CSV export
699 482 *
700 483 * @since 2.0.19
701 - * @since 5.0.16 function went from private to public.
702 484 *
703 485 * @param int $form_id
704 486 * @param object $form
705 487 *
@@ -704,18 +486,18 @@
704 486 * @param object $form
705 487 *
706 488 * @return array $csv_fields
707 489 */
708 - public static function get_fields_for_csv_export( $form_id, $form ) {
490 + private static function get_fields_for_csv_export( $form_id, $form ) {
709 491 $csv_fields = FrmField::get_all_for_form( $form_id, '', 'include', 'include' );
710 492 $no_export_fields = FrmField::no_save_fields();
711 493 foreach ( $csv_fields as $k => $f ) {
712 - if ( in_array( $f->type, $no_export_fields, true ) ) {
494 + if ( in_array( $f->type, $no_export_fields ) ) {
713 495 unset( $csv_fields[ $k ] );
714 496 }
715 497 }
716 498
717 - return apply_filters( 'frm_fields_for_csv_export', $csv_fields, compact( 'form' ) );
499 + return $csv_fields;
718 500 }
719 501
720 502 public static function allow_mime( $mimes ) {
721 503 if ( ! isset( $mimes['csv'] ) ) {