PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.22.0
GiveWP – Donation Plugin and Fundraising Platform v3.22.0
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / admin / tools / export / give-export-donations-exporter.php
give / includes / admin / tools / export Last commit date
class-batch-export-donors.php 5 years ago class-batch-export.php 4 years ago class-core-settings-export.php 7 years ago class-export-earnings.php 3 years ago class-export.php 3 years ago class-give-export-donations.php 5 years ago export-actions.php 3 years ago export-functions.php 2 years ago give-export-donations-exporter.php 1 year ago give-export-donations-functions.php 2 years ago pdf-reports.php 5 years ago
give-export-donations-exporter.php
704 lines
1 <?php
2 /**
3 * Payments Export Class.
4 *
5 * This class handles payment export in batches.
6 *
7 * @package Give
8 * @subpackage Admin/Reports
9 * @copyright Copyright (c) 2016, GiveWP
10 * @license https://opensource.org/licenses/gpl-license GNU Public License
11 * @since 2.1
12 */
13
14 // Exit if accessed directly.
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 /**
20 * Give_Export_Donations_CSV Class
21 *
22 * @since 2.1
23 */
24 class Give_Export_Donations_CSV extends Give_Batch_Export {
25
26 /**
27 * Our export type. Used for export-type specific filters/actions.
28 *
29 * @since 2.1
30 *
31 * @var string
32 */
33 public $export_type = 'payments';
34
35 /**
36 * Form submission data.
37 *
38 * @since 2.1
39 *
40 * @var array
41 */
42 public $data = array();
43
44 /**
45 * Form submission data.
46 *
47 * @since 2.1
48 *
49 * @var array
50 */
51 public $cols = array();
52
53 /**
54 * Form ID.
55 *
56 * @since 2.1
57 *
58 * @var string
59 */
60 public $form_id = '';
61
62 /**
63 * Form tags ids.
64 *
65 * @since 2.1
66 *
67 * @var array
68 */
69 public $tags = '';
70
71
72 /**
73 * Form categories ids.
74 *
75 * @since 2.1
76 *
77 * @var array
78 */
79 public $categories = '';
80
81 /**
82 * Set the properties specific to the export.
83 *
84 * @since 2.1
85 *
86 * @param array $request The Form Data passed into the batch processing.
87 */
88 public function set_properties( $request ) {
89
90 // Set data from form submission
91 if ( isset( $_POST['form'] ) ) {
92 $this->data = give_clean( wp_parse_args( $_POST['form'] ) );
93 }
94
95 $this->form = $this->data['forms'];
96 $this->categories = ! empty( $request['give_forms_categories'] ) ? (array) $request['give_forms_categories'] : array();
97 $this->tags = ! empty( $request['give_forms_tags'] ) ? (array) $request['give_forms_tags'] : array();
98 $this->form_id = $this->get_form_ids( $request );
99 $this->price_id = isset( $request['give_price_option'] ) && ! in_array( $this->price_id, array( 'all', '' ) ) ? absint( $request['give_price_option'] ) : null;
100 $this->start = ! empty( $request['start'] ) ? date( 'Y-m-d', strtotime( $request['start'] ) ) : '';
101 $this->end = ! empty( $request['end'] ) ? date( 'Y-m-d', strtotime( $request['end'] ) ) : '';
102 $this->status = isset( $request['status'] ) ? sanitize_text_field( $request['status'] ) : 'complete';
103
104 /**
105 * Hook to use after setting properties.
106 *
107 * @since 2.1.3
108 */
109 do_action( 'give_export_donations_form_data', $this->data );
110 }
111
112 /**
113 * Get donation form id list
114 *
115 * @since 2.1
116 *
117 * @param array $request form data that need to be exported
118 *
119 * @return array|boolean|null $form get all the donation id that need to be exported
120 */
121 public function get_form_ids( $request = array() ) {
122 $form = ! empty( $request['forms'] ) && 0 !== $request['forms'] ? absint( $request['forms'] ) : null;
123
124 $form_ids = ! empty( $request['form_ids'] ) ? sanitize_text_field( $request['form_ids'] ) : null;
125
126 if ( empty( $form ) && ! empty( $form_ids ) && ( ! empty( $this->categories ) || ! empty( $this->tags ) ) ) {
127 $form = explode( ',', $form_ids );
128 }
129
130 return $form;
131 }
132
133 /**
134 * Set the CSV columns.
135 *
136 * @access public
137 *
138 * @since 2.1
139 *
140 * @return array|bool $cols All the columns.
141 */
142 public function csv_cols() {
143
144 $columns = isset( $this->data['give_give_donations_export_option'] ) ? $this->data['give_give_donations_export_option'] : array();
145
146 // We need columns.
147 if ( empty( $columns ) ) {
148 return false;
149 }
150
151 $this->cols = $this->get_cols( $columns );
152
153 return $this->cols;
154 }
155
156
157 /**
158 * CSV file columns.
159 *
160 * @since 3.12.1 add phone column.
161 * @since 2.1
162 *
163 * @param array $columns
164 *
165 * @return array
166 */
167 private function get_cols( $columns ) {
168
169 $cols = array();
170
171 foreach ( $columns as $key => $value ) {
172
173 switch ( $key ) {
174 case 'donation_id':
175 $cols['donation_id'] = __( 'Donation ID', 'give' );
176 break;
177 case 'seq_id':
178 $cols['seq_id'] = __( 'Donation Number', 'give' );
179 break;
180 case 'title_prefix':
181 $cols['title_prefix'] = __( 'Title Prefix', 'give' );
182 break;
183 case 'first_name':
184 $cols['first_name'] = __( 'First Name', 'give' );
185 break;
186 case 'last_name':
187 $cols['last_name'] = __( 'Last Name', 'give' );
188 break;
189 case 'email':
190 $cols['email'] = __( 'Email Address', 'give' );
191 break;
192 case 'company':
193 $cols['company'] = __( 'Company Name', 'give' );
194 break;
195 case 'address':
196 $cols['address_line1'] = __( 'Address 1', 'give' );
197 $cols['address_line2'] = __( 'Address 2', 'give' );
198 $cols['address_city'] = __( 'City', 'give' );
199 $cols['address_state'] = __( 'State', 'give' );
200 $cols['address_zip'] = __( 'Zip', 'give' );
201 $cols['address_country'] = __( 'Country', 'give' );
202 break;
203 case 'phone':
204 $cols['phone'] = __( 'Donor Phone Number', 'give' );
205 break;
206 case 'comment':
207 $cols['comment'] = __( 'Donor Comment', 'give' );
208 break;
209 case 'donation_total':
210 $cols['donation_total'] = __( 'Donation Total', 'give' );
211 break;
212 case 'currency_code':
213 $cols['currency_code'] = __( 'Currency Code', 'give' );
214 break;
215 case 'currency_symbol':
216 $cols['currency_symbol'] = __( 'Currency Symbol', 'give' );
217 break;
218 case 'donation_status':
219 $cols['donation_status'] = __( 'Donation Status', 'give' );
220 break;
221 case 'payment_gateway':
222 $cols['payment_gateway'] = __( 'Payment Gateway', 'give' );
223 break;
224 case 'payment_mode':
225 $cols['payment_mode'] = __( 'Payment Mode', 'give' );
226 break;
227 case 'form_id':
228 $cols['form_id'] = __( 'Form ID', 'give' );
229 break;
230 case 'form_title':
231 $cols['form_title'] = __( 'Form Title', 'give' );
232 break;
233 case 'form_level_id':
234 $cols['form_level_id'] = __( 'Level ID', 'give' );
235 break;
236 case 'form_level_title':
237 $cols['form_level_title'] = __( 'Level Title', 'give' );
238 break;
239 case 'donation_date':
240 $cols['donation_date'] = __( 'Donation Date', 'give' );
241 break;
242 case 'donation_time':
243 $cols['donation_time'] = __( 'Donation Time', 'give' );
244 break;
245 case 'userid':
246 $cols['userid'] = __( 'User ID', 'give' );
247 break;
248 case 'donorid':
249 $cols['donorid'] = __( 'Donor ID', 'give' );
250 break;
251 case 'donor_ip':
252 $cols['donor_ip'] = __( 'Donor IP Address', 'give' );
253 break;
254 case 'donation_note_private':
255 $cols['donation_note_private'] = __( 'Donation Note (private)', 'give' );
256 break;
257 case 'donation_note_to_donor':
258 $cols['donation_note_to_donor'] = __( 'Donation Note (to donor)', 'give' );
259 break;
260 default:
261 $cols[ $key ] = $key;
262
263 }
264 }
265
266 /**
267 * Filter to get columns name when exporting donation
268 *
269 * @since 2.1
270 *
271 * @param array $cols columns name for CSV
272 * @param array $columns columns select by admin to export
273 */
274 return (array) apply_filters( 'give_export_donation_get_columns_name', $cols, $columns );
275 }
276
277 /**
278 * Get the donation argument
279 *
280 * @since 2.1
281 *
282 * @param array $args donation argument
283 *
284 * @return array $args donation argument
285 */
286 public function get_donation_argument( $args = array() ) {
287 $defaults = array(
288 'number' => 30,
289 'page' => $this->step,
290 'status' => $this->status,
291 'order' => 'ASC',
292 );
293 // Date query.
294 if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
295 if ( ! empty( $this->start ) ) {
296 $defaults['date_query'][0]['after'] = "{$this->start} 00:00:00";
297 }
298 if ( ! empty( $this->end ) ) {
299 $defaults['date_query'][0]['before'] = "{$this->end} 23:59:59";
300 }
301 }
302
303 if ( ! empty( $this->form_id ) ) {
304 $defaults['give_forms'] = is_array( $this->form_id ) ? $this->form_id : array( $this->form_id );
305 }
306
307 /**
308 * Filter to modify Payment Query arguments for exporting
309 * donations.
310 *
311 * @since 2.1.3
312 */
313 return apply_filters( 'give_export_donations_donation_query_args', wp_parse_args( $args, $defaults ) );
314 }
315
316 /**
317 * Get the Export Data.
318 *
319 * @access public
320 *
321 * @since 3.12.1 add donor phone.
322 * @since 2.1
323 *
324 * @global object $wpdb Used to query the database using the WordPress database API.
325 *
326 * @return array $data The data for the CSV file.
327 */
328 public function get_data() {
329
330 $data = array();
331 $i = 0;
332 // Payment query.
333 $payments = give_get_payments( $this->get_donation_argument() );
334
335 if ( $payments ) {
336
337 foreach ( $payments as $payment ) {
338
339 $columns = $this->csv_cols();
340 $payment = new Give_Payment( $payment->ID );
341 $payment_meta = $payment->payment_meta;
342 $address = $payment->address;
343
344 // Set columns.
345 if ( ! empty( $columns['donation_id'] ) ) {
346 $data[ $i ]['donation_id'] = $payment->ID;
347 }
348
349 if ( ! empty( $columns['seq_id'] ) ) {
350 $data[ $i ]['seq_id'] = Give()->seq_donation_number->get_serial_code( $payment->ID );
351 }
352
353 if ( ! empty( $columns['title_prefix'] ) ) {
354 $data[ $i ]['title_prefix'] = ! empty( $payment->title_prefix ) ? $payment->title_prefix : '';
355 }
356
357 if ( ! empty( $columns['first_name'] ) ) {
358 $data[ $i ]['first_name'] = isset( $payment->first_name ) ? $payment->first_name : '';
359 }
360
361 if ( ! empty( $columns['last_name'] ) ) {
362 $data[ $i ]['last_name'] = isset( $payment->last_name ) ? $payment->last_name : '';
363 }
364
365 if ( ! empty( $columns['email'] ) ) {
366 $data[ $i ]['email'] = $payment->email;
367 }
368
369 if ( ! empty( $columns['company'] ) ) {
370 $data[ $i ]['company'] = empty( $payment_meta['_give_donation_company'] ) ? '' : str_replace( "\'", "'", $payment_meta['_give_donation_company'] );
371 }
372
373 if ( ! empty( $columns['address_line1'] ) ) {
374 $data[ $i ]['address_line1'] = isset( $address['line1'] ) ? $address['line1'] : '';
375 $data[ $i ]['address_line2'] = isset( $address['line2'] ) ? $address['line2'] : '';
376 $data[ $i ]['address_city'] = isset( $address['city'] ) ? $address['city'] : '';
377 $data[ $i ]['address_state'] = isset( $address['state'] ) ? $address['state'] : '';
378 $data[ $i ]['address_zip'] = isset( $address['zip'] ) ? $address['zip'] : '';
379 $data[ $i ]['address_country'] = isset( $address['country'] ) ? $address['country'] : '';
380 }
381
382 if ( ! empty( $columns['phone'] ) ) {
383 $data[ $i ]['phone'] = $payment_meta['_give_payment_donor_phone'];
384 }
385
386 if ( ! empty( $columns['comment'] ) ) {
387 $comment = give_get_donor_donation_comment( $payment->ID, $payment->donor_id );
388 $data[ $i ]['comment'] = ! empty( $comment ) ? $comment->comment_content : '';
389 }
390
391 if ( ! empty( $columns['donation_total'] ) ) {
392 $data[ $i ]['donation_total'] = give_format_amount( give_donation_amount( $payment->ID ) );
393 }
394
395 if ( ! empty( $columns['currency_code'] ) ) {
396 $data[ $i ]['currency_code'] = empty( $payment_meta['_give_payment_currency'] ) ? give_get_currency() : $payment_meta['_give_payment_currency'];
397 }
398
399 if ( ! empty( $columns['currency_symbol'] ) ) {
400 $currency_code = $data[ $i ]['currency_code'];
401 $data[ $i ]['currency_symbol'] = give_currency_symbol( $currency_code, true );
402 }
403
404 if ( ! empty( $columns['donation_status'] ) ) {
405 $data[ $i ]['donation_status'] = give_get_payment_status( $payment, true );
406 }
407
408 if ( ! empty( $columns['payment_gateway'] ) ) {
409 $data[ $i ]['payment_gateway'] = $payment->gateway;
410 }
411
412 if ( ! empty( $columns['payment_mode'] ) ) {
413 $data[ $i ]['payment_mode'] = $payment->mode;
414 }
415
416 if ( ! empty( $columns['form_id'] ) ) {
417 $data[ $i ]['form_id'] = $payment->form_id;
418 }
419
420 if ( ! empty( $columns['form_title'] ) ) {
421 $data[ $i ]['form_title'] = get_the_title( $payment->form_id );
422 }
423
424 if ( ! empty( $columns['form_level_id'] ) ) {
425 $data[ $i ]['form_level_id'] = $payment->price_id;
426 }
427
428 if ( ! empty( $columns['form_level_title'] ) ) {
429 $var_prices = give_has_variable_prices( $payment->form_id );
430 if ( empty( $var_prices ) ) {
431 $data[ $i ]['form_level_title'] = '';
432 } else {
433 if ( 'custom' === $payment->price_id ) {
434 $custom_amount_text = give_get_meta( $payment->form_id, '_give_custom_amount_text', true );
435
436 if ( empty( $custom_amount_text ) ) {
437 $custom_amount_text = esc_html__( 'Custom Amount', 'give' );
438 }
439 $data[ $i ]['form_level_title'] = $custom_amount_text;
440 } else {
441 $data[ $i ]['form_level_title'] = give_get_price_option_name( $payment->form_id, $payment->price_id );
442 }
443 }
444 }
445
446 if ( ! empty( $columns['donation_date'] ) ) {
447 $payment_date = strtotime( $payment->date );
448 $data[ $i ]['donation_date'] = date( give_date_format(), $payment_date );
449 }
450
451 if ( ! empty( $columns['donation_time'] ) ) {
452 $payment_date = strtotime( $payment->date );
453 $data[ $i ]['donation_time'] = date_i18n( 'H', $payment_date ) . ':' . date( 'i', $payment_date );
454 }
455
456 if ( ! empty( $columns['userid'] ) ) {
457 $data[ $i ]['userid'] = $payment->user_id;
458 }
459
460 if ( ! empty( $columns['donorid'] ) ) {
461 $data[ $i ]['donorid'] = $payment->customer_id;
462 }
463
464 if ( ! empty( $columns['donor_ip'] ) ) {
465 $data[ $i ]['donor_ip'] = give_get_payment_user_ip( $payment->ID );
466 }
467
468 if ( ! empty( $columns['donation_note_private'] ) ) {
469 $comments = Give()->comment->db->get_comments(
470 array(
471 'comment_parent' => $payment->ID,
472 'comment_type' => 'donation',
473 'meta_query' => array(
474 'relation' => 'OR',
475 array(
476 'key' => 'note_type',
477 'compare' => 'NOT EXISTS',
478 ),
479 array(
480 'key' => 'note_type',
481 'value' => 'donor',
482 'compare' => '!=',
483 ),
484 ),
485 )
486 );
487
488 $comment_html = array();
489
490 if ( ! empty( $comments ) ) {
491 foreach ( $comments as $comment ) {
492 $comment_html[] = sprintf(
493 '%s - %s',
494 date( 'Y-m-d', strtotime( $comment->comment_date ) ),
495 $comment->comment_content
496 );
497 }
498 }
499
500 $data[ $i ]['donation_note_private'] = implode( "\n", $comment_html );
501 }
502
503 if ( ! empty( $columns['donation_note_to_donor'] ) ) {
504 $comments = Give()->comment->db->get_comments(
505 array(
506 'comment_parent' => $payment->ID,
507 'comment_type' => 'donation',
508 'meta_query' => array(
509 array(
510 'key' => 'note_type',
511 'value' => 'donor',
512 ),
513 ),
514 )
515 );
516
517 $comment_html = array();
518
519 if ( ! empty( $comments ) ) {
520 foreach ( $comments as $comment ) {
521 $comment_html[] = sprintf(
522 '%s - %s',
523 date( 'Y-m-d', strtotime( $comment->comment_date ) ),
524 $comment->comment_content
525 );
526 }
527 }
528 $data[ $i ]['donation_note_to_donor'] = implode( "\n", $comment_html );
529 }
530
531 // Add custom field data.
532 // First we remove the standard included keys from above.
533 $remove_keys = array(
534 'donation_id',
535 'seq_id',
536 'first_name',
537 'last_name',
538 'email',
539 'address_line1',
540 'address_line2',
541 'address_city',
542 'address_state',
543 'address_zip',
544 'address_country',
545 'donation_total',
546 'payment_gateway',
547 'payment_mode',
548 'form_id',
549 'form_title',
550 'form_level_id',
551 'form_level_title',
552 'donation_date',
553 'donation_time',
554 'userid',
555 'donorid',
556 'donor_ip',
557 );
558
559 // Removing above keys...
560 foreach ( $remove_keys as $key ) {
561 unset( $columns[ $key ] );
562 }
563
564 // Now loop through remaining meta fields.
565 foreach ( $columns as $col ) {
566 $field_data = get_post_meta( $payment->ID, $col, true );
567 $data[ $i ][ $col ] = $field_data;
568 unset( $columns[ $col ] );
569 }
570
571 /**
572 * Filter to modify Donation CSV data when exporting donation
573 *
574 * @since 2.1
575 *
576 * @param array Donation data
577 * @param Give_Payment $payment Instance of Give_Payment
578 * @param array $columns Donation data $columns that are not being merge
579 * @param Give_Export_Donations_CSV $this Instance of Give_Export_Donations_CSV
580 *
581 * @return array Donation data
582 */
583 $data[ $i ] = apply_filters( 'give_export_donation_data', $data[ $i ], $payment, $columns, $this );
584
585 $new_data = array();
586 $old_data = $data[ $i ];
587
588 // sorting the columns bas on row
589 foreach ( $this->csv_cols() as $key => $value ) {
590 if ( array_key_exists( $key, $old_data ) ) {
591 $new_data[ $key ] = $old_data[ $key ];
592 }
593 }
594
595 $data[ $i ] = $new_data;
596
597 // Increment iterator.
598 $i ++;
599
600 }
601
602 $data = apply_filters( 'give_export_get_data', $data );
603 $data = apply_filters( "give_export_get_data_{$this->export_type}", $data );
604
605 return $data;
606
607 }
608
609 return array();
610
611 }
612
613 /**
614 * Return the calculated completion percentage.
615 *
616 * @since 2.1
617 *
618 * @return int
619 */
620 public function get_percentage_complete() {
621 $args = $this->get_donation_argument(
622 array(
623 'number' => - 1,
624 'output' => '',
625 )
626 );
627 if ( isset( $args['page'] ) ) {
628 unset( $args['page'] );
629 }
630 $query = give_get_payments( $args );
631 $total = count( $query );
632 $percentage = 100;
633 if ( $total > 0 ) {
634 $percentage = ( ( 30 * $this->step ) / $total ) * 100;
635 }
636 if ( $percentage > 100 ) {
637 $percentage = 100;
638 }
639
640 return $percentage;
641 }
642
643 /**
644 * Print the CSV rows for the current step.
645 *
646 * @access public
647 *
648 * @since 2.1
649 * @since 3.14.0 Use maybe_serialize() for column data (some data are arrays)
650 *
651 * @return string|false
652 */
653 public function print_csv_rows() {
654
655 $row_data = '';
656 $data = $this->get_data();
657 $cols = $this->get_csv_cols();
658
659 if ( $data ) {
660
661 // Output each row
662 foreach ( $data as $row ) {
663 $i = 1;
664 foreach ( $row as $col_id => $column ) {
665 // Make sure the column is valid
666 if ( array_key_exists( $col_id, $cols ) ) {
667 $column = maybe_serialize( $column );
668 $row_data .= '"' . $this->escape_csv_cell_data(preg_replace( '/"/', "'", $column )) . '"';
669 $row_data .= $i == count( $cols ) ? '' : ',';
670 $i ++;
671 }
672 }
673 $row_data .= "\r\n";
674 }
675
676 $this->stash_step_data( $row_data );
677
678 return $row_data;
679 }
680
681 return false;
682 }
683
684 /**
685 * Escapes CSV cell data to protect against CSV injection.
686 * @link https://owasp.org/www-community/attacks/CSV_Injection
687 *
688 * @since 3.12.1 sanitize + prefix
689 * @since 2.25.2
690 *
691 * @param mixed|string $cellData
692 *
693 * @return mixed|string
694 */
695 protected function escape_csv_cell_data($cellData) {
696 $cellData = str_replace('+', '', $cellData);
697 $firstCharacter = substr($cellData, 0, 1);
698 if( in_array($firstCharacter, array('=', '+', '-', '@')) ) {
699 $cellData = "'" . $cellData;
700 }
701 return $cellData;
702 }
703 }
704