PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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 +96 -57 6.25 → trunk View file →
@@ -8,9 +8,9 @@
8 8 /**
9 9 * @return void
10 10 */
11 11 public static function menu() {
12 - add_submenu_page( 'formidable', 'Formidable | ' . __( 'Import/Export', 'formidable' ), __( 'Import/Export', 'formidable' ), 'frm_edit_forms', 'formidable-import', 'FrmXMLController::route' );
12 + add_submenu_page( 'formidable', 'Formidable | ' . __( 'Import/Export', 'formidable' ), __( 'Import/Export', 'formidable' ), 'frm_edit_forms', 'formidable-import', 'FrmXMLController::route' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
13 13 }
14 14
15 15 /**
16 16 * @return void
@@ -22,11 +22,10 @@
22 22 }
23 23
24 24 $set_err = libxml_use_internal_errors( true );
25 25 $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
26 + $files = apply_filters( 'frm_default_templates_files', array() );
26 27
27 - $files = apply_filters( 'frm_default_templates_files', array() );
28 -
29 28 foreach ( (array) $files as $file ) {
30 29 FrmXMLHelper::import_xml( $file );
31 30 unset( $file );
32 31 }
@@ -40,8 +39,9 @@
40 39 /**
41 40 * Use the template link to install the XML template
42 41 *
43 42 * @since 3.06
43 + *
44 44 * @return void
45 45 */
46 46 public static function install_template() {
47 47 FrmAppHelper::permission_check( 'frm_edit_forms' );
@@ -81,23 +81,24 @@
81 81
82 82 self::set_new_form_name( $xml );
83 83
84 84 $imported = FrmXMLHelper::import_xml_now( $xml, true );
85 +
85 86 if ( ! empty( $imported['form_status'] ) ) {
86 87 // Get the last form id in case there are child forms.
87 - end( $imported['form_status'] );
88 - $form_id = key( $imported['form_status'] );
88 + $form_id = array_key_last( $imported['form_status'] );
89 89 $response = array(
90 90 'id' => $form_id,
91 91 'redirect' => FrmForm::get_edit_link( $form_id ) . '&new_template=true',
92 92 'success' => 1,
93 93 );
94 +
94 95 if ( ! empty( $imported['imported']['posts'] ) ) {
95 96 // Return the link to the last page created.
96 97 $pages = $imported['posts'];
97 98 }
98 99
99 - if ( ! empty( $form ) ) {
100 + if ( $form ) {
100 101 // Create selected pages with the correct shortcodes.
101 102 $pages = self::create_pages_for_import( $form );
102 103 }
103 104
@@ -105,17 +106,12 @@
105 106 $post_id = end( $pages );
106 107 $response['redirect'] = get_permalink( $post_id );
107 108 }
108 109 } else {
109 - if ( isset( $imported['error'] ) ) {
110 - $message = $imported['error'];
111 - } else {
112 - $message = __( 'There was an error importing form', 'formidable' );
113 - }
110 + $message = $imported['error'] ?? __( 'There was an error importing form', 'formidable' );
114 111 $response = array(
115 112 'message' => $message,
116 113 );
117 -
118 114 }//end if
119 115
120 116 /**
121 117 * @since 6.18 Added `url` to the $args.
@@ -130,8 +126,9 @@
130 126 * 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.
131 127 * This is to make sure that the URL can't be exploited for a SSRF attack.
132 128 *
133 129 * @since 5.5.5
130 + *
134 131 * @param string $url
135 132 *
136 133 * @return bool True on success, False on error.
137 134 */
@@ -145,13 +142,9 @@
145 142 * @return mixed
146 143 */
147 144 private static function get_posted_form() {
148 145 $form = FrmAppHelper::get_param( 'form', '', 'post', 'wp_unslash' );
149 - if ( empty( $form ) ) {
150 - return $form;
151 - }
152 - $form = json_decode( $form, true );
153 - return $form;
146 + return $form ? json_decode( $form, true ) : $form;
154 147 }
155 148
156 149 /**
157 150 * Get a different URL depending on the selection in the form.
@@ -157,18 +150,23 @@
157 150 * Get a different URL depending on the selection in the form.
158 151 *
159 152 * @since 4.06.02
160 153 *
154 + * @param array $form The posted form values.
155 + * @param string $url The URL to override.
156 + *
161 157 * @return void
162 158 */
163 159 private static function override_url( $form, &$url ) {
164 160 $selected_form = self::get_selected_in_form( $form, 'form' );
165 - if ( empty( $selected_form ) ) {
161 +
162 + if ( ! $selected_form ) {
166 163 return;
167 164 }
168 165
169 166 $selected_xml = isset( $form['xml'] ) && isset( $form['xml'][ $selected_form ] ) ? $form['xml'][ $selected_form ] : '';
170 - if ( empty( $selected_xml ) || strpos( $selected_xml, 'http' ) !== 0 ) {
167 +
168 + if ( ! $selected_xml || ! str_starts_with( $selected_xml, 'http' ) ) {
171 169 return;
172 170 }
173 171
174 172 $url = $selected_xml;
@@ -178,11 +176,13 @@
178 176 * @since 4.06.02
179 177 *
180 178 * @param array $form
181 179 * @param string $value
180 + *
181 + * @return array|string
182 182 */
183 183 private static function get_selected_in_form( $form, $value = 'form' ) {
184 - if ( ! empty( $form ) && ! empty( $form[ $value ] ) ) {
184 + if ( $form && ! empty( $form[ $value ] ) ) {
185 185 return $form[ $value ];
186 186 }
187 187
188 188 return '';
@@ -191,8 +191,9 @@
191 191 /**
192 192 * @since 4.06.02
193 193 *
194 194 * @param array $form The posted form values.
195 + *
195 196 * @return array|null The array of created pages.
196 197 */
197 198 private static function create_pages_for_import( $form ) {
198 199 if ( empty( $form['pages'] ) ) {
@@ -200,12 +201,12 @@
200 201 }
201 202
202 203 $form_key = self::get_selected_in_form( $form, 'form' );
203 204 $view_keys = self::get_selected_in_form( $form, 'view' );
205 + $page_ids = array();
204 206
205 - $page_ids = array();
206 207 foreach ( (array) $form['pages'] as $for => $name ) {
207 - if ( empty( $name ) ) {
208 + if ( ! $name ) {
208 209 // Don't create a page if no title is given.
209 210 continue;
210 211 }
211 212
@@ -244,8 +245,9 @@
244 245 *
245 246 * @since 3.06
246 247 *
247 248 * @param object $xml The values included in the XML.
249 + *
248 250 * @return void
249 251 */
250 252 private static function set_new_form_name( &$xml ) {
251 253 if ( ! isset( $xml->form ) ) {
@@ -253,8 +255,9 @@
253 255 }
254 256
255 257 $name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
256 258 $description = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
259 +
257 260 if ( ! $name && ! $description ) {
258 261 return;
259 262 }
260 263
@@ -259,8 +262,9 @@
259 262 }
260 263
261 264 // Get the main form ID.
262 265 $set_name = 0;
266 +
263 267 foreach ( $xml->form as $form ) {
264 268 if ( empty( $form->parent_form_id ) ) {
265 269 $set_name = (int) $form->id;
266 270 }
@@ -334,12 +338,12 @@
334 338 /**
335 339 * @return void
336 340 */
337 341 public static function import_xml() {
338 - $errors = array();
339 - $message = '';
342 + $errors = array();
343 + $message = '';
344 + $permission_error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'import-xml', 'import-xml-nonce' );
340 345
341 - $permission_error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'import-xml', 'import-xml-nonce' );
342 346 if ( false !== $permission_error ) {
343 347 $errors[] = $permission_error;
344 348 self::form( $errors );
345 349
@@ -345,10 +349,11 @@
345 349
346 350 return;
347 351 }
348 352
349 - // phpcs:ignore WordPress.Security.NonceVerification.Missing
353 + // phpcs:ignore WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
350 354 $has_file = ! empty( $_FILES['frm_import_file'] ) && ! empty( $_FILES['frm_import_file']['name'] ) && ! empty( $_FILES['frm_import_file']['size'] ) && (int) $_FILES['frm_import_file']['size'] > 0;
355 +
351 356 if ( ! $has_file ) {
352 357 $errors[] = __( 'Oops, you didn\'t select a file.', 'formidable' );
353 358 self::form( $errors );
354 359
@@ -377,10 +382,11 @@
377 382
378 383 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
379 384 $file_type = sanitize_option( 'upload_path', $_FILES['frm_import_file']['name'] );
380 385 $file_type = strtolower( pathinfo( $file_type, PATHINFO_EXTENSION ) );
386 +
381 387 if ( 'xml' !== $file_type && isset( $export_format[ $file_type ] ) ) {
382 - // allow other file types to be imported
388 + // Allow other file types to be imported
383 389 do_action( 'frm_before_import_' . $file_type );
384 390
385 391 return;
386 392 }
@@ -394,10 +400,9 @@
394 400 }
395 401
396 402 $set_err = libxml_use_internal_errors( true );
397 403 $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
398 -
399 - $result = FrmXMLHelper::import_xml( $file );
404 + $result = FrmXMLHelper::import_xml( $file );
400 405 FrmXMLHelper::parse_message( $result, $message, $errors );
401 406
402 407 unset( $file );
403 408
@@ -411,9 +416,10 @@
411 416 * @return void
412 417 */
413 418 public static function export_xml() {
414 419 $error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'export-xml', 'export-xml-nonce' );
415 - if ( ! empty( $error ) ) {
420 +
421 + if ( $error ) {
416 422 wp_die( esc_html( $error ) );
417 423 }
418 424
419 425 $ids = FrmAppHelper::get_post_param( 'frm_export_forms', array(), 'sanitize_text_field' );
@@ -420,9 +426,9 @@
420 426 $type = FrmAppHelper::get_post_param( 'type', array(), 'sanitize_text_field' );
421 427 $format = FrmAppHelper::get_post_param( 'format', 'xml', 'sanitize_title' );
422 428
423 429 if ( ! headers_sent() && ! $type ) {
424 - wp_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
430 + wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
425 431 die();
426 432 }
427 433
428 434 if ( 'xml' === $format ) {
@@ -436,20 +442,27 @@
436 442 wp_die();
437 443 }
438 444
439 445 /**
440 - * @param string[] $type
441 - * @param array $args
446 + * @param array<string>|string $type
447 + * @param array $args
442 448 *
443 449 * @psalm-param array{ids?: mixed} $args
444 450 *
445 451 * @return void
446 452 */
447 - public static function generate_xml( $type, $args = array() ) {
453 + public static function generate_xml( $type, $args = array() ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
448 454 global $wpdb;
449 455
450 456 self::prepare_types_array( $type );
451 457
458 + if ( ! is_array( $type ) ) {
459 + // This shouldn't be possible.
460 + // It is cast to array in prepare_types_array.
461 + // This is just for static analysis.
462 + return;
463 + }
464 +
452 465 $tables = array(
453 466 'items' => $wpdb->prefix . 'frm_items',
454 467 'forms' => $wpdb->prefix . 'frm_forms',
455 468 'posts' => $wpdb->posts,
@@ -462,9 +475,9 @@
462 475 );
463 476 $args = wp_parse_args( $args, $defaults );
464 477
465 478 // Make sure ids are numeric.
466 - if ( is_array( $args['ids'] ) && ! empty( $args['ids'] ) ) {
479 + if ( is_array( $args['ids'] ) && $args['ids'] ) {
467 480 $args['ids'] = array_filter( $args['ids'], 'is_numeric' );
468 481 }
469 482
470 483 $records = array();
@@ -469,12 +482,11 @@
469 482
470 483 $records = array();
471 484
472 485 foreach ( $type as $tb_type ) {
473 - $where = array();
474 - $join = '';
475 - $table = $tables[ $tb_type ];
476 -
486 + $where = array();
487 + $join = '';
488 + $table = $tables[ $tb_type ];
477 489 $select = $table . '.id';
478 490 $query_vars = array();
479 491
480 492 switch ( $tb_type ) {
@@ -492,8 +504,9 @@
492 504 break;
493 505 case 'actions':
494 506 $select = $table . '.ID';
495 507 $where['post_type'] = FrmFormActionsController::$action_post_type;
508 +
496 509 if ( ! empty( $args['ids'] ) ) {
497 510 $where['menu_order'] = $args['ids'];
498 511 }
499 512 break;
@@ -508,10 +521,12 @@
508 521 $frm_style = new FrmStyle();
509 522 $default_style = $frm_style->get_default_style();
510 523 $form_ids = $args['ids'];
511 524 $style_ids = array();
525 +
512 526 foreach ( $form_ids as $form_id ) {
513 527 $form_data = FrmForm::getOne( $form_id );
528 +
514 529 // For forms that have not been updated while running 2.0, check if custom_style is set.
515 530 if ( isset( $form_data->options['custom_style'] ) ) {
516 531 if ( 1 === absint( $form_data->options['custom_style'] ) ) {
517 532 $style_ids[] = $default_style->ID;
@@ -520,13 +535,14 @@
520 535 }
521 536 }
522 537 unset( $form_id, $form_data );
523 538 }
539 +
524 540 $select = $table . '.ID';
525 541 $where['post_type'] = 'frm_styles';
526 542
527 543 // Only export selected styles.
528 - if ( ! empty( $style_ids ) ) {
544 + if ( $style_ids ) {
529 545 $where['ID'] = $style_ids;
530 546 }
531 547 break;
532 548 default:
@@ -558,9 +574,11 @@
558 574 /**
559 575 * Returns an array that has parent term slugs for the terms provided.
560 576 *
561 577 * @since 6.8.3
578 + *
562 579 * @param array $terms
580 + *
563 581 * @return array
564 582 */
565 583 public static function get_parent_terms_slugs( $terms ) {
566 584 $parent_term_ids = array_filter( array_unique( wp_list_pluck( $terms, 'parent' ) ) );
@@ -569,26 +587,30 @@
569 587 if ( ! $parent_term_ids ) {
570 588 return $parent_slugs;
571 589 }
572 590
573 - $results = FrmDb::get_results( 'terms', array( 'term_id' => $parent_term_ids ), 'term_id, slug' );
574 - $parent_slugs = wp_list_pluck( $results, 'slug', 'term_id' );
591 + $results = FrmDb::get_results( 'terms', array( 'term_id' => $parent_term_ids ), 'term_id, slug' );
575 592
576 - return $parent_slugs;
593 + return wp_list_pluck( $results, 'slug', 'term_id' );
577 594 }
578 595
579 596 /**
597 + * Prepare the types array.
598 + *
599 + * @param array<string>|string $type
600 + *
580 601 * @return void
581 602 */
582 603 private static function prepare_types_array( &$type ) {
583 604 $type = (array) $type;
605 +
584 606 if ( ! in_array( 'forms', $type, true ) && ( in_array( 'items', $type, true ) || in_array( 'posts', $type, true ) ) ) {
585 - // make sure the form is included if there are entries
607 + // Make sure the form is included if there are entries
586 608 $type[] = 'forms';
587 609 }
588 610
589 611 if ( in_array( 'forms', $type, true ) ) {
590 - // include actions with forms
612 + // Include actions with forms
591 613 $type[] = 'actions';
592 614 }
593 615 }
594 616
@@ -599,19 +621,22 @@
599 621 * @since 3.06
600 622 *
601 623 * @param array $args
602 624 * @param array $records
625 + *
603 626 * @return string
604 627 */
605 628 private static function get_file_name( $args, $records ) {
606 629 $has_one_form = ! empty( $records['forms'] ) && count( $args['ids'] ) === 1;
630 +
607 631 if ( $has_one_form ) {
608 - // one form is being exported
632 + // One form is being exported
609 633 $selected_form_id = reset( $args['ids'] );
610 634 $filename = 'form-' . $selected_form_id . '.xml';
611 635
612 636 foreach ( $records['forms'] as $form_id ) {
613 637 $filename = 'form-' . $form_id . '.xml';
638 +
614 639 if ( $selected_form_id === $form_id ) {
615 640 $form = FrmForm::getOne( $form_id );
616 641 $filename = $form->name !== '' ? $form->name : $form->form_key;
617 642 $filename = sanitize_title( $filename ) . '-form.xml';
@@ -620,11 +645,12 @@
620 645 }
621 646 } else {
622 647 $sitename = sanitize_key( get_bloginfo( 'name' ) );
623 648
624 - if ( ! empty( $sitename ) ) {
649 + if ( $sitename ) {
625 650 $sitename .= '.';
626 651 }
652 +
627 653 $filename = $sitename . 'formidable.' . gmdate( 'Y-m-d' ) . '.xml';
628 654 }//end if
629 655
630 656 /**
@@ -641,9 +667,10 @@
641 667 * @return void
642 668 */
643 669 public static function generate_csv( $atts ) {
644 670 $form_ids = $atts['ids'];
645 - if ( empty( $form_ids ) ) {
671 +
672 + if ( ! $form_ids ) {
646 673 wp_die( esc_html__( 'Please select a form', 'formidable' ) );
647 674 }
648 675 self::csv( reset( $form_ids ) );
649 676 }
@@ -652,8 +679,12 @@
652 679 * Export to CSV
653 680 *
654 681 * @since 2.0.19
655 682 *
683 + * @param false|int|string $form_id
684 + * @param string $search
685 + * @param string $fid
686 + *
656 687 * @return void
657 688 */
658 689 public static function csv( $form_id = false, $search = '', $fid = '' ) {
659 690 FrmAppHelper::permission_check( 'frm_view_entries' );
@@ -659,9 +690,9 @@
659 690 FrmAppHelper::permission_check( 'frm_view_entries' );
660 691
661 692 if ( ! $form_id ) {
662 693 $form_id = FrmAppHelper::get_param( 'form', '', 'get', 'sanitize_text_field' );
663 - $search = FrmAppHelper::get_param( ( isset( $_REQUEST['s'] ) ? 's' : 'search' ), '', 'get', 'sanitize_text_field' );
694 + $search = FrmAppHelper::get_param( isset( $_REQUEST['s'] ) ? 's' : 'search', '', 'get', 'sanitize_text_field' );
664 695 $fid = FrmAppHelper::get_param( 'fid', '', 'get', 'sanitize_text_field' );
665 696 }
666 697
667 698 // Remove time limit to execute this function.
@@ -667,9 +698,11 @@
667 698 // Remove time limit to execute this function.
668 699 if ( function_exists( 'set_time_limit' ) ) {
669 700 set_time_limit( 0 );
670 701 }
702 +
671 703 $mem_limit = str_replace( 'M', '', ini_get( 'memory_limit' ) );
704 +
672 705 if ( (int) $mem_limit < 256 ) {
673 706 wp_raise_memory_limit();
674 707 }
675 708
@@ -683,11 +716,11 @@
683 716 }
684 717
685 718 $form_id = $form->id;
686 719 $form_cols = self::get_fields_for_csv_export( $form_id, $form );
720 + $item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
687 721
688 - $item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
689 - if ( ! empty( $item_id ) ) {
722 + if ( $item_id ) {
690 723 $item_id = explode( ',', $item_id );
691 724 }
692 725
693 726 $query = array(
@@ -708,12 +741,12 @@
708 741
709 742 $entry_ids = FrmDb::get_col( $wpdb->prefix . 'frm_items it', $query );
710 743 unset( $query );
711 744
712 - if ( empty( $entry_ids ) ) {
745 + if ( $entry_ids ) {
746 + FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
747 + } else {
713 748 esc_html_e( 'There are no entries for that form.', 'formidable' );
714 - } else {
715 - FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
716 749 }
717 750
718 751 wp_die();
719 752 }
@@ -726,13 +759,14 @@
726 759 *
727 760 * @param int $form_id
728 761 * @param object $form
729 762 *
730 - * @return array $csv_fields
763 + * @return array CSV fields.
731 764 */
732 765 public static function get_fields_for_csv_export( $form_id, $form ) {
733 766 $csv_fields = FrmField::get_all_for_form( $form_id, '', 'include', 'include' );
734 767 $no_export_fields = FrmField::no_save_fields();
768 +
735 769 foreach ( $csv_fields as $k => $f ) {
736 770 if ( in_array( $f->type, $no_export_fields, true ) ) {
737 771 unset( $csv_fields[ $k ] );
738 772 }
@@ -740,16 +774,21 @@
740 774
741 775 return apply_filters( 'frm_fields_for_csv_export', $csv_fields, compact( 'form' ) );
742 776 }
743 777
778 + /**
779 + * @param array $mimes
780 + *
781 + * @return array
782 + */
744 783 public static function allow_mime( $mimes ) {
745 784 if ( ! isset( $mimes['csv'] ) ) {
746 - // allow csv files
785 + // Allow csv files
747 786 $mimes['csv'] = 'text/csv';
748 787 }
749 788
750 789 if ( ! isset( $mimes['xml'] ) ) {
751 - // allow xml
790 + // Allow xml
752 791 $mimes['xml'] = 'text/xml';
753 792 }
754 793
755 794 return $mimes;