Completed
Push — master ( 7d0274...3690ae )
by
unknown
10:22 queued 05:14
created

WPSC_Tracking::check_for_settings_optin()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 3
nc 2
nop 2
dl 0
loc 5
rs 9.2
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style introduced by
End of line character is invalid; expected "\n" but found "\r\n"
Loading history...
2
3
/**
4
 * Tracking functions for reporting plugin usage to the WPEC site for users that have opted in
5
 *
6
 * @package     WPEC
7
 * @subpackage  Admin
8
 * @copyright   Copyright (c) 2017
9
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
10
 * @since       3.12.0
11
*/
12
13
// Exit if accessed directly
14
if ( ! defined( 'ABSPATH' ) ) exit;
15
16
/**
17
 * Usage tracking
18
 *
19
 * @access public
20
 * @since  3.12.0
21
 * @return void
22
 */
23
class WPSC_Tracking {
24
25
	/**
26
	 * The data to send to the WPEC site
27
	 *
28
	 * @since 3.12.0
29
	 * @access private
30
	 */
31
	private $data;
32
33
	/**
34
	 * Where we are sending the data to
35
	 *
36
	 * @since 3.12.0
37
	 * @access private
38
	 */
39
	private $api_url = 'https://wpecommerce.org/';
40
41
	/**
42
	 * Get things going
43
	 *
44
	 * @since 3.12.0
45
	 * @access public
46
	 */
47
	public function __construct() {
48
		add_action( 'init'                           , array( $this, 'schedule_send' ) );
49
		add_action( 'wpsc_opt_into_tracking'         , array( $this, 'check_for_optin' ) );
50
		add_action( 'wpsc_opt_out_of_tracking'       , array( $this, 'check_for_optout' ) );
51
		add_action( 'wpsc_settings_page_save_options', array( $this, 'check_for_settings_optin' ), 10, 2 );
52
		add_action( 'admin_notices'                  , array( $this, 'admin_notice' ) );
53
	}
54
55
	/**
56
	 * Schedule a weekly checkin
57
	 *
58
	 * @since 3.12.0
59
	 * @access public
60
	 * @return void
61
	 */
62
	public function schedule_send() {
63
64
		if ( isset( $_REQUEST['wpsc_tracking_action'] ) && ( $_REQUEST['wpsc_tracking_action'] == 'opt_into_tracking' ) ) {
65
			do_action( 'wpsc_opt_into_tracking' );
66
		}
67
68
		if ( isset( $_REQUEST['wpsc_tracking_action'] ) && ( $_REQUEST['wpsc_tracking_action'] == 'opt_out_of_tracking' ) ) {
69
			do_action( 'wpsc_opt_out_of_tracking' );
70
		}
71
72
		// We send once a week (while tracking is allowed) to check in, which can be used to determine active sites
73
		add_action( 'wpsc_weekly_cron_task', array( $this, 'send_data' ) );
74
	}
75
76
	/**
77
	 * Check if the user has opted into tracking
78
	 *
79
	 * @since 3.12.0
80
	 * @access private
81
	 * @return bool
82
	 */
83
	private function tracking_allowed() {
84
		return (bool) get_option( 'wpsc_usage_tracking', false );
85
	}
86
87
	/**
88
	 * Get the last time a checkin was sent
89
	 *
90
	 * @since 3.12.0
91
	 * @access private
92
	 * @return false|string
93
	 */
94
	private function get_last_send() {
95
		return get_option( 'wpsc_usage_tracking_last_send' );
96
	}
97
98
	/**
99
	 * Send the data to the WPEC server
100
	 *
101
	 * @since 3.12.0
102
	 * @access private
103
	 * @return void
104
	 */
105
	public function send_data( $override = false ) {
106
107
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
108
			return;
109
		}
110
111
		$home_url = trailingslashit( home_url() );
112
113
		// Allows us to stop our own site from checking in, and a filter for our additional sites
114
		if ( true === apply_filters( 'wpsc_disable_tracking_checkin', false ) ) {
115
			return false;
116
		}
117
118
		if ( ! $this->tracking_allowed() && ! $override ) {
119
			return false;
120
		}
121
122
		// Send a maximum of once per week
123
		$last_send = $this->get_last_send();
124
125
		if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) ) {
126
			return false;
127
		}
