Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/paid-memberships-pro/adminpages/memberslist-csv.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
<?php
2
+
3
+
if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_memberslistcsv")))
4
+
{
5
+
die(esc_html__("You do not have permissions to perform this action.", 'paid-memberships-pro' ));
6
+
}
7
+
8
+
if (!defined('PMPRO_BENCHMARK'))
9
+
define('PMPRO_BENCHMARK', false);
10
+
11
+
if (PMPRO_BENCHMARK)
12
+
{
13
+
error_log(str_repeat('-', 10) . date_i18n('Y-m-d H:i:s') . str_repeat('-', 10));
14
+
$start_time = microtime(true);
15
+
$start_memory = memory_get_usage(true);
16
+
}
17
+
18
+
19
+
/**
20
+
* Filter to set max number of records to process at a time
21
+
* for the export (helps manage memory footprint)
22
+
*
23
+
* Rule of thumb: 2000 records: ~50-60 MB of addl. memory (memory_limit needs to be between 128MB and 256MB)
24
+
* 4000 records: ~70-100 MB of addl. memory (memory_limit needs to be >= 256MB)
25
+
* 6000 records: ~100-140 MB of addl. memory (memory_limit needs to be >= 256MB)
26
+
*
27
+
* NOTE: Use the pmpro_before_members_list_csv_export hook to increase memory "on-the-fly"
28
+
* Can reset with the pmpro_after_members_list_csv_export hook
29
+
*
30
+
* @since 1.8.7
31
+
*/
32
+
//set the number of users we'll load to try and protect ourselves from OOM errors
33
+
$max_users_per_loop = intval( apply_filters( 'pmpro_set_max_user_per_export_loop', 2000 ) );
34
+
35
+
//If the filter returns odd value, reset to default.
36
+
if ( $max_users_per_loop < 1 ) {
37
+
$max_users_per_loop = 2000;
38
+
}
39
+
global $wpdb;
40
+
41
+
//get users (search input field)
42
+
$search_key = false;
43
+
if( isset( $_REQUEST['s'] ) ) {
44
+
$s = trim( sanitize_text_field( $_REQUEST['s'] ) );
45
+
} else {
46
+
$s = '';
47
+
}
48
+
49
+
// If there's a colon in the search, let's split it out.
50
+
if( ! empty( $s ) && strpos( $s, ':' ) !== false ) {
51
+
$parts = explode( ':', $s );
52
+
$search_key = array_shift( $parts );
53
+
$s = implode( ':', $parts );
54
+
}
55
+
56
+
// Treat * as wild cards.
57
+
$s = str_replace( '*', '%', $s );
58
+
59
+
// requested a level id
60
+
if(isset($_REQUEST['l']))
61
+
$l = sanitize_text_field($_REQUEST['l']);
62
+
else
63
+
$l = false;
64
+
65
+
//some vars for the search
66
+
if(!empty($_REQUEST['pn']))
67
+
$pn = intval($_REQUEST['pn']);
68
+
else
69
+
$pn = 1;
70
+
71
+
if(!empty($_REQUEST['limit']))
72
+
$limit = intval($_REQUEST['limit']);
73
+
else
74
+
$limit = false;
75
+
76
+
if($limit)
77
+
{
78
+
$end = $pn * $limit;
79
+
$start = $end - $limit;
80
+
}
81
+
else
82
+
{
83
+
$end = NULL;
84
+
$start = NULL;
85
+
}
86
+
87
+
$headers = array();
88
+
$headers[] = "Content-Type: text/csv";
89
+
$headers[] = "Cache-Control: max-age=0, no-cache, no-store";
90
+
$headers[] = "Pragma: no-cache";
91
+
$headers[] = "Connection: close";
92
+
93
+
if ( $s && $l == "oldmembers" ) {
94
+
$headers[] = 'Content-Disposition: attachment; filename="members_list_oldmembers_' . sanitize_file_name($s) . '.csv"';
95
+
} elseif($s && $l) {
96
+
$headers[] = 'Content-Disposition: attachment; filename="members_list_' . intval($l) . '_level_' . sanitize_file_name($s) . '.csv"';
97
+
} elseif($s) {
98
+
$headers[] = 'Content-Disposition: attachment; filename="members_list_' . sanitize_file_name($s) . '.csv"';
99
+
} elseif($l == "oldmembers") {
100
+
$headers[] = 'Content-Disposition: attachment; filename="members_list_oldmembers.csv"';
101
+
} elseif($l == 'expired' ) {
102
+
$headers[] = 'Content-Disposition: attachment; filename="members_list_expired.csv"';
103
+
} else {
104
+
$headers[] = 'Content-Disposition: attachment; filename="members_list.csv"';
105
+
}
106
+
107
+
//set default CSV file headers, using comma as delimiter
108
+
$csv_file_header = "id,username,firstname,lastname,email,membership,discount_code_id,discount_code,subscription_transaction_id,billing_amount,cycle_number,cycle_period,next_payment_date,joined,startdate";
109
+
110
+
if($l == "oldmembers")
111
+
$csv_file_header .= ",ended";
112
+
else
113
+
$csv_file_header .= ",expires";
114
+
115
+
//these are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID)
116
+
$default_columns = array(
117
+
array("theuser", "ID"),
118
+
array("theuser", "user_login"),
119
+
array("metavalues", "first_name"),
120
+
array("metavalues", "last_name"),
121
+
array("theuser", "user_email"),
122
+
array("theuser", "membership"),
123
+
array("discount_code", "id"),
124
+
array("discount_code", "code")
125
+
// Subscription information, joindate, and enddate are handled specifically below
126
+
);
127
+
128
+
//filter
129
+
$default_columns = apply_filters("pmpro_members_list_csv_default_columns", $default_columns);
130
+
131
+
//set the preferred date format:
132
+
$dateformat = apply_filters("pmpro_memberslist_csv_dateformat","Y-m-d");
133
+
134
+
//any extra columns
135
+
$extra_columns = apply_filters("pmpro_members_list_csv_extra_columns", array());
136
+
if(!empty($extra_columns))
137
+
{
138
+
foreach($extra_columns as $heading => $callback)
139
+
{
140
+
$csv_file_header .= "," . $heading;
141
+
}
142
+
}
143
+
144
+
$csv_file_header = apply_filters("pmpro_members_list_csv_heading", $csv_file_header);
145
+
$csv_file_header .= "\n";
146
+
147
+
//generate SQL for list of users to process
148
+
$sqlQuery = "
149
+
SELECT
150
+
DISTINCT u.ID
151
+
FROM $wpdb->users u ";
152
+
153
+
if ( $s ) {
154
+
if ( ! empty( $search_key ) ) {
155
+
// If there's a colon in the search string, make the search smarter.
156
+
if( in_array( $search_key, array( 'login', 'nicename', 'email', 'url', 'display_name' ), true ) ) {
157
+
$key_column = 'u.user_' . $search_key; // All options for $search_key are safe for use in a query.
158
+
$search = " AND $key_column LIKE '%" . esc_sql( $s ) . "%' ";
159
+
} elseif ( $search_key === 'discount' || $search_key === 'discount_code' || $search_key === 'dc' ) {
160
+
$user_ids = $wpdb->get_col( "SELECT dcu.user_id FROM $wpdb->pmpro_discount_codes_uses dcu LEFT JOIN $wpdb->pmpro_discount_codes dc ON dcu.code_id = dc.id WHERE dc.code = '" . esc_sql( $s ) . "'" );
161
+
if ( empty( $user_ids ) ) {
162
+
$user_ids = array(0); // Avoid warning, but ensure 0 results.
163
+
}
164
+
$search = " AND u.ID IN(" . implode( ",", $user_ids ) . ") ";
165
+
} else {
166
+
$user_ids = $wpdb->get_col( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '" . esc_sql( $search_key ) . "' AND meta_value lIKE '%" . esc_sql( $s ) . "%'" );
167
+
if ( empty( $user_ids ) ) {
168
+
$user_ids = array(0); // Avoid warning, but ensure 0 results.
169
+
}
170
+
$search = " AND u.ID IN(" . implode( ",", $user_ids ) . ") ";
171
+
}
172
+
} elseif( function_exists( 'wp_is_large_user_count' ) && wp_is_large_user_count() ) {
173
+
// Don't check user meta at all on big sites.
174
+
$search_query = " AND ( u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR u.display_name LIKE '%" . esc_sql($s) . "%' ) ";
175
+
} else {
176
+
// Default search checks a few fields.
177
+
$sqlQuery .= "LEFT JOIN {$wpdb->usermeta} um ON u.ID = um.user_id ";
178
+
$search = " AND ( u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%' OR u.display_name LIKE '%" . esc_sql($s) . "%' ) ";
179
+
}
180
+
} else {
181
+
$search = '';
182
+
}
183
+
184
+
$sqlQuery .= "LEFT JOIN {$wpdb->pmpro_memberships_users} mu ON u.ID = mu.user_id ";
185
+
$sqlQuery .= "LEFT JOIN {$wpdb->pmpro_membership_levels} m ON mu.membership_id = m.id ";
186
+
187
+
$sqlQuery .= "WHERE mu.membership_id > 0 ";
188
+
189
+
// looking for a specific user
190
+
if ( ! empty( $s ) ) {
191
+
$sqlQuery .= $search;
192
+
}
193
+
194
+
$filter = null;
195
+
196
+
//records where the user is NOT an active member
197
+
//if $l == "oldmembers"
198
+
$filter = ($l == "oldmembers" ? " AND mu.status <> 'active' " : $filter);
199
+
200
+
// prepare the status to use in the filter
201
+
// elseif ($l == "expired") elseif ($l == "cancelled")
202
+
$f_status = ($l == "expired" ? array( 'expired' ) : ( $l == "cancelled" ? array('cancelled', 'admin_cancelled') : null));
203
+
204
+
//records where the user is expired or cancelled
205
+
$filter = ( ($l == "expired" || $l == "cancelled") && is_null($filter)) ? "AND mu.status IN ('" . implode("','", $f_status) . "') " : $filter;
206
+
207
+
if ( in_array($l, array( "oldmembers", "expired", "cancelled") ) ) {
208
+
$filter .= " AND NOT EXISTS (
209
+
SELECT 1
210
+
FROM {$wpdb->pmpro_memberships_users} mu2
211
+
WHERE mu2.user_id = u.ID
212
+
AND mu2.status = 'active'
213
+
) ";
214
+
}
215
+
216
+
//records for active users with the requested membership level
217
+
// elseif($l)
218
+
$filter = ( (is_null($filter) && is_numeric($l)) ? " AND mu.status = 'active' AND mu.membership_id = " . (int) $l . " " : $filter);
219
+
220
+
//any active users
221
+
// else
222
+
$filter = (is_null($filter) ? " AND mu.status = 'active' " : $filter);
223
+
224
+
//add the filter
225
+
$sqlQuery .= $filter;
226
+
227
+
//process based on limit value(s).
228
+
$sqlQuery .= "ORDER BY u.ID ";
229
+
230
+
if(!empty($limit))
231
+
$sqlQuery .= "LIMIT {$start}, {$limit}";
232
+
233
+
/**
234
+
* Filter to change/manipulate the SQL for the list of members export
235
+
* @since v1.9.0 Re-introduced
236
+
*/
237
+
$sqlQuery = apply_filters('pmpro_members_list_sql', $sqlQuery);
238
+
239
+
// Generate a temporary file to store the data in.
240
+
$tmp_dir = sys_get_temp_dir();
241
+
$filename = tempnam( $tmp_dir, 'pmpro_ml_');
242
+
243
+
// open in append mode
244
+
$csv_fh = fopen($filename, 'a');
245
+
246
+
//write the CSV header to the file
247
+
fprintf($csv_fh, '%s', $csv_file_header );
248
+
249
+
//get users
250
+
$theusers = $wpdb->get_col($sqlQuery);
251
+
252
+
//if no records just transmit file with only CSV header as content
253
+
if (empty($theusers) && empty($_REQUEST['pmpro_no_download'])) {
254
+
255
+
// send the data to the remote browser
256
+
pmpro_transmit_content($csv_fh, $filename, $headers);
257
+
}
258
+
259
+
$users_found = count($theusers);
260
+
261
+
if (PMPRO_BENCHMARK)
262
+
{
263
+
$pre_action_time = microtime(true);
264
+
$pre_action_memory = memory_get_usage(true);
265
+
}
266
+
267
+
do_action('pmpro_before_members_list_csv_export', $theusers);
268
+
269
+
$i_start = 0;
270
+
$i_limit = 0;
271
+
$iterations = 1;
272
+
273
+
$csvoutput = array();
274
+
275
+
if($users_found >= $max_users_per_loop)
276
+
{
277
+
$iterations = ceil($users_found / $max_users_per_loop);
278
+
$i_limit = $max_users_per_loop;
279
+
}
280
+
281
+
$end = 0;
282
+
$time_limit = ini_get('max_execution_time');
283
+
284
+
if (PMPRO_BENCHMARK)
285
+
{
286
+
error_log("PMPRO_BENCHMARK - Total records to process: {$users_found}");
287
+
error_log("PMPRO_BENCHMARK - Will process {$iterations} iterations of max {$max_users_per_loop} records per iteration.");
288
+
$pre_iteration_time = microtime(true);
289
+
$pre_iteration_memory = memory_get_usage(true);
290
+
}
291
+
292
+
//to manage memory footprint, we'll iterate through the membership list multiple times
293
+
for ( $ic = 1 ; $ic <= $iterations ; $ic++ ) {
294
+
295
+
if (PMPRO_BENCHMARK)
296
+
{
297
+
$start_iteration_time = microtime(true);
298
+
$start_iteration_memory = memory_get_usage(true);
299
+
}
300
+
301
+
//make sure we don't timeout
302
+
if ($end != 0) {
303
+
304
+
$iteration_diff = $end - $start;
305
+
$new_time_limit = ceil($iteration_diff*$iterations * 1.2);
306
+
307
+
if ($time_limit < $new_time_limit )
308
+
{
309
+
$time_limit = $new_time_limit;
310
+
set_time_limit( $time_limit );
311
+
}
312
+
}
313
+
314
+
$start = current_time('timestamp');
315
+
316
+
$i_end = min( $i_start + $max_users_per_loop - 1, $users_found - 1 );
317
+
318
+
$spl = array_slice( $theusers, $i_start, $i_end - $i_start + 1 );
319
+
//increment starting position
320
+
$i_start = $i_end + 1;
321
+
322
+
//escape the % for LIKE comparison with $wpdb
323
+
if(!empty($search))
324
+
$search = str_replace('%', '%%', $search);
325
+
326
+
$userSql = "
327
+
SELECT
328
+
DISTINCT u.ID,
329
+
u.user_login,
330
+
u.user_email,
331
+
UNIX_TIMESTAMP(CONVERT_TZ(u.user_registered, '+00:00', @@global.time_zone)) as joindate,
332
+
u.user_login,
333
+
u.user_nicename,
334
+
u.user_url,
335
+
u.user_registered,
336
+
u.user_status,
337
+
u.display_name,
338
+
mu.membership_id,
339
+
UNIX_TIMESTAMP(CONVERT_TZ(min(mu.startdate), '+00:00', @@global.time_zone)) as startdate,
340
+
UNIX_TIMESTAMP(CONVERT_TZ(max(mu.enddate), '+00:00', @@global.time_zone)) as enddate,
341
+
m.name as membership
342
+
FROM {$wpdb->users} u
343
+
LEFT JOIN {$wpdb->usermeta} um ON u.ID = um.user_id
344
+
LEFT JOIN {$wpdb->pmpro_memberships_users} mu ON u.ID = mu.user_id
345
+
LEFT JOIN {$wpdb->pmpro_membership_levels} m ON mu.membership_id = m.id
346
+
WHERE u.ID in ( " . implode(', ', array_fill(0, count( $spl ), '%d' ) ) . " ) AND mu.membership_id > 0 {$filter} {$search}
347
+
GROUP BY u.ID, mu.membership_id
348
+
ORDER BY u.ID
349
+
";
350
+
$userSql = call_user_func( array( $wpdb, 'prepare' ), $userSql, $spl );
351
+
$usr_data = $wpdb->get_results($userSql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
352
+
$userSql = null;
353
+
354
+
if (PMPRO_BENCHMARK)
355
+
{
356
+
$pre_userdata_time = microtime(true);
357
+
$pre_userdata_memory = memory_get_usage(true);
358
+
}
359
+
360
+
// process the actual data we want to export
361
+
foreach($usr_data as $theuser) {
362
+
363
+
$csvoutput = array();
364
+
365
+
//process usermeta
366
+
$metavalues = new stdClass();
367
+
368
+
// Returns array of meta keys containing array(s) of metavalues.
369
+
$um_values = get_user_meta($theuser->ID);
370
+
371
+
foreach( $um_values as $key => $value ) {
372
+
373
+
$metavalues->{$key} = isset( $value[0] ) ? $value[0] : null;
374
+
}
375
+
376
+
$theuser->metavalues = $metavalues;
377
+
378
+
$um_values = null;
379
+
380
+
//grab discount code info
381
+
$disSql = $wpdb->prepare("
382
+
SELECT
383
+
c.id,
384
+
c.code
385
+
FROM {$wpdb->pmpro_discount_codes_uses} cu
386
+
LEFT JOIN $wpdb->pmpro_discount_codes c ON cu.code_id = c.id
387
+
WHERE cu.user_id = %d
388
+
ORDER BY c.id DESC
389
+
LIMIT 1",
390
+
$theuser->ID
391
+
);
392
+
393
+
$discount_code = $wpdb->get_row($disSql);
394
+
395
+
//make sure there's data for the discount code info
396
+
if (empty($discount_code))
397
+
{
398
+
$empty_dc = new stdClass();
399
+
$empty_dc->id = '';
400
+
$empty_dc->code = '';
401
+
$discount_code = $empty_dc;
402
+
}
403
+
404
+
unset($disSql);
405
+
406
+
//default columns
407
+
if(!empty($default_columns))
408
+
{
409
+
$count = 0;
410
+
foreach($default_columns as $col)
411
+
{
412
+
//checking $object->property. note the double $$
413
+
$val = isset(${$col[0]}->{$col[1]}) ? ${$col[0]}->{$col[1]} : null;
414
+
array_push($csvoutput, pmpro_enclose($val)); //output the value
415
+
}
416
+
}
417
+
418
+
// Subscription transaction ID, billing amount, cycle number, and cycle period.
419
+
$subscriptions = PMPro_Subscription::get_subscriptions_for_user( $theuser->ID, $theuser->membership_id );
420
+
array_push($csvoutput, pmpro_enclose( ( empty( $subscriptions ) ? '' : $subscriptions[0]->get_subscription_transaction_id() ) ) );
421
+
array_push($csvoutput, pmpro_enclose( ( empty( $subscriptions ) ? '' : $subscriptions[0]->get_billing_amount() ) ) );
422
+
array_push($csvoutput, pmpro_enclose( ( empty( $subscriptions ) ? '' : $subscriptions[0]->get_cycle_number() ) ) );
423
+
array_push($csvoutput, pmpro_enclose( ( empty( $subscriptions ) ? '' : $subscriptions[0]->get_cycle_period() ) ) );
424
+
array_push($csvoutput, pmpro_enclose( ( empty( $subscriptions ) ? '' : date_i18n($dateformat, $subscriptions[0]->get_next_payment_date() ) ) ) );
425
+
426
+
//joindate, startdate, and enddate
427
+
array_push($csvoutput, pmpro_enclose(date_i18n($dateformat, $theuser->joindate)));
428
+
429
+
if ( $theuser->startdate ) {
430
+
array_push( $csvoutput, pmpro_enclose( date_i18n( $dateformat, $theuser->startdate ) ) );
431
+
} else {
432
+
array_push( $csvoutput, pmpro_enclose( __( 'N/A', 'paid-memberships-pro' ) ) );
433
+
}
434
+
// We are no longer filtering the expiration date text for performance reasons.
435
+
if ( $theuser->enddate ) {
436
+
array_push( $csvoutput, pmpro_enclose( date_i18n( $dateformat, $theuser->enddate ) ) );
437
+
} else {
438
+
array_push( $csvoutput, pmpro_enclose( __( 'N/A', 'paid-memberships-pro' ) ) );
439
+
}
440
+
441
+
//any extra columns
442
+
if(!empty($extra_columns))
443
+
{
444
+
foreach($extra_columns as $heading => $callback)
445
+
{
446
+
$val = call_user_func($callback, $theuser, $heading);
447
+
$val = ( is_string( $val ) || ! empty($val) ) ? $val : null;
448
+
array_push( $csvoutput, pmpro_enclose($val) );
449
+
}
450
+
}
451
+
452
+
//free memory for user records
453
+
$metavalues = null;
454
+
$discount_code = null;
455
+
$theuser = null;
456
+
457
+
// $csvoutput .= "\n";
458
+
$line = implode(',', $csvoutput) . "\n";
459
+
460
+
fprintf($csv_fh, "%s", $line);
461
+
462
+
//reset
463
+
$line = null;
464
+
$csvoutput = null;
465
+
} // end of foreach usr_data
466
+
467
+
if (PMPRO_BENCHMARK)
468
+
{
469
+
$end_of_iteration_time = microtime(true);
470
+
$end_of_iteration_memory = memory_get_usage(true);
471
+
}
472
+
473
+
//keep memory consumption low(ish)
474
+
wp_cache_flush();
475
+
476
+
if (PMPRO_BENCHMARK)
477
+
{
478
+
$after_flush_time = microtime(true);
479
+
$after_flush_memory = memory_get_usage(true);
480
+
481
+
$time_in_iteration = $end_of_iteration_time - $start_iteration_time;
482
+
$time_flushing = $after_flush_time - $end_of_iteration_time;
483
+
$userdata_time = $end_of_iteration_time - $pre_userdata_time;
484
+
485
+
list($iteration_sec, $iteration_usec) = explode('.', $time_in_iteration);
486
+
list($udata_sec, $udata_usec) = explode('.', $userdata_time);
487
+
list($flush_sec, $flush_usec) = explode('.', $time_flushing);
488
+
489
+
$memory_used = $end_of_iteration_memory - $start_iteration_memory;
490
+
491
+
error_log("PMPRO_BENCHMARK - For iteration #{$ic} of {$iterations} - Records processed: " . count($usr_data));
492
+
error_log("PMPRO_BENCHMARK - \tTime processing whole iteration: " . date_i18n("H:i:s", $iteration_sec) . ".{$iteration_sec}");
493
+
error_log("PMPRO_BENCHMARK - \tTime processing user data for iteration: " . date_i18n("H:i:s", $udata_sec) . ".{$udata_sec}");
494
+
error_log("PMPRO_BENCHMARK - \tTime flushing cache: " . date_i18n("H:i:s", $flush_sec) . ".{$flush_usec}");
495
+
error_log("PMPRO_BENCHMARK - \tAdditional memory used during iteration: ".number_format($memory_used, 2, '.', ',') . " bytes");
496
+
}
497
+
498
+
//need to increase max running time?
499
+
$end = current_time('timestamp');
500
+
501
+
} // end of foreach iteration
502
+
503
+
if (PMPRO_BENCHMARK)
504
+
{
505
+
$after_data_time = microtime(true);
506
+
$after_data_memory = memory_get_peak_usage(true);
507
+
508
+
$time_processing_data = $after_data_time - $start_time;
509
+
$memory_processing_data = $after_data_memory - $start_memory;
510
+
511
+
list($sec, $usec) = explode('.', $time_processing_data);
512
+
513
+
error_log("PMPRO_BENCHMARK - Time processing data: {$sec}.{$usec} seconds");
514
+
error_log("PMPRO_BENCHMARK - Peak memory usage: " . number_format($memory_processing_data, false, '.', ',') . " bytes");
515
+
}
516
+
517
+
// free memory
518
+
$usr_data = null;
519
+
520
+
// send the data to the remote browser, if this was not run via the Toolkit API
521
+
if ( empty( $_REQUEST['pmpro_no_download'] ) ) {
522
+
pmpro_transmit_content($csv_fh, $filename, $headers);
523
+
exit;
524
+
}
525
+
526
+
527
+
function pmpro_enclose($s) {
528
+
$s = (string) $s;
529
+
return "\"" . str_replace("\"", "\\\"", $s) . "\"";
530
+
}
531
+
532
+
// responsible for trasnmitting content of file to remote browser
533
+
function pmpro_transmit_content( $csv_fh, $filename, $headers = array() ) {
534
+
535
+
//close the temp file
536
+
fclose($csv_fh);
537
+
538
+
if (version_compare(phpversion(), '5.3.0', '>')) {
539
+
540
+
//make sure we get the right file size
541
+
clearstatcache( true, $filename );
542
+
} else {
543
+
// for any PHP version prior to v5.3.0
544
+
clearstatcache();
545
+
}
546
+
547
+
//did we accidentally send errors/warnings to browser?
548
+
if (headers_sent())
549
+
{
550
+
echo esc_html( str_repeat('-', 75) ) . "<br/>\n";
551
+
echo 'Please open a support case and paste in the warnings/errors you see above this text to\n ';
552
+
echo 'the <a href="http://paidmembershipspro.com/support/?utm_source=plugin&utm_medium=banner&utm_campaign=memberslist_csv" target="_blank">Paid Memberships Pro support forum</a><br/>\n';
553
+
echo esc_html( str_repeat('-', 75) ) . "<br/>\n";
554
+
echo wp_kses_post( file_get_contents($filename) );
555
+
echo esc_html( str_repeat('-', 75) ) . "<br/>\n";
556
+
}
557
+
558
+
//transmission
559
+
if (! empty($headers) )
560
+
{
561
+
//set the download size
562
+
$headers[] = "Content-Length: " . filesize($filename);
563
+
564
+
//set headers
565
+
foreach($headers as $header)
566
+
{
567
+
header($header . "\r\n");
568
+
}
569
+
570
+
// disable compression for the duration of file download
571
+
if(ini_get('zlib.output_compression')){
572
+
ini_set('zlib.output_compression', 'Off');
573
+
}
574
+
575
+
if( function_exists( 'fpassthru' ) ) {
576
+
// use fpassthru to output the csv
577
+
$csv_fh = fopen( $filename, 'rb' );
578
+
fpassthru( $csv_fh );
579
+
fclose( $csv_fh );
580
+
} else {
581
+
// use readfile() if fpassthru() is disabled (like on Flywheel Hosted)
582
+
readfile( $filename );
583
+
}
584
+
585
+
// remove the temp file
586
+
unlink( $filename );
587
+
}
588
+
589
+
//allow user to clean up after themselves
590
+
do_action('pmpro_after_members_list_csv_export');
591
+
exit;
592
+
}
593
+