Completed
Push — try/namespacing-all-the-things ( 457764 )
by
unknown
08:24
created

Client::build_pixel_url()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Automattic\Jetpack\Tracks;
3
4
/**
5
 * Jetpack_Tracks_Client
6
 * @autounit nosara tracks-client
7
 *
8
 * Send Tracks events on behalf of a user
9
 *
10
 * Example Usage:
11
```php
12
	require( dirname(__FILE__).'path/to/tracks/class.tracks-client' );
13
14
	$result = Jetpack_Tracks_Client::record_event( array(
15
		'_en'        => $event_name,       // required
16
		'_ui'        => $user_id,          // required unless _ul is provided
17
		'_ul'        => $user_login,       // required unless _ui is provided
18
19
		// Optional, but recommended
20
		'_ts'        => $ts_in_ms,         // Default: now
21
		'_via_ip'    => $client_ip,        // we use it for geo, etc.
22
23
		// Possibly useful to set some context for the event
24
		'_via_ua'    => $client_user_agent,
25
		'_via_url'   => $client_url,
26
		'_via_ref'   => $client_referrer,
27
28
		// For user-targeted tests
29
		'abtest_name'        => $abtest_name,
30
		'abtest_variation'   => $abtest_variation,
31
32
		// Your application-specific properties
33
		'custom_property'    => $some_value,
34
	) );
35
36
	if ( is_wp_error( $result ) ) {
37
		// Handle the error in your app
38
	}
39
```
40
 */
41
42
class Client {
43
	const PIXEL = 'https://pixel.wp.com/t.gif';
44
	const BROWSER_TYPE = 'php-agent';
45
	const USER_AGENT_SLUG = 'tracks-client';
46
	const VERSION = '0.3';
47
48
	/**
49
	 * record_event
50
	 * @param  mixed  $event Event object to send to Tracks. An array will be cast to object. Required.
51
	 *                       Properties are included directly in the pixel query string after light validation.
52
	 * @return mixed         True on success, WP_Error on failure
53
	 */
54
	static function record_event( $event ) {
55
		if ( ! Jetpack::jetpack_tos_agreed() || ! empty( $_COOKIE['tk_opt-out'] ) ) {
56
			return false;
57
		}
58
		
59
		if ( ! $event instanceof Event ) {
60
			$event = new Event( $event );
61
		}
62
		if ( is_wp_error( $event ) ) {
63
			return $event;
64
		}
65
66
		$pixel = $event->build_pixel_url( $event );
0 ignored issues
show
Unused Code introduced by
The call to Event::build_pixel_url() has too many arguments starting with $event.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
67
68
		if ( ! $pixel ) {
69
			return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 );
70
		}
71
72
		return self::record_pixel( $pixel );
73
	}
74
75
	/**
76
	 * Synchronously request the pixel
77
	 */
78
	static function record_pixel( $pixel ) {
79
		// Add the Request Timestamp and URL terminator just before the HTTP request.
80
		$pixel .= '&_rt=' . self::build_timestamp() . '&_=_';
81
82
		$response = wp_remote_get( $pixel, array(
83
			'blocking'    => true, // The default, but being explicit here :)
84
			'timeout'     => 1,
85
			'redirection' => 2,
86
			'httpversion' => '1.1',
87
			'user-agent'  => self::get_user_agent(),
88
		) );
89
90
		if ( is_wp_error( $response ) ) {
91
			return $response;
92
		}
93
94
		$code = isset( $response['response']['code'] ) ? $response['response']['code'] : 0;
95
96
		if ( $code !== 200 ) {
97
			return new WP_Error( 'request_failed', 'Tracks pixel request failed', $code );
98
		}
99
100
		return true;
101
	}
102
103
	static function get_user_agent() {
104
		return Client::USER_AGENT_SLUG . '-v' . Client::VERSION;
105
	}
106
107
	/**
108
	 * Build an event and return its tracking URL
109
	 * @deprecated          Call the `build_pixel_url` method on a Jetpack_Tracks_Event object instead.
110
	 * @param  array $event Event keys and values
111
	 * @return string       URL of a tracking pixel
112
	 */
113
	static function build_pixel_url( $event ) {
114
		$_event = new Event( $event );
115
		return $_event->build_pixel_url();
116
	}
117
118
	/**
119
	 * Validate input for a tracks event.
120
	 * @deprecated          Instantiate a Jetpack_Tracks_Event object instead
121
	 * @param  array $event Event keys and values
122
	 * @return mixed        Validated keys and values or WP_Error on failure
123
	 */
124
	private static function validate_and_sanitize( $event ) {
125
		$_event = new Event( $event );
126
		if ( is_wp_error( $_event ) ) {
127
			return $_event;
128
		}
129
		return get_object_vars( $_event );
130
	}
131
132
	// Milliseconds since 1970-01-01
133
	static function build_timestamp() {
134
		$ts = round( microtime( true ) * 1000 );
135
		return number_format( $ts, 0, '', '' );
136
	}
137
138
	/**
139
	 * Grabs the user's anon id from cookies, or generates and sets a new one
140
	 *
141
	 * @return string An anon id for the user
142
	 */
143
	static function get_anon_id() {
144
		static $anon_id = null;
145
146
		if ( ! isset( $anon_id ) ) {
147
148
			// Did the browser send us a cookie?
149
			if ( isset( $_COOKIE[ 'tk_ai' ] ) && preg_match( '#^[A-Za-z0-9+/=]{24}$#', $_COOKIE[ 'tk_ai' ] ) ) {
150
				$anon_id = $_COOKIE[ 'tk_ai' ];
151
			} else {
152
153
				$binary = '';
154
155
				// Generate a new anonId and try to save it in the browser's cookies
156
				// Note that base64-encoding an 18 character string generates a 24-character anon id
157
				for ( $i = 0; $i < 18; ++$i ) {
158
					$binary .= chr( mt_rand( 0, 255 ) );
159
				}
160
161
				$anon_id = 'jetpack:' . base64_encode( $binary );
162
163
				if ( ! headers_sent()
164
					&& ! ( defined( 'REST_REQUEST' ) && REST_REQUEST )
165
					&& ! ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
166
				) {
167
					setcookie( 'tk_ai', $anon_id );
168
				}
169
			}
170
		}
171
172
		return $anon_id;
173
	}
174
}
175