Completed
Push — update/sitemaps-module-info-li... ( 810de8...355356 )
by
unknown
21:57 queued 10:09
created

Tracks_Event::record()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * @autounit nosara tracks-client
5
 *
6
 * Example Usage:
7
```php
8
	require_once( dirname(__FILE__) . 'path/to/tracks/class.tracks-event' );
9
10
	$event = new Jetpack_Tracks_Event( array(
11
		'_en'        => $event_name,       // required
12
		'_ui'        => $user_id,          // required unless _ul is provided
13
		'_ul'        => $user_login,       // required unless _ui is provided
14
15
		// Optional, but recommended
16
		'_via_ip'    => $client_ip,        // for geo, etc.
17
18
		// Possibly useful to set some context for the event
19
		'_via_ua'    => $client_user_agent,
20
		'_via_url'   => $client_url,
21
		'_via_ref'   => $client_referrer,
22
23
		// For user-targeted tests
24
		'abtest_name'        => $abtest_name,
25
		'abtest_variation'   => $abtest_variation,
26
27
		// Your application-specific properties
28
		'custom_property'    => $some_value,
29
	) );
30
31
	if ( is_wp_error( $event->error ) ) {
32
		// Handle the error in your app
33
	}
34
35
	$bump_and_redirect_pixel = $event->build_signed_pixel_url();
36
```
37
 */
38
39
require_once( dirname(__FILE__) . '/class.tracks-client.php' );
40
41
class Jetpack_Tracks_Event {
42
	const EVENT_NAME_REGEX = '/^(([a-z0-9]+)_){2}([a-z0-9_]+)$/';
43
	const PROP_NAME_REGEX = '/^[a-z_][a-z0-9_]*$/';
44
	public $error;
45
46
	function __construct( $event ) {
47
		$_event = self::validate_and_sanitize( $event );
48
		if ( is_wp_error( $_event ) ) {
49
			$this->error = $_event;
50
			return;
51
		}
52
53
		foreach( $_event as $key => $value ) {
54
			$this->{$key} = $value;
55
		}
56
	}
57
58
	function record() {
59
		return Jetpack_Tracks_Client::record_event( $this );
60
	}
61
62
	/**
63
	 * Annotate the event with all relevant info.
64
	 * @param  mixed		$event Object or (flat) array
65
	 * @return mixed        The transformed event array or WP_Error on failure.
66
	 */
67
	static function validate_and_sanitize( $event ) {
68
		$event = (object) $event;
69
70
		// Required
71
		if ( ! $event->_en ) {
72
			return new WP_Error( 'invalid_event', 'A valid event must be specified via `_en`', 400 );
73
		}
74
75
		// delete non-routable addresses otherwise geoip will discard the record entirely
76
		if ( property_exists( $event, '_via_ip' ) && preg_match( '/^192\.168|^10\./', $event->_via_ip ) ) {
77
			unset($event->_via_ip);
78
		}
79
80
		$validated = array(
81
			'browser_type'      => Jetpack_Tracks_Client::BROWSER_TYPE,
82
			'_aua'              => Jetpack_Tracks_Client::get_user_agent(),
83
		);
84
85
		$_event = (object) array_merge( (array) $event, $validated );
86
87
		// If you want to blacklist property names, do it here.
88
89
		// Make sure we have an event timestamp.
90
		if ( ! isset( $_event->_ts ) ) {
91
			$_event->_ts = Jetpack_Tracks_Client::build_timestamp();
92
		}
93
94
		return $_event;
95
	}
96
97
	/**
98
	 * Build a pixel URL that will send a Tracks event when fired.
99
	 * On error, returns an empty string ('').
100
	 *
101
	 * @return string A pixel URL or empty string ('') if there were invalid args.
102
	 */
103
	function build_pixel_url() {
104
		if ( $this->error ) {
105
			return '';
106
		}
107
108
		$args = get_object_vars( $this );
109
110
		// Request Timestamp and URL Terminator must be added just before the HTTP request or not at all.
111
		unset( $args['_rt'] );
112
		unset( $args['_'] );
113
114
		$validated = self::validate_and_sanitize( $args );
115
116
		if ( is_wp_error( $validated ) )
117
			return '';
118
119
		return Jetpack_Tracks_Client::PIXEL . '?' . http_build_query( $validated );
120
	}
121
122
	static function event_name_is_valid( $name ) {
123
		return preg_match( Jetpack_Tracks_Event::EVENT_NAME_REGEX, $name );
124
	}
125
126
	static function prop_name_is_valid( $name ) {
127
		return preg_match( Jetpack_Tracks_Event::PROP_NAME_REGEX, $name );
128
	}
129
130
	static function scrutinize_event_names( $event ) {
131
		if ( ! Jetpack_Tracks_Event::event_name_is_valid( $event->_en ) ) {
132
			return;
133
		}
134
135
		$whitelisted_key_names = array(
136
			'anonId',
137
			'Browser_Type',
138
		);
139
140
		foreach ( array_keys( (array) $event ) as $key ) {
141
			if ( in_array( $key, $whitelisted_key_names ) ) {
142
				continue;
143
			}
144
			if ( ! Jetpack_Tracks_Event::prop_name_is_valid( $key ) ) {
145
				return;
146
			}
147
		}
148
	}
149
}
150