128
129
		$this->setup_data();
130
131
		$request = wp_safe_remote_post( $this->api_url . '?wpsc_tracking_action=checkin', array(
132
			'timeout'     => 20,
133
			'redirection' => 5,
134
			'httpversion' => '1.1',
135
			'blocking'    => true,
136
			'body'        => $this->data,
137
			'user-agent'  => 'WPEC/' . WPSC_VERSION . '; ' . get_bloginfo( 'url' )
138
		) );
139
140
		if ( is_wp_error( $request ) ) {
141
			return $request;
142
		}
143
144
		update_option( 'wpsc_usage_tracking_last_send', time() );
145
146
		return true;
147
	}
148
149
	/**
150
	 * Check for a new opt-in via the admin notice
151
	 *
152
	 * @since 3.12.0
153
	 * @access public
154
	 * @return void
155
	 */
156
	public function check_for_optin() {
157
158
		update_option( 'wpsc_usage_tracking', '1' );
159
160
		$this->send_data( true );
161
162
		update_option( 'wpsc_usage_tracking_notice', '1' );
163
164
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
165
		exit;
166
	}
167
168
	/**
169
	 * Check for opt-out via the admin notice
170
	 *
171
	 * @since 3.12.0
172
	 * @access public
173
	 * @return void
174
	 */
175
	public function check_for_optout() {
176
177
		$allowed = get_option( 'wpsc_usage_tracking', false );
178
179
		if ( $allowed ) {
180
			delete_option( 'wpsc_usage_tracking' );
181
		}
182
183
		update_option( 'wpsc_usage_tracking_notice', '1' );
184
185
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
186
		exit;
187
	}
188
189
	/**
190
	 * Check for opt-in via the settings page
191
	 *
192
	 * @since 3.12.0
193
	 * @access public
194
	 * @return void
195
	 */
196
	public function check_for_settings_optin( $option, $value ) {
197
		if( isset( $option ) && $option == 'wpsc_usage_tracking' && $value == '1'  ) {
198
			$this->send_data( true );
199
		}
200
	}
201
202
	/**
203
	 * Display the admin notice to users that have not opted-in or out
204
	 *
205
	 * @since 3.12.0
206
	 * @access public
207
	 * @return void
208
	 */
209
	public function admin_notice() {
210
		$hide_notice = get_option( 'wpsc_usage_tracking_notice' );
211
212
		if ( $hide_notice ) {
213
			return;
214
		}
215
216
		if ( get_option( 'wpsc_usage_tracking', false ) ) {
217
			return;
218
		}
219
220
		if ( ! current_user_can( 'manage_options' ) ) {
221
			return;
222
		}
223
224
		if (
225
			stristr( network_site_url( '/' ), 'dev'       ) !== false ||
226
			stristr( network_site_url( '/' ), 'localhost' ) !== false ||
227
			stristr( network_site_url( '/' ), ':8888'     ) !== false // This is common with MAMP on OS X
228
		) {
229
			update_option( 'wpsc_usage_tracking_notice', '1' );
230
		} else {
231
			$optin_url  = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_into_tracking' ) );
232
			$optout_url = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_out_of_tracking' ) );
233
			$extensions_url = $this->api_url . 'store/';
234
			echo '<div class="updated"><p>';
235
				echo sprintf( __( 'Allow WP eCommerce to track plugin usage? Opt-in to tracking and our newsletter and immediately be emailed a 20%s discount to the WPEC shop, valid towards the <a href="%s" target="_blank">purchase of extensions</a>. No sensitive data is tracked.', 'wp-e-commerce' ), '%', $extensions_url );
236
				echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-secondary">' . __( 'Allow', 'wp-e-commerce' ) . '</a>';
237
				echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary">' . __( 'Do not allow', 'wp-e-commerce' ) . '</a>';
238
			echo '</p></div>';
239
		}
240
	}
241
242
	/**
243
	 * Setup the data that is going to be tracked
244
	 *
245
	 * @since 3.12.0
246
	 * @access private
247
	 * @return void
248
	 */
