Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/paid-memberships-pro/adminpages/login-csv.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + // only admins can get this
4 + if ( ! function_exists( 'current_user_can' ) || ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'pmpro_loginscsv' ) ) ) {
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 +
12 + $start_memory = memory_get_usage( true );
13 + $start_time = microtime( true );
14 +
15 + if ( true === PMPRO_BENCHMARK ) {
16 + error_log( str_repeat( '-', 10 ) . date_i18n( 'Y-m-d H:i:s' ) . str_repeat( '-', 10 ) );
17 + }
18 +
19 + /**
20 + * Filter to set max number records to process at a time
21 + * for the export (helps manage memory footprint)
22 + *
23 + * NOTE: Use the pmpro_before_visits_views_logins_csv_export hook to increase memory "on-the-fly"
24 + * Can reset with the pmpro_after_visits_views_logins_csv_export hook
25 + *
26 + * @since 2.9
27 + */
28 + // set the number of records we'll load to try and protect ourselves from OOM errors
29 + $max_record_loops = apply_filters( 'pmpro_set_max_visits_views_logins_records_per_export_loop', 2000 );
30 + global $wpdb;
31 +
32 + // vars
33 + if ( ! empty( $_REQUEST['s'] ) ) {
34 + $s = sanitize_text_field( $_REQUEST['s'] );
35 + } else {
36 + $s = '';
37 + }
38 +
39 + if ( ! empty( $_REQUEST['l'] ) ) {
40 + if ( $_REQUEST['l'] == 'all' ) {
41 + $l = 'all';
42 + } else {
43 + $l = intval( $_REQUEST['l'] );
44 + }
45 + } else {
46 + $l = '';
47 + }
48 +
49 + // some vars for the search
50 + if ( isset( $_REQUEST['pn'] ) ) {
51 + $pn = intval( $_REQUEST['pn'] );
52 + } else {
53 + $pn = 1;
54 + }
55 +
56 + if ( isset( $_REQUEST['limit'] ) ) {
57 + $limit = intval( $_REQUEST['limit'] );
58 + } else {
59 + $limit = false;
60 + }
61 +
62 + if ( $limit ) {
63 + $end = $pn * $limit;
64 + $start = $end - $limit;
65 + } else {
66 + $end = null;
67 + $start = null;
68 + }
69 +
70 + if ( $s ) {
71 + $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(CONVERT_TZ(u.user_registered, '+00:00', @@global.time_zone)) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(CONVERT_TZ(mu.startdate, '+00:00', @@global.time_zone)) as startdate, UNIX_TIMESTAMP(CONVERT_TZ(mu.enddate, '+00:00', @@global.time_zone)) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE (u.user_login LIKE '%" . esc_sql( $s ) . "%' OR u.user_email LIKE '%" . esc_sql( $s ) . "%' OR um.meta_value LIKE '%" . esc_sql( $s ) . "%') ";
72 +
73 + if ( $l == 'all' ) {
74 + $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id > 0 ";
75 + } elseif ( $l ) {
76 + $sqlQuery .= " AND mu.membership_id = '" . esc_sql( $l ) . "' ";
77 + }
78 +
79 + $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC";
80 + } else {
81 + $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(CONVERT_TZ(u.user_registered, '+00:00', @@global.time_zone)) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(CONVERT_TZ(mu.startdate, '+00:00', @@global.time_zone)) as startdate, UNIX_TIMESTAMP(CONVERT_TZ(mu.enddate, '+00:00', @@global.time_zone)) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id";
82 + $sqlQuery .= ' WHERE 1=1 ';
83 +
84 + if ( $l == 'all' ) {
85 + $sqlQuery .= " AND mu.membership_id > 0 AND mu.status = 'active' ";
86 + } elseif ( $l ) {
87 + $sqlQuery .= " AND mu.membership_id = '" . esc_sql( $l ) . "' ";
88 + }
89 + $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC";
90 + }
91 +
92 + if ( ! empty( $start ) && ! empty( $limit ) ) {
93 + $sqlQuery .= "LIMIT " . (int) $start . "," . (int) $limit;
94 + }
95 +
96 + $sqlQuery = apply_filters( 'pmpro_visits_views_logins_csv_sql', $sqlQuery );
97 +
98 + $theusers = $wpdb->get_results( $sqlQuery );
99 +
100 + $headers = array();
101 + $headers[] = 'Content-Type: text/csv';
102 + $headers[] = 'Cache-Control: max-age=0, no-cache, no-store';
103 + $headers[] = 'Pragma: no-cache';
104 + $headers[] = 'Connection: close';
105 +
106 + $filename = 'views-logins-visits.csv';
107 + /*
108 + Insert logic here for building filename from $filter and other values.
109 + */
110 + $filename = apply_filters( 'pmpro_visits_views_logins_csv_export_filename', $filename );
111 + $headers[] = "Content-Disposition: attachment; filename={$filename};";
112 +
113 + // Default CSV file headers.
114 + $csv_file_header_array = array(
115 + 'ID',
116 + 'username',
117 + 'level',
118 + 'last_visit',
119 + 'visits_this_week',
120 + 'visits_this_month',
121 + 'visits_this_year',
122 + 'visits_all_time',
123 + 'views_this_week',
124 + 'views_this_month',
125 + 'views_this_year',
126 + 'views_all_time',
127 + 'last_login',
128 + 'logins_this_week',
129 + 'logins_this_month',
130 + 'logins_this_year',
131 + 'logins_all_time',
132 + 'joined',
133 + 'expires',
134 + );
135 +
136 + // These are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID) - Date items are manually handled further down.
137 + $default_columns = array(
138 + array( 'user', 'ID' ),
139 + array( 'user', 'user_login' ),
140 + array( 'user', 'membership' ),
141 + array( 'visits', 'last' ),
142 + array( 'visits', 'week' ),
143 + array( 'visits', 'month' ),
144 + array( 'visits', 'ytd' ),
145 + array( 'visits', 'alltime' ),
146 + array( 'views', 'week' ),
147 + array( 'views', 'month' ),
148 + array( 'views', 'ytd' ),
149 + array( 'views', 'alltime' ),
150 + array( 'logins', 'last' ),
151 + array( 'logins', 'week' ),
152 + array( 'logins', 'month' ),
153 + array( 'logins', 'ytd' ),
154 + array( 'logins', 'alltime' ),
155 + );
156 +
157 + $dateformat = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
158 +
159 + $csv_file_header = implode( ',', $csv_file_header_array ) . "\n";
160 +
161 + // Generate a temporary file to store the data in.
162 + $tmp_dir = apply_filters( 'pmpro_visits_views_logins_csv_export_tmp_dir', sys_get_temp_dir() );
163 + $filename = tempnam( $tmp_dir, 'pmpro_olcsv_' );
164 +
165 + // open in append mode
166 + $csv_fh = fopen( $filename, 'a' );
167 +
168 + // write the CSV header to the file
169 + fprintf( $csv_fh, '%s', $csv_file_header );
170 +
171 + $user_ids = $wpdb->get_col( $sqlQuery );
172 + $users_found = count( $user_ids );
173 +
174 + if ( empty( $user_ids ) ) {
175 + // send data to remote browser
176 + pmpro_transmit_report_data( $csv_fh, $filename, $headers );
177 + }
178 +
179 + if ( PMPRO_BENCHMARK ) {
180 + $pre_action_time = microtime( true );
181 + $pre_action_memory = memory_get_usage( true );
182 + }
183 +
184 + do_action( 'pmpro_before_visits_views_logins_csv_export', $user_ids );
185 +
186 + $i_start = 0;
187 + $i_limit = 0;
188 + $iterations = 1;
189 +
190 + if ( $users_found >= $max_record_loops ) {
191 + $iterations = ceil( $users_found / $max_record_loops );
192 + $i_limit = $max_record_loops;
193 + }
194 +
195 + $end = 0;
196 + $time_limit = ini_get( 'max_execution_time' );
197 +
198 + if ( PMPRO_BENCHMARK ) {
199 + error_log( "PMPRO_BENCHMARK - Total records to process: {$users_found}" );
200 + error_log( "PMPRO_BENCHMARK - Will process {$iterations} iterations of max {$max_record_loops} records per iteration." );
201 + $pre_iteration_time = microtime( true );
202 + $pre_iteration_memory = memory_get_usage( true );
203 + }
204 +
205 + for ( $ic = 1; $ic <= $iterations; $ic ++ ) {
206 +
207 + if ( PMPRO_BENCHMARK ) {
208 + $start_iteration_time = microtime( true );
209 + $start_iteration_memory = memory_get_usage( true );
210 + }
211 +
212 + // avoiding timeouts (modify max run-time for export)
213 + if ( $end != 0 ) {
214 +
215 + $iteration_diff = $end - $start;
216 + $new_time_limit = ceil( $iteration_diff * $iterations * 1.2 );
217 +
218 + if ( $time_limit < $new_time_limit ) {
219 + $time_limit = $new_time_limit;
220 + set_time_limit( $time_limit );
221 + }
222 + }
223 +
224 +
225 + // get the user list we should process
226 + $user_list = array_slice( $user_ids, $i_start, $max_record_loops );
227 +
228 + if ( PMPRO_BENCHMARK ) {
229 + $pre_data_time = microtime( true );
230 + $pre_data_memory = memory_get_usage( true );
231 + }
232 +
233 + foreach ( $theusers as $user ) {
234 + $csvoutput = array();
235 +
236 + // Get the visits, views and logins arrays. Set it to an object.
237 + $visits = (object) pmpro_reports_get_values_for_user( 'visits', $user->ID );
238 + $views = (object) pmpro_reports_get_values_for_user( 'views', $user->ID );
239 + $logins = (object) pmpro_reports_get_values_for_user( 'logins', $user->ID );
240 +
241 + if ( ! empty( $default_columns ) ) {
242 + $count = 0;
243 + foreach ( $default_columns as $col ) {
244 +
245 + // checking $object->property. note the double $$
246 + switch ( count( $col ) ) {
247 + case 3:
248 + $val = isset( ${$col[0]}->{$col[1]}->{$col[2]} ) ? ${$col[0]}->{$col[1]}->{$col[2]} : null;
249 + break;
250 +
251 + case 2:
252 + $val = isset( ${$col[0]}->{$col[1]} ) ? ${$col[0]}->{$col[1]} : null;
253 + break;
254 +
255 + default:
256 + $val = null;
257 + }
258 +
259 + array_push( $csvoutput, pmpro_enclose( $val ) );
260 + }
261 + }
262 +
263 + // Check if the user has an enddate or not.
264 + if ( $user->enddate ) {
265 + $enddate = pmpro_enclose( date_i18n( $dateformat, $user->enddate ) );
266 + } else {
267 + $enddate = __( 'Never', 'paid-memberships-pro' );
268 + }
269 +
270 + // Add joindate and enddate to the CSV export.
271 + array_push( $csvoutput, pmpro_enclose( date_i18n( $dateformat, $user->joindate ) ) );
272 + array_push( $csvoutput, $enddate ); // Don't pmpro_enclose, handled further up for date and not needed for strings.
273 +
274 + $line = implode( ',', $csvoutput ) . "\n";
275 +
276 + // output
277 + fprintf( $csv_fh, '%s', $line );
278 +
279 + $line = null;
280 + $csvoutput = null;
281 +
282 + $end = current_time( 'timestamp' );
283 +
284 +
285 +
286 + } // end of foreach users.
287 +
288 + if ( PMPRO_BENCHMARK ) {
289 + $after_data_time = microtime( true );
290 + $after_data_memory = memory_get_peak_usage( true );
291 +
292 + $time_processing_data = $after_data_time - $start_time;
293 + $memory_processing_data = $after_data_memory - $start_memory;
294 +
295 + list($sec, $usec) = explode( '.', $time_processing_data );
296 +
297 + error_log( "PMPRO_BENCHMARK - Time processing data: {$sec}.{$usec} seconds" );
298 + error_log( 'PMPRO_BENCHMARK - Peak memory usage: ' . number_format( $memory_processing_data, false, '.', ',' ) . ' bytes' );
299 + }
300 + $user_list = null;
301 + wp_cache_flush();
302 + }
303 + // If this was run via Toolkit API, we don't have to output the CSV file.
304 + if ( empty( $_REQUEST['pmpro_no_download'] ) ) {
305 + pmpro_transmit_report_data( $csv_fh, $filename, $headers );
306 + }
307 +
308 + /**
309 + * Enclose items passed through to ensure data structure is valid for export CSV.
310 + *
311 + * @param mixed $string|$date Enclose and return a given string, required for CSV files.
312 + * @return string
313 + */
314 + function pmpro_enclose( $s ) {
315 + return '"' . str_replace( '"', '\\"', $s ) . '"';
316 + }
317 +
318 + /**
319 + * Write the data to the CSV and create the CSV file.
320 + *
321 + * @param mixed $csv_fh The temp file we opened and write to.
322 + * @param string $filename The name of the CSV file.
323 + * @param array $headers The headers for the CSV file.
324 + * @return void
325 + */
326 + function pmpro_transmit_report_data( $csv_fh, $filename, $headers = array() ) {
327 +
328 + // close the temp file
329 + fclose( $csv_fh );
330 +
331 + if ( version_compare( phpversion(), '5.3.0', '>' ) ) {
332 +
333 + // make sure we get the right file size
334 + clearstatcache( true, $filename );
335 + } else {
336 + // for any PHP version prior to v5.3.0
337 + clearstatcache();
338 + }
339 +
340 + // did we accidentally send errors/warnings to browser?
341 + if ( headers_sent() ) {
342 + echo esc_html( str_repeat( '-', 75 ) ) . "<br/>\n";
343 + echo 'Please open a support case and paste in the warnings/errors you see above this text to\n ';
344 + echo 'the <a href="http://paidmembershipspro.com/support/?utm_source=plugin&utm_medium=pmpro-visits-views-logins-csv&utm_campaign=support" target="_blank">Paid Memberships Pro support forum</a><br/>\n';
345 + echo esc_html( str_repeat( '-', 75 ) ) . "<br/>\n";
346 + echo wp_kses_post( file_get_contents( $filename ) );
347 + echo esc_html( str_repeat( '-', 75 ) ) . "<br/>\n";
348 + }
349 +
350 + // transmission
351 + if ( ! empty( $headers ) ) {
352 + // set the download size
353 + $headers[] = 'Content-Length: ' . filesize( $filename );
354 +
355 + // set headers
356 + foreach ( $headers as $header ) {
357 + header( $header . "\r\n" );
358 + }
359 +
360 + // disable compression for the duration of file download
361 + if ( ini_get( 'zlib.output_compression' ) ) {
362 + ini_set( 'zlib.output_compression', 'Off' );
363 + }
364 +
365 + if ( function_exists( 'fpassthru' ) ) {
366 + // use fpassthru to output the csv
367 + $csv_fh = fopen( $filename, 'rb' );
368 + fpassthru( $csv_fh );
369 + fclose( $csv_fh );
370 + } else {
371 + // use readfile() if fpassthru() is disabled (like on Flywheel Hosted)
372 + readfile( $filename );
373 + }
374 +
375 + // remove the temp file
376 + unlink( $filename );
377 + }
378 +
379 + // allow user to clean up after themselves
380 + do_action( 'pmpro_after_visits_views_logins_csv_export' );
381 + exit;
382 + }
383 +