PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.1
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/helpers/FrmCSVExportHelper.php +53 -150 6.255.1 View file →
@@ -5,120 +5,94 @@
5 5
6 6 class FrmCSVExportHelper {
7 7
8 8 /**
9 - * @var string
9 + * @var string $separator
10 10 */
11 11 protected static $separator = ', ';
12 12
13 13 /**
14 - * @var string
14 + * @var string $column_separator
15 15 */
16 16 protected static $column_separator = ',';
17 17
18 18 /**
19 - * @var string
19 + * @var string $line_break
20 20 */
21 21 protected static $line_break = 'return';
22 22
23 23 /**
24 - * @var string
24 + * @var string $charset
25 25 */
26 26 protected static $charset = 'UTF-8';
27 27
28 28 /**
29 - * @var string
29 + * @var string $to_encoding
30 30 */
31 31 protected static $to_encoding = 'UTF-8';
32 32
33 33 /**
34 - * @var string
34 + * @var string $wp_date_format
35 35 */
36 36 protected static $wp_date_format = 'Y-m-d H:i:s';
37 37
38 38 /**
39 - * @var int
39 + * @var int $comment_count
40 40 */
41 41 protected static $comment_count = 0;
42 42
43 43 /**
44 - * @var int
44 + * @var int $form_id
45 45 */
46 46 protected static $form_id = 0;
47 47
48 48 /**
49 - * @var array
49 + * @var array $headings
50 50 */
51 51 protected static $headings = array();
52 52
53 53 /**
54 - * @var array
54 + * @var array $fields
55 55 */
56 56 protected static $fields = array();
57 57
58 58 /**
59 - * @var stdClass|null
59 + * @var stdClass|null $entry
60 60 */
61 61 protected static $entry;
62 62
63 63 /**
64 - * @var bool|null
64 + * @var bool|null $has_parent_id
65 65 */
66 66 protected static $has_parent_id;
67 67
68 68 /**
69 - * @var array|null
69 + * @var array|null $fields_by_repeater_id
70 70 */
71 71 protected static $fields_by_repeater_id;
72 72
73 73 /**
74 - * @var string either 'echo' or 'file' are supported.
74 + * @var string $mode either 'echo' or 'file' are supported.
75 75 */
76 76 protected static $mode = 'echo';
77 77
78 78 /**
79 - * @var resource|null used to write a CSV file in file mode.
79 + * @var resource|null $fp used to write a CSV file in file mode.
80 80 */
81 81 protected static $fp;
82 82
83 83 /**
84 - * @var string the context of the CSV being generated. Possible values include 'email' when used as an email attachment, or 'default'.
84 + * @var string $context the context of the CSV being generated. Possible values include 'email' when used as an email attachment, or 'default'.
85 85 */
86 86 protected static $context = 'default';
87 87
88 88 /**
89 - * @var array
89 + * @var array $meta
90 90 */
91 91 protected static $meta = array();
92 92
93 - /**
94 - * Whether to include the BOM (Byte Order Mark) in the CSV file.
95 - * Only applicable for UTF-8 exports.
96 - *
97 - * @since 6.17
98 - *
99 - * @var bool
100 - */
101 - private static $include_bom = false;
102 -
103 - /**
104 - * Get all options for the CSV export format dropdown.
105 - *
106 - * @since 6.17 The UTF-8 with BOM option was added.
107 - *
108 - * @return array
109 - */
110 93 public static function csv_format_options() {
111 94 $formats = array( 'UTF-8', 'ISO-8859-1', 'windows-1256', 'windows-1251', 'macintosh' );
112 -
113 - // Do not add the UTF-8 with BOM option if this function is called on Global Settings.
114 - // This is to improve compatibility with the Export View as CSV add-on (v1.10).
115 - // Otherwise, the option will appear twice since it is added in the add-on as well.
116 - $on_global_settings_page = 'formidable-settings' === FrmAppHelper::get_param( 'page' );
117 - if ( ! $on_global_settings_page ) {
118 - array_splice( $formats, 1, 0, 'UTF-8 with BOM' );
119 - }
120 -
121 95 $formats = apply_filters( 'frm_csv_format_options', $formats );
122 96
123 97 return $formats;
124 98 }
@@ -124,9 +98,9 @@
124 98 }
125 99
126 100 /**
127 101 * @param array $atts
128 - * @return false|string|null returns a string file path or false if $atts['mode'] is set to 'file'.
102 + * @return string|false|void returns a string file path or false if $atts['mode'] is set to 'file'.
129 103 */
130 104 public static function generate_csv( $atts ) {
131 105 global $frm_vars;
132 106 $frm_vars['prevent_caching'] = true;
@@ -140,8 +114,9 @@
140 114 self::set_class_parameters();
141 115 self::set_has_parent_id( $atts['form'] );
142 116
143 117 $filename = self::generate_csv_filename( $atts['form'] );
118 + unset( $atts['form'], $atts['form_cols'] );
144 119
145 120 if ( 'file' === self::$mode ) {
146 121 $filepath = get_temp_dir() . $filename;
147 122 self::$fp = @fopen( $filepath, 'w' );
@@ -158,9 +133,9 @@
158 133 'frm_item_metas',
159 134 array(
160 135 'item_id' => $atts['entry_ids'],
161 136 'field_id' => 0,
162 - 'meta_value like' => 's:7:"comment";',
137 + 'meta_value like' => '{',
163 138 ),
164 139 array(
165 140 'group_by' => 'item_id',
166 141 'order_by' => 'count(*) DESC',
@@ -170,56 +145,20 @@
170 145 self::$comment_count = $comment_count;
171 146
172 147 self::prepare_csv_headings();
173 148
174 - /**
175 - * For a target form with 50k entries (Locations List, with 7 fields), batch sizes of 100
176 - * were significantly faster and used less memory, so a filter was added.
177 - *
178 - * @since 6.17
179 - *
180 - * @param int $batch_size
181 - * @param int $form_id
182 - */
183 - $csv_export_batch_size = (int) apply_filters( 'frm_csv_export_batch_size', 20, self::$form_id );
184 -
185 - // Fetch posts in batches rather than loading the entire table into memory.
186 - while ( $next_set = array_splice( $atts['entry_ids'], 0, $csv_export_batch_size ) ) {
149 + // fetch 20 posts at a time rather than loading the entire table into memory
150 + while ( $next_set = array_splice( $atts['entry_ids'], 0, 20 ) ) {
187 151 self::prepare_next_csv_rows( $next_set );
188 152 }
189 153
190 - self::after_generate_csv( $atts );
191 -
192 - unset( $atts['form'], $atts['form_cols'] );
193 -
194 154 if ( 'file' === self::$mode ) {
195 155 fclose( self::$fp );
196 156 return $filepath;
197 157 }
198 -
199 - return null;
200 158 }
201 159
202 160 /**
203 - * @since 6.8.4
204 - *
205 - * @param array $atts
206 - * @return void
207 - */
208 - private static function after_generate_csv( $atts ) {
209 - /**
210 - * @since 6.8.4
211 - *
212 - * @param array $atts {
213 - * @type object $form
214 - * @type array $entry_ids
215 - * @type array $form_cols
216 - * }
217 - */
218 - do_action( 'frm_after_generate_csv', $atts );
219 - }
220 -
221 - /**
222 161 * @since 5.0.16
223 162 *
224 163 * @param stdClass $form
225 164 * @return string
@@ -266,12 +205,8 @@
266 205 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
267 206 header( 'Cache-Control: no-cache, must-revalidate' );
268 207 header( 'Pragma: no-cache' );
269 208
270 - if ( self::$include_bom ) {
271 - echo esc_html( chr( 239 ) . chr( 187 ) . chr( 191 ) );
272 - }
273 -
274 209 do_action(
275 210 'frm_csv_headers',
276 211 array(
277 212 'form_id' => self::$form_id,
@@ -279,21 +214,10 @@
279 214 )
280 215 );
281 216 }
282 217
283 - /**
284 - * Check the POST request data for the CSV format to use.
285 - *
286 - * @return void
287 - */
288 218 public static function get_csv_format() {
289 - $csv_format = FrmAppHelper::get_post_param( 'csv_format', 'UTF-8', 'sanitize_text_field' );
290 -
291 - if ( 'UTF-8 with BOM' === $csv_format ) {
292 - self::$include_bom = true;
293 - $csv_format = 'UTF-8';
294 - }
295 -
219 + $csv_format = FrmAppHelper::get_post_param( 'csv_format', 'UTF-8', 'sanitize_text_field' );
296 220 $csv_format = apply_filters( 'frm_csv_format', $csv_format, self::get_standard_filter_args() );
297 221 self::$to_encoding = $csv_format;
298 222 }
299 223
@@ -315,10 +239,9 @@
315 239 }
316 240
317 241 private static function field_headings( $col ) {
318 242 $field_type_obj = FrmFieldFactory::get_field_factory( $col );
319 - if ( ! empty( $field_type_obj->is_combo_field ) ) {
320 - // This is combo field.
243 + if ( ! empty( $field_type_obj->is_combo_field ) ) { // This is combo field.
321 244 return $field_type_obj->get_export_headings();
322 245 }
323 246
324 247 $field_headings = array();
@@ -345,11 +268,10 @@
345 268 $repeater_ids = array();
346 269
347 270 foreach ( self::$fields as $col ) {
348 271 if ( self::is_the_child_of_a_repeater( $col ) ) {
349 - $repeater_id = $col->field_options['in_section'];
350 - // Set a placeholder to maintain order for repeater fields.
351 - $headings[ 'repeater' . $repeater_id ] = array();
272 + $repeater_id = $col->field_options['in_section'];
273 + $headings[ 'repeater' . $repeater_id ] = array(); // set a placeholder to maintain order for repeater fields
352 274
353 275 if ( ! isset( $fields_by_repeater_id[ $repeater_id ] ) ) {
354 276 $fields_by_repeater_id[ $repeater_id ] = array();
355 277 $repeater_ids[] = $repeater_id;
@@ -389,9 +311,9 @@
389 311 foreach ( $fields_by_repeater_id[ $repeater_id ] as $col ) {
390 312 $repeater_headings += self::field_headings( $col );
391 313 }
392 314
393 - for ( $i = 0; $i < $max[ $repeater_id ]; $i++ ) {
315 + for ( $i = 0; $i < $max[ $repeater_id ]; $i ++ ) {
394 316 foreach ( $repeater_headings as $repeater_key => $repeater_name ) {
395 317 $flat[ $repeater_key . '[' . $i . ']' ] = $repeater_name;
396 318 }
397 319 }
@@ -405,12 +327,12 @@
405 327 unset( $key, $heading, $max, $repeater_headings, $repeater_id, $fields_by_repeater_id );
406 328
407 329 $headings = $flat;
408 330 unset( $flat );
409 - }//end if
331 + }
410 332
411 333 if ( self::$comment_count ) {
412 - for ( $i = 0; $i < self::$comment_count; $i++ ) {
334 + for ( $i = 0; $i < self::$comment_count; $i ++ ) {
413 335 $headings[ 'comment' . $i ] = __( 'Comment', 'formidable' );
414 336 $headings[ 'comment_user_id' . $i ] = __( 'Comment User', 'formidable' );
415 337 $headings[ 'comment_created_at' . $i ] = __( 'Comment Date', 'formidable' );
416 338 }
@@ -420,9 +342,9 @@
420 342 $headings['created_at'] = __( 'Timestamp', 'formidable' );
421 343 $headings['updated_at'] = __( 'Last Updated', 'formidable' );
422 344 $headings['user_id'] = __( 'Created By', 'formidable' );
423 345 $headings['updated_by'] = __( 'Updated By', 'formidable' );
424 - $headings['is_draft'] = __( 'Entry Status', 'formidable' );
346 + $headings['is_draft'] = __( 'Draft', 'formidable' );
425 347 $headings['ip'] = __( 'IP', 'formidable' );
426 348 $headings['id'] = __( 'ID', 'formidable' );
427 349 $headings['item_key'] = __( 'Key', 'formidable' );
428 350 if ( self::has_parent_id() ) {
@@ -455,28 +377,17 @@
455 377 return self::$has_parent_id;
456 378 }
457 379
458 380 private static function prepare_next_csv_rows( $next_set ) {
459 - if ( FrmAppHelper::pro_is_installed() ) {
460 - $where = array(
461 - 'or' => 1,
462 - 'id' => $next_set,
463 - 'parent_item_id' => $next_set,
464 - );
465 - // Order by parent_item_id so children will be first.
466 - $order_by = ' ORDER BY parent_item_id DESC';
467 - } else {
468 - // When Pro is not installed, only query for direct ID matches only as we do not expect parent item id
469 - // matches and the more simplified query is faster.
470 - $where = array(
471 - 'id' => $next_set,
472 - );
473 - $order_by = '';
474 - }
381 + // order by parent_item_id so children will be first
382 + $where = array(
383 + 'or' => 1,
384 + 'id' => $next_set,
385 + 'parent_item_id' => $next_set,
386 + );
387 + $entries = FrmEntry::getAll( $where, ' ORDER BY parent_item_id DESC', '', true, false );
475 388
476 - $entries = FrmEntry::getAll( $where, $order_by, '', true, false );
477 -
478 - foreach ( $entries as $entry ) {
389 + foreach ( $entries as $k => $entry ) {
479 390 self::$entry = $entry;
480 391 unset( $entry );
481 392
482 393 if ( self::$entry->form_id !== self::$form_id ) {
@@ -522,19 +433,19 @@
522 433 if ( ! isset( $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] ) ) {
523 434 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] = array();
524 435 } elseif ( ! is_array( $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] ) ) {
525 436 // if the data is here, it should be an array but if this field has collected data
526 - // both while inside and outside of the repeating section, it's possible this is a string.
437 + // both while inside and outside of the repeating section, it's possible this is a string
527 438 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] = (array) $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ];
528 439 }
529 440
530 - // Add the repeated values.
441 + //add the repeated values
531 442 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ][] = $meta_value;
532 - }//end foreach
443 + }
533 444
534 445 self::$entry->metas = self::fill_missing_repeater_metas( self::$entry->metas, $entries );
535 446 $entries[ self::$entry->parent_item_id ]->metas += self::$entry->metas;
536 - }//end if
447 + }
537 448
538 449 // add the embedded form id
539 450 if ( ! isset( $entries[ self::$entry->parent_item_id ]->embedded_fields ) ) {
540 451 $entries[ self::$entry->parent_item_id ]->embedded_fields = array();
@@ -565,14 +476,9 @@
565 476 }
566 477
567 478 foreach ( self::$fields_by_repeater_id[ $repeater_id ] as $repeater_child ) {
568 479 if ( ! isset( $metas[ $repeater_child->id ] ) ) {
569 - $metas[ $repeater_child->id ] = '';
570 -
571 - if ( ! isset( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) || ! is_array( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) ) {
572 - $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] = array();
573 - }
574 -
480 + $metas[ $repeater_child->id ] = '';
575 481 $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ][] = '';
576 482 }
577 483 }
578 484
@@ -590,11 +496,11 @@
590 496 }
591 497
592 498 private static function add_field_values_to_csv( &$row ) {
593 499 foreach ( self::$fields as $col ) {
594 - $field_value = self::$entry->metas[ $col->id ] ?? false;
500 + $field_value = isset( self::$entry->metas[ $col->id ] ) ? self::$entry->metas[ $col->id ] : false;
595 501
596 - FrmFieldsHelper::prepare_field_value( $field_value, $col->type );
502 + FrmAppHelper::unserialize_or_decode( $field_value );
597 503 self::add_array_values_to_columns( $row, compact( 'col', 'field_value' ) );
598 504
599 505 $field_value = apply_filters(
600 506 'frm_csv_value',
@@ -610,13 +516,10 @@
610 516 if ( ! empty( $col->field_options['separate_value'] ) ) {
611 517 $label_key = $col->id . '_label';
612 518 if ( self::is_the_child_of_a_repeater( $col ) ) {
613 519 $row[ $label_key ] = array();
614 -
615 - if ( is_array( $field_value ) ) {
616 - foreach ( $field_value as $value ) {
617 - $row[ $label_key ][] = self::get_separate_value_label( $value, $col );
618 - }
520 + foreach ( $field_value as $value ) {
521 + $row[ $label_key ][] = self::get_separate_value_label( $value, $col );
619 522 }
620 523 } else {
621 524 $row[ $label_key ] = self::get_separate_value_label( $field_value, $col );
622 525 }
@@ -625,9 +528,9 @@
625 528
626 529 $row[ $col->id ] = $field_value;
627 530
628 531 unset( $col, $field_value );
629 - }//end foreach
532 + }
630 533 }
631 534
632 535 /**
633 536 * @since 5.0.06
@@ -645,9 +548,9 @@
645 548 'post_id' => self::$entry->post_id,
646 549 'show_icon' => false,
647 550 'entry_id' => self::$entry->id,
648 551 'sep' => self::$separator,
649 - 'embedded_field_id' => isset( self::$entry->embedded_fields ) && isset( self::$entry->embedded_fields[ self::$entry->id ] ) ? 'form' . self::$entry->embedded_fields[ self::$entry->id ] : 0,
552 + 'embedded_field_id' => ( isset( self::$entry->embedded_fields ) && isset( self::$entry->embedded_fields[ self::$entry->id ] ) ) ? 'form' . self::$entry->embedded_fields[ self::$entry->id ] : 0,
650 553 )
651 554 );
652 555 }
653 556
@@ -681,9 +584,9 @@
681 584 $row['created_at'] = FrmAppHelper::get_formatted_time( self::$entry->created_at, self::$wp_date_format, ' ' );
682 585 $row['updated_at'] = FrmAppHelper::get_formatted_time( self::$entry->updated_at, self::$wp_date_format, ' ' );
683 586 $row['user_id'] = self::$entry->user_id;
684 587 $row['updated_by'] = self::$entry->updated_by;
685 - $row['is_draft'] = self::$entry->is_draft;
588 + $row['is_draft'] = self::$entry->is_draft ? '1' : '0';
686 589 $row['ip'] = self::$entry->ip;
687 590 $row['id'] = self::$entry->id;
688 591 $row['item_key'] = self::$entry->item_key;
689 592 if ( self::has_parent_id() ) {
@@ -702,9 +605,9 @@
702 605 $row = '';
703 606 // array indexed data is not at $rows[ $k ]
704 607 if ( $k[ strlen( $k ) - 1 ] === ']' ) {
705 608 $start = strrpos( $k, '[' );
706 - $key = substr( $k, 0, $start++ );
609 + $key = substr( $k, 0, $start ++ );
707 610 $index = substr( $k, $start, strlen( $k ) - 1 - $start );
708 611
709 612 if ( isset( $rows[ $key ] ) && isset( $rows[ $key ][ $index ] ) ) {
710 613 $row = $rows[ $key ][ $index ];
@@ -731,9 +634,9 @@
731 634 }
732 635 $sep = self::$column_separator;
733 636
734 637 unset( $k, $row );
735 - }//end foreach
638 + }
736 639 if ( $echo ) {
737 640 echo "\n";
738 641 } else {
739 642 fwrite( self::$fp, "\n" );
@@ -750,9 +653,9 @@
750 653 switch ( self::$to_encoding ) {
751 654 case 'macintosh':
752 655 // this map was derived from the differences between the MacRoman and UTF-8 Charsets
753 656 // Reference:
754 - // http://www.alanwood.net/demos/macroman.html.
657 + // - http://www.alanwood.net/demos/macroman.html
755 658 $convmap = array( 256, 304, 0, 0xffff, 306, 337, 0, 0xffff, 340, 375, 0, 0xffff, 377, 401, 0, 0xffff, 403, 709, 0, 0xffff, 712, 727, 0, 0xffff, 734, 936, 0, 0xffff, 938, 959, 0, 0xffff, 961, 8210, 0, 0xffff, 8213, 8215, 0, 0xffff, 8219, 8219, 0, 0xffff, 8227, 8229, 0, 0xffff, 8231, 8239, 0, 0xffff, 8241, 8248, 0, 0xffff, 8251, 8259, 0, 0xffff, 8261, 8363, 0, 0xffff, 8365, 8481, 0, 0xffff, 8483, 8705, 0, 0xffff, 8707, 8709, 0, 0xffff, 8711, 8718, 0, 0xffff, 8720, 8720, 0, 0xffff, 8722, 8729, 0, 0xffff, 8731, 8733, 0, 0xffff, 8735, 8746, 0, 0xffff, 8748, 8775, 0, 0xffff, 8777, 8799, 0, 0xffff, 8801, 8803, 0, 0xffff, 8806, 9673, 0, 0xffff, 9675, 63742, 0, 0xffff, 63744, 64256, 0, 0xffff );
756 659 break;
757 660 case 'ISO-8859-1':
758 661 $convmap = array( 256, 10000, 0, 0xffff );