PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
jetpack / jetpack_vendor / automattic / jetpack-connection / legacy / class-jetpack-tracks-client.php

class-jetpack-tracks-client.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-connection/legacy/class-jetpack-tracks-client.php

231 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Legacy Jetpack Tracks Client
4 *
5 * @package automattic/jetpack-tracking
6 */
7
8 use Automattic\Jetpack\Connection\Manager;
9
10 /**
11 * Jetpack_Tracks_Client
12 *
13 * Send Tracks events on behalf of a user
14 *
15 * Example Usage:
16 ```php
17 require( dirname(__FILE__).'path/to/tracks/class-jetpack-tracks-client.php' );
18
19 $result = Jetpack_Tracks_Client::record_event( array(
20 '_en' => $event_name, // required
21 '_ui' => $user_id, // required unless _ul is provided
22 '_ul' => $user_login, // required unless _ui is provided
23
24 // Optional, but recommended
25 '_ts' => $ts_in_ms, // Default: now
26 '_via_ip' => $client_ip, // we use it for geo, etc.
27
28 // Possibly useful to set some context for the event
29 '_via_ua' => $client_user_agent,
30 '_via_url' => $client_url,
31 '_via_ref' => $client_referrer,
32
33 // For user-targeted tests
34 'abtest_name' => $abtest_name,
35 'abtest_variation' => $abtest_variation,
36
37 // Your application-specific properties
38 'custom_property' => $some_value,
39 ) );
40
41 if ( is_wp_error( $result ) ) {
42 // Handle the error in your app
43 }
44 ```
45 */
46 class Jetpack_Tracks_Client {
47 const PIXEL = 'https://pixel.wp.com/t.gif';
48 const BROWSER_TYPE = 'php-agent';
49 const USER_AGENT_SLUG = 'tracks-client';
50 const VERSION = '0.3';
51
52 /**
53 * Stores the Terms of Service Object Reference.
54 *
55 * @var null
56 */
57 private static $terms_of_service = null;
58
59 /**
60 * Record an event.
61 *
62 * @param mixed $event Event object to send to Tracks. An array will be cast to object. Required.
63 * Properties are included directly in the pixel query string after light validation.
64 * @return mixed True on success, WP_Error on failure
65 */
66 public static function record_event( $event ) {
67 if ( ! self::$terms_of_service ) {
68 self::$terms_of_service = new \Automattic\Jetpack\Terms_Of_Service();
69 }
70
71 // Don't track users who have opted out or not agreed to our TOS, or are not running an active Jetpack.
72 if ( ! self::$terms_of_service->has_agreed() || ! empty( $_COOKIE['tk_opt-out'] ) ) {
73 return false;
74 }
75
76 if ( ! $event instanceof Jetpack_Tracks_Event ) {
77 $event = new Jetpack_Tracks_Event( $event );
78 }
79 if ( is_wp_error( $event ) ) {
80 return $event;
81 }
82
83 $pixel = $event->build_pixel_url();
84
85 if ( ! $pixel ) {
86 return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 );
87 }
88
89 return self::record_pixel( $pixel );
90 }
91
92 /**
93 * Synchronously request the pixel.
94 *
95 * @param string $pixel The wp.com tracking pixel.
96 * @return array|bool|WP_Error True if successful. wp_remote_get response or WP_Error if not.
97 */
98 public static function record_pixel( $pixel ) {
99 // Add the Request Timestamp and URL terminator just before the HTTP request.
100 $pixel .= '&_rt=' . self::build_timestamp() . '&_=_';
101
102 $response = wp_remote_get(
103 $pixel,
104 array(
105 'blocking' => true, // The default, but being explicit here :).
106 'timeout' => 1,
107 'redirection' => 2,
108 'httpversion' => '1.1',
109 'user-agent' => self::get_user_agent(),
110 )
111 );
112
113 if ( is_wp_error( $response ) ) {
114 return $response;
115 }
116
117 $code = $response['response']['code'] ?? 0;
118
119 if ( 200 !== $code ) {
120 return new WP_Error( 'request_failed', 'Tracks pixel request failed', $code );
121 }
122
123 return true;
124 }
125
126 /**
127 * Get the user agent.
128 *
129 * @return string The user agent.
130 */
131 public static function get_user_agent() {
132 return self::USER_AGENT_SLUG . '-v' . self::VERSION;
133 }
134
135 /**
136 * Build an event and return its tracking URL
137 *
138 * @deprecated Call the `build_pixel_url` method on a Jetpack_Tracks_Event object instead.
139 * @param array $event Event keys and values.
140 * @return string URL of a tracking pixel.
141 */
142 public static function build_pixel_url( $event ) {
143 $_event = new Jetpack_Tracks_Event( $event );
144 return $_event->build_pixel_url();
145 }
146
147 /**
148 * Validate input for a tracks event.
149 *
150 * @deprecated Instantiate a Jetpack_Tracks_Event object instead
151 * @param array $event Event keys and values.
152 * @return mixed Validated keys and values or WP_Error on failure
153 */
154 private static function validate_and_sanitize( $event ) {
155 $_event = new Jetpack_Tracks_Event( $event );
156 if ( is_wp_error( $_event ) ) {
157 return $_event;
158 }
159 return get_object_vars( $_event );
160 }
161
162 /**
163 * Builds a timestamp.
164 *
165 * Milliseconds since 1970-01-01.
166 *
167 * @return string
168 */
169 public static function build_timestamp() {
170 $ts = round( microtime( true ) * 1000 );
171 return number_format( $ts, 0, '', '' );
172 }
173
174 /**
175 * Grabs the user's anon id from cookies, or generates and sets a new one
176 *
177 * @return string An anon id for the user
178 */
179 public static function get_anon_id() {
180 static $anon_id = null;
181
182 if ( ! isset( $anon_id ) ) {
183
184 // Did the browser send us a cookie?
185 if ( isset( $_COOKIE['tk_ai'] ) && preg_match( '#^[a-z]+:[A-Za-z0-9+/=]{24}$#', $_COOKIE['tk_ai'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is validating.
186 $anon_id = $_COOKIE['tk_ai']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is validating.
187 } else {
188
189 $binary = '';
190
191 // Generate a new anonId and try to save it in the browser's cookies.
192 // Note that base64-encoding an 18 character string generates a 24-character anon id.
193 for ( $i = 0; $i < 18; ++$i ) {
194 $binary .= chr( wp_rand( 0, 255 ) );
195 }
196
197 $anon_id = 'jetpack:' . base64_encode( $binary ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
198
199 if ( ! headers_sent()
200 && ! ( defined( 'REST_REQUEST' ) && REST_REQUEST )
201 && ! ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
202 ) {
203 setcookie( 'tk_ai', $anon_id, 0, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), false ); // phpcs:ignore Jetpack.Functions.SetCookie -- This is a random value and should be fine.
204 }
205 }
206 }
207
208 return $anon_id;
209 }
210
211 /**
212 * Gets the WordPress.com user's Tracks identity, if connected.
213 *
214 * @return array|bool
215 */
216 public static function get_connected_user_tracks_identity() {
217 $user_data = ( new Manager() )->get_connected_user_data();
218 if ( ! $user_data ) {
219 return false;
220 }
221
222 return array(
223 'blogid' => Jetpack_Options::get_option( 'id', 0 ),
224 'email' => $user_data['email'],
225 'userid' => $user_data['ID'],
226 'username' => $user_data['login'],
227 'user_locale' => $user_data['user_locale'],
228 );
229 }
230 }
231