PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 2.05.09
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v2.05.09
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
formidable / classes / helpers / FrmCSVExportHelper.php

FrmCSVExportHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 2.05.09, at classes/helpers/FrmCSVExportHelper.php

322 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class FrmCSVExportHelper {
4
5 protected static $separator = ', ';
6 protected static $column_separator = ',';
7 protected static $line_break = 'return';
8 protected static $charset = 'UTF-8';
9 protected static $to_encoding = 'UTF-8';
10 protected static $wp_date_format = 'Y-m-d H:i:s';
11 protected static $comment_count = 0;
12 protected static $form_id = 0;
13 protected static $headings = array();
14 protected static $fields = array();
15 protected static $entry;
16
17 public static function csv_format_options() {
18 $formats = array( 'UTF-8', 'ISO-8859-1', 'windows-1256', 'windows-1251', 'macintosh' );
19 $formats = apply_filters( 'frm_csv_format_options', $formats );
20 return $formats;
21 }
22
23 public static function generate_csv( $atts ) {
24 global $frm_vars;
25 $frm_vars['prevent_caching'] = true;
26
27 self::$fields = $atts['form_cols'];
28 self::$form_id = $atts['form']->id;
29 self::set_class_paramters();
30
31 $filename = apply_filters( 'frm_csv_filename', date( 'ymdHis', time() ) . '_' . sanitize_title_with_dashes( $atts['form']->name ) . '_formidable_entries.csv', $atts['form'] );
32 unset( $atts['form'], $atts['form_cols'] );
33
34 self::print_file_headers( $filename );
35 unset( $filename );
36
37 $comment_count = FrmDb::get_count(
38 'frm_item_metas',
39 array(
40 'item_id' => $atts['entry_ids'],
41 'field_id' => 0,
42 'meta_value like' => '{',
43 ),
44 array(
45 'group_by' => 'item_id',
46 'order_by' => 'count(*) DESC',
47 'limit' => 1,
48 )
49 );
50 self::$comment_count = $comment_count;
51
52 self::prepare_csv_headings();
53
54 // fetch 20 posts at a time rather than loading the entire table into memory
55 while ( $next_set = array_splice( $atts['entry_ids'], 0, 20 ) ) {
56 self::prepare_next_csv_rows( $next_set );
57 }
58 }
59
60 private static function set_class_paramters() {
61 self::$separator = apply_filters( 'frm_csv_sep', self::$separator );
62 self::$line_break = apply_filters( 'frm_csv_line_break', self::$line_break );
63 self::$wp_date_format = apply_filters( 'frm_csv_date_format', self::$wp_date_format );
64 self::get_csv_format();
65 self::$charset = get_option( 'blog_charset' );
66
67 $col_sep = ( isset( $_POST['csv_col_sep'] ) && ! empty( $_POST['csv_col_sep'] ) ) ? sanitize_text_field( $_POST['csv_col_sep'] ) : self::$column_separator;
68 self::$column_separator = apply_filters( 'frm_csv_column_sep', $col_sep );
69 }
70
71 private static function print_file_headers( $filename ) {
72 header( 'Content-Description: File Transfer' );
73 header( 'Content-Disposition: attachment; filename="' . esc_attr( $filename ) . '"' );
74 header( 'Content-Type: text/csv; charset=' . self::$charset, true );
75 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', mktime( date( 'H' ) + 2, date( 'i' ), date( 's' ), date( 'm' ), date( 'd' ), date( 'Y' ) ) ) . ' GMT' );
76 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
77 header( 'Cache-Control: no-cache, must-revalidate' );
78 header( 'Pragma: no-cache' );
79
80 do_action( 'frm_csv_headers', array(
81 'form_id' => self::$form_id,
82 'fields' => self::$fields,
83 ) );
84 }
85
86 public static function get_csv_format() {
87 $csv_format = FrmAppHelper::get_post_param( 'csv_format', 'UTF-8', 'sanitize_text_field' );
88 $csv_format = apply_filters( 'frm_csv_format', $csv_format );
89 self::$to_encoding = $csv_format;
90 }
91
92 private static function prepare_csv_headings() {
93 $headings = array();
94 self::csv_headings( $headings );
95 $headings = apply_filters( 'frm_csv_columns', $headings, self::$form_id, array(
96 'fields' => self::$fields,
97 ) );
98 self::$headings = $headings;
99
100 self::print_csv_row( $headings );
101 }
102
103 private static function csv_headings( &$headings ) {
104 foreach ( self::$fields as $col ) {
105 $field_headings = array();
106 if ( isset( $col->field_options['separate_value'] ) && $col->field_options['separate_value'] && ! in_array( $col->type, array( 'user_id', 'file', 'data', 'date' ), true ) ) {
107 $field_headings[ $col->id . '_label' ] = strip_tags( $col->name . ' ' . __( '(label)', 'formidable' ) );
108 }
109
110 $field_headings[ $col->id ] = strip_tags( $col->name );
111 $field_headings = apply_filters( 'frm_csv_field_columns', $field_headings, array(
112 'field' => $col,
113 ) );
114 $headings += $field_headings;
115 }
116
117 if ( self::$comment_count ) {
118 for ( $i = 0; $i < self::$comment_count; $i++ ) {
119 $headings[ 'comment' . $i ] = __( 'Comment', 'formidable' );
120 $headings[ 'comment_user_id' . $i ] = __( 'Comment User', 'formidable' );
121 $headings[ 'comment_created_at' . $i ] = __( 'Comment Date', 'formidable' );
122 }
123 unset( $i );
124 }
125
126 $headings['created_at'] = __( 'Timestamp', 'formidable' );
127 $headings['updated_at'] = __( 'Last Updated', 'formidable' );
128 $headings['user_id'] = __( 'Created By', 'formidable' );
129 $headings['updated_by'] = __( 'Updated By', 'formidable' );
130 $headings['is_draft'] = __( 'Draft', 'formidable' );
131 $headings['ip'] = __( 'IP', 'formidable' );
132 $headings['id'] = __( 'ID', 'formidable' );
133 $headings['item_key'] = __( 'Key', 'formidable' );
134 }
135
136 private static function prepare_next_csv_rows( $next_set ) {
137 // order by parent_item_id so children will be first
138 $where = array(
139 'or' => 1,
140 'id' => $next_set,
141 'parent_item_id' => $next_set,
142 );
143 $entries = FrmEntry::getAll( $where, ' ORDER BY parent_item_id DESC', '', true, false );
144
145 foreach ( $entries as $k => $entry ) {
146 self::$entry = $entry;
147 unset( $entry );
148
149 if ( self::$entry->form_id !== self::$form_id ) {
150 self::add_repeat_field_values_to_csv( $entries );
151 } else {
152 self::prepare_csv_row();
153 }
154 }
155 }
156
157 private static function prepare_csv_row() {
158 $row = array();
159 self::add_field_values_to_csv( $row );
160 self::add_entry_data_to_csv( $row );
161 $row = apply_filters( 'frm_csv_row', $row, array(
162 'entry' => self::$entry,
163 'date_format' => self::$wp_date_format,
164 'comment_count' => self::$comment_count,
165 ) );
166 self::print_csv_row( $row );
167 }
168
169 private static function add_repeat_field_values_to_csv( &$entries ) {
170 if ( isset( self::$entry->metas ) ) {
171 // add child entries to the parent
172 foreach ( self::$entry->metas as $meta_id => $meta_value ) {
173 if ( ! is_numeric( $meta_id ) || '' === $meta_value ) {
174 // if the hook is being used to include field keys in the metas array,
175 // we need to skip the keys and only process field ids
176 continue;
177 }
178
179 if ( ! isset( $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] ) ) {
180 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] = array();
181 } elseif ( ! is_array( $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] ) ) {
182 // if the data is here, it should be an array but if this field has collected data
183 // both while inside and outside of the repeating section, it's possible this is a string
184 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ] = (array) $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ];
185 }
186
187 //add the repeated values
188 $entries[ self::$entry->parent_item_id ]->metas[ $meta_id ][] = $meta_value;
189 }
190 $entries[ self::$entry->parent_item_id ]->metas += self::$entry->metas;
191 }
192
193 // add the embedded form id
194 if ( ! isset( $entries[ self::$entry->parent_item_id ]->embedded_fields ) ) {
195 $entries[ self::$entry->parent_item_id ]->embedded_fields = array();
196 }
197 $entries[ self::$entry->parent_item_id ]->embedded_fields[ self::$entry->id ] = self::$entry->form_id;
198 }
199
200 private static function add_field_values_to_csv( &$row ) {
201 foreach ( self::$fields as $col ) {
202 $field_value = isset( self::$entry->metas[ $col->id ] ) ? self::$entry->metas[ $col->id ] : false;
203
204 $field_value = maybe_unserialize( $field_value );
205 self::add_array_values_to_columns( $row, compact( 'col', 'field_value' ) );
206
207 $field_value = apply_filters( 'frm_csv_value', $field_value, array(
208 'field' => $col,
209 'entry' => self::$entry,
210 'separator' => self::$separator,
211 ) );
212
213 if ( isset( $col->field_options['separate_value'] ) && $col->field_options['separate_value'] ) {
214 $sep_value = FrmEntriesHelper::display_value( $field_value, $col, array(
215 'type' => $col->type,
216 'post_id' => self::$entry->post_id,
217 'show_icon' => false,
218 'entry_id' => self::$entry->id,
219 'sep' => self::$separator,
220 '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,
221 ) );
222 $row[ $col->id . '_label' ] = $sep_value;
223 unset( $sep_value );
224 }
225
226 $row[ $col->id ] = $field_value;
227
228 unset( $col, $field_value );
229 }
230 }
231
232 /**
233 * @since 2.0.23
234 */
235 private static function add_array_values_to_columns( &$row, $atts ) {
236 if ( is_array( $atts['field_value'] ) ) {
237 foreach ( $atts['field_value'] as $key => $sub_value ) {
238 $column_key = $atts['col']->id . '_' . $key;
239 if ( ! is_numeric( $key ) && isset( self::$headings[ $column_key ] ) ) {
240 $row[ $column_key ] = $sub_value;
241 }
242 }
243 }
244 }
245
246 private static function add_entry_data_to_csv( &$row ) {
247 $row['created_at'] = FrmAppHelper::get_formatted_time( self::$entry->created_at, self::$wp_date_format, ' ' );
248 $row['updated_at'] = FrmAppHelper::get_formatted_time( self::$entry->updated_at, self::$wp_date_format, ' ' );
249 $row['user_id'] = self::$entry->user_id;
250 $row['updated_by'] = self::$entry->updated_by;
251 $row['is_draft'] = self::$entry->is_draft ? '1' : '0';
252 $row['ip'] = self::$entry->ip;
253 $row['id'] = self::$entry->id;
254 $row['item_key'] = self::$entry->item_key;
255 }
256
257 private static function print_csv_row( $rows ) {
258 $sep = '';
259
260 foreach ( self::$headings as $k => $heading ) {
261 $row = isset( $rows[ $k ] ) ? $rows[ $k ] : '';
262 if ( is_array( $row ) ) {
263 // implode the repeated field values
264 $row = implode( self::$separator, FrmAppHelper::array_flatten( $row, 'reset' ) );
265 }
266
267 $val = self::encode_value( $row );
268 if ( 'return' !== self::$line_break ) {
269 $val = str_replace( array( "\r\n", "\r", "\n" ), self::$line_break, $val );
270 }
271
272 echo $sep . '"' . $val . '"';
273 $sep = self::$column_separator;
274
275 unset( $k, $row );
276 }
277 echo "\n";
278 }
279
280 public static function encode_value( $line ) {
281 if ( '' === $line ) {
282 return $line;
283 }
284
285 $convmap = false;
286
287 switch ( self::$to_encoding ) {
288 case 'macintosh':
289 // this map was derived from the differences between the MacRoman and UTF-8 Charsets
290 // Reference:
291 // - http://www.alanwood.net/demos/macroman.html
292 $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 );
293 break;
294 case 'ISO-8859-1':
295 $convmap = array( 256, 10000, 0, 0xffff );
296 }
297
298 if ( is_array( $convmap ) ) {
299 $line = mb_encode_numericentity( $line, $convmap, self::$charset );
300 }
301
302 if ( self::$to_encoding !== self::$charset ) {
303 $line = iconv( self::$charset, self::$to_encoding . '//IGNORE', $line );
304 }
305
306 return self::escape_csv( $line );
307 }
308
309 /**
310 * Escape a " in a csv with another "
311 * @since 2.0
312 */
313 public static function escape_csv( $value ) {
314 if ( '=' === $value[0] ) {
315 // escape the = to prevent vulnerability
316 $value = "'" . $value;
317 }
318 $value = str_replace( '"', '""', $value );
319 return $value;
320 }
321 }
322