249
	private function setup_data() {
250
251
		$data = array();
252
253
		// General site info
254
		$data['url']                = home_url();
255
		$data['email']              = get_option( 'admin_email' );
256
257
		// Theme info
258
		$data['theme']              = self::get_theme_info();
259
260
		// WordPress Info
261
		$data['wp']                 = self::get_wordpress_info();
262
263
		// Server Info
264
		$data['server']             = self::get_server_info();
265
266
		// Plugin info
267
		$all_plugins                = self::get_all_plugins();
268
		$data['active_plugins']     = $all_plugins['active_plugins'];
269
		$data['inactive_plugins']   = $all_plugins['inactive_plugins'];
270
271
		// WPEC Related Section
272
		$data['wpec']               = self::get_wpec_info();
273
274
		// Store count info
275
		$data['users']              = self::get_user_counts();
276
		$data['products']           = self::get_product_counts();
277
		$data['orders']             = self::get_order_counts();
278
279
		// Payment gateway info
280
		$data['gateways']           = self::get_active_payment_gateways();
281
282
		// Shipping method info
283
		$data['shipping_methods']   = self::get_active_shipping_methods();
284
285
		// Template overrides
286
		$data['template_overrides'] = self::get_all_template_overrides();
287
288
		$this->data = $data;
289
	}
290
291
	/**
292
	 * Get the current theme info, theme name and version.
293
	 *
294
	 * @since 3.12.0
295
	 * @return array
296
	 */
297
	public static function get_theme_info() {
298
		$theme_data        = wp_get_theme();
299
300
		return array(
301
			'name'        => $theme_data->Name,
302
			'version'     => $theme_data->Version,
303
			'child_theme' => is_child_theme() ? 'Yes' : 'No'
304
		);
305
	}
306
307
	/**
308
	 * Get WordPress related data.
309
	 *
310
	 * @since 3.12.0
311
	 * @return array
312
	 */
313
	private static function get_wordpress_info() {
314
		$wp_data = array();
315
316
		$memory = self::wpsc_let_to_num( WP_MEMORY_LIMIT );
317
318
		if ( function_exists( 'memory_get_usage' ) ) {
319
			$system_memory = self::wpsc_let_to_num( @ini_get( 'memory_limit' ) );
0 ignored issues
show
Coding Style introduced by
Silencing errors is discouraged
Loading history...
320
			$memory        = max( $memory, $system_memory );
321
		}
322
323
		$wp_data['memory_limit'] = size_format( $memory );
324
		$wp_data['debug_mode']   = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No';
325
		$wp_data['locale']       = get_locale();
326
		$wp_data['version']      = get_bloginfo( 'version' );
327
		$wp_data['multisite']    = is_multisite() ? 'Yes' : 'No';
328
329
		return $wp_data;
330
	}
331
332
	/**
333
	 * Get server related info.
334
	 *
335
	 * @since 3.12.0
336
	 * @return array
337
	 */
338
	private static function get_server_info() {
339
		$server_data = array();
340
341
		if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
342
			$server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
343
		}
344
345
		if ( function_exists( 'phpversion' ) ) {
346
			$server_data['php_version'] = phpversion();
347
		}
348
349
		if ( function_exists( 'ini_get' ) ) {
350
			$server_data['php_post_max_size'] = size_format( self::wpsc_let_to_num( ini_get( 'post_max_size' ) ) );
351
			$server_data['php_time_limt']      = ini_get( 'max_execution_time' );
352
			$server_data['php_max_input_vars'] = ini_get( 'max_input_vars' );
353
			$server_data['php_suhosin']        = extension_loaded( 'suhosin' ) ? 'Yes' : 'No';
354
		}
355
356
		global $wpdb;
357
358
		$server_data['mysql_version'] = $wpdb->db_version();
359
360
		$server_data['php_max_upload_size']  = size_format( wp_max_upload_size() );
361
		$server_data['php_default_timezone'] = date_default_timezone_get();
362
		$server_data['php_soap']             = class_exists( 'SoapClient' )   ? 'Yes' : 'No';
363
		$server_data['php_fsockopen']        = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
364
		$server_data['php_curl']             = function_exists( 'curl_init' ) ? 'Yes' : 'No';
365
366
		return $server_data;
367
	}
368
369
	/**
370
	 * Get all plugins grouped into activated or not.
371
	 *
372
	 * @since 3.12.0
373
	 * @return array
374
	 */
375
	private static function get_all_plugins() {
376
377
		// Ensure get_plugins function is loaded
378
		if ( ! function_exists( 'get_plugins' ) ) {
379
			include ABSPATH . '/wp-admin/includes/plugin.php';
380
		}
381
382
		$plugins        	 = get_plugins();
383
		$active_plugins_keys = get_option( 'active_plugins', array() );
384
		$active_plugins 	 = array();
385
386
		foreach ( $plugins as $k => $v ) {
387
			// Take care of formatting the data how we want it.
388
			$formatted = array();
389
			$formatted['name'] = strip_tags( $v['Name'] );
390
391
			if ( isset( $v['Version'] ) ) {
392
				$formatted['version'] = strip_tags( $v['Version'] );
393
			}
394
395
			if ( isset( $v['Author'] ) ) {
396
				$formatted['author'] = strip_tags( $v['Author'] );
397
			}
398
399
			if ( isset( $v['Network'] ) ) {
400
				$formatted['network'] = strip_tags( $v['Network'] );
401
			}
402
403
			if ( isset( $v['PluginURI'] ) ) {
404
				$formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
405
			}
406
407
			if ( in_array( $k, $active_plugins_keys ) ) {
408
				// Remove active plugins from list so we can show active and inactive separately
409
				unset( $plugins[ $k ] );
410
				$active_plugins[ $k ] = $formatted;
411
			} else {
412
				$plugins[ $k ] = $formatted;
413
			}
414
		}
415
416
		return array(
417
			'active_plugins'   => $active_plugins,
418
			'inactive_plugins' => $plugins
419
		);
420
	}
421
422
	/**
423
	 * Get WP eCommerce related info.
424
	 *
425
	 * @since 3.12.0
426
	 * @return array
427
	 */
428
	private static function get_wpec_info() {
429
		$wpec_data = array();
430
431
		$wpec_data['version'] = WPSC_VERSION;
432
		$wpec_data['url']     = WPSC_URL;
433
		$wpec_data['debug']   = WPSC_DEBUG;
434
435
		return $wpec_data;
436
	}
437
438
	/**
439
	 * Get user totals based on user role.
440
	 *
441
	 * @since 3.12.0
442
	 * @return array
443
	 */
444
	private static function get_user_counts() {
445
		$user_count          = array();
446
447
		$user_count_data     = count_users();
448
		$user_count['total'] = $user_count_data['total_users'];
449
450
		// Get user count based on user role
451
		foreach ( $user_count_data['avail_roles'] as $role => $count ) {
452
			$user_count[ $role ] = $count;
453
		}
454
455
		return $user_count;
456
	}
457
458
	/**
459
	 * Get product totals based on product type.
460
	 *
461
	 * @since 3.12.0
462
	 * @return array
463
	 */
464
	private static function get_product_counts() {
465
		$product_count          = array();
466
467
		$product_count_data     = wp_count_posts( 'wpsc-product' );
468
		$product_count['total'] = $product_count_data->publish;
469
470
		return $product_count;
471
	}
472
473
	/**
474
	 * Get order counts based on order status.
475
	 *
476
	 * @since 3.12.0
477
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
478
	 */
479
	private static function get_order_counts() {
480
		global $wpdb;
481
482
		$order_count = array();
483
		$curr_year   = date( 'Y' );
484
485
		$result = $wpdb->get_row(
486
			"SELECT FROM_UNIXTIME( DATE,  '%Y' ) AS year
487
			FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
488
			WHERE FROM_UNIXTIME( DATE,  '%Y' ) > 2000
489
			AND processed IN ( 3, 4, 5 )
490
			ORDER BY date ASC
491
			LIMIT 1 ", ARRAY_A
492
		);
493
494
		$start_year = $result['year'];
495
496
		if ( $start_year ) {
497
			while ( $start_year <= $curr_year ) {
498
				$sql = $wpdb->prepare(
499
					"SELECT SUM(`totalprice`) as total,
500
					COUNT(*) as cnt
501
					FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
502
					WHERE `processed` IN (3,4,5) AND `date` BETWEEN %s AND %s",
503
					mktime( 0, 0, 0, 1, 1, $start_year ),
504
					mktime( 23, 59, 59, 12, 31, $start_year )
505
				);
506
507
				$orders = $wpdb->get_row( $sql, ARRAY_A );
508
509
				if ( $orders ) {
510
					$order_count[ $start_year ] = array(
511
						'orders' => $orders['cnt'],
512
						'total'  => $orders['total']
513
					);
514
				}
515
516
				$start_year++;
517
			}
518
		}
519
520
		$currency_data           = WPSC_Countries::get_currency_data( get_option( 'currency_type' ), true );
521
		$order_count['currency'] = $currency_data['code'];
522
523
		return $order_count;
524
	}
525
526
	/**
527
	 * Get a list of all active payment gateways.
528
	 *
529
	 * @since 3.12.0
530
	 * @return array
531
	 */
532
	private static function get_active_payment_gateways() {
533
		$active_gateways = array();
534
535
		// First get merchant V2 gateways
536
		if ( _wpsc_is_merchant_v2_active() ) {
537
			$gateways = _wpsc_merchant_v2_get_active_gateways();
538
539
			if ( ! empty( $gateways ) ) {
540
				foreach ( $gateways as $id => $gateway ) {
541
					$active_gateways['mv2'][ $id ] = array( 'title' => $gateway['name'] );
542
				}
543
			}
544
		}
545
546
		// Merchant V3 gateways if any
547
		$gateways = WPSC_Payment_Gateways::get_active_gateways();
548
549
		if ( ! empty( $gateways ) ) {
550
			foreach ( $gateways as $id => $gateway ) {
551
				$meta = WPSC_Payment_Gateways::get_meta( $gateway );
552
				$name = isset( $meta['name'] ) ? $meta['name'] : $meta['class'];
553
554
				$active_gateways['mv3'][ $id ] = array( 'title' => $name );
555
			}
556
		}
557
558
		return $active_gateways;
559
	}
560
561
	/**
562
	 * Get a list of all active shipping methods.
563
	 *
564
	 * @since 3.12.0
565
	 * @return array
566
	 */
567
	private static function get_active_shipping_methods() {
568
		$active_methods   = array();
569
570
		if ( wpsc_is_shipping_enabled() ) {
571
			global $wpsc_shipping_modules;
572
573
			$custom_shipping = get_option( 'custom_shipping_options' );
574
575
			foreach ( (array) $custom_shipping as $id => $shipping ) {
576
				$module_title = isset( $wpsc_shipping_modules[ $shipping ] ) && is_callable( array( $wpsc_shipping_modules[ $shipping ], 'getName' ) ) ? $wpsc_shipping_modules[ $shipping ]->getName() : '';
577
				$active_methods[ $id ] = array( 'name' => $shipping, 'title' => $module_title );
578
			}
579
		}
580
581
		return $active_methods;
582
	}
583
584
	/**
585
	 * Look for any template override and return filenames.
586
	 *
587
	 * @todo Implement a method of checking template overrides for tev2.
588
	 * @since 3.12.0
589
	 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|false? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
590
	 */
591
	private static function get_all_template_overrides() {
592
		$override_data  = array();
593
594
		$te = get_option( 'wpsc_get_active_theme_engine', '1.0' );
595
596
		if( '1.0' == $te ) {
597
			$override_data = wpsc_check_theme_location();
598
		}
599
600
		return $override_data;
601
	}
602
603
	/**
604
	 * let_to_num function.
605
	 *
606
	 * This function transforms the php.ini notation for numbers (like '2M') to an integer.
607
	 *
608
	 * @since 3.12.0
609
	 * @param $size
610
	 * @return int
611
	 */
612
	private static function wpsc_let_to_num( $size ) {
613
		$l   = substr( $size, -1 );
614
		$ret = substr( $size, 0, -1 );
615
		switch ( strtoupper( $l ) ) {
616
			case 'P':
617
				$ret *= 1024;
618
			case 'T':
619
				$ret *= 1024;
620
			case 'G':
621
				$ret *= 1024;
622
			case 'M':
623
				$ret *= 1024;
624
			case 'K':
625
				$ret *= 1024;
626
		}
627
		return $ret;
628
	}
629
}
630
631
$wpsc_tracking = new WPSC_Tracking;
632