PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.4.3
Jetpack – WP Security, Backup, Speed, & Growth v7.4.3
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
jetpack / sync / class.jetpack-sync-listener.php
class.jetpack-sync-listener.php
330 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once dirname( __FILE__ ) . '/class.jetpack-sync-settings.php';
4 require_once dirname( __FILE__ ) . '/class.jetpack-sync-queue.php';
5 require_once dirname( __FILE__ ) . '/class.jetpack-sync-modules.php';
6 require_once dirname( __FILE__ ) . '/class.jetpack-sync-actions.php';
7
8 /**
9 * This class monitors actions and logs them to the queue to be sent
10 */
11 class Jetpack_Sync_Listener {
12 const QUEUE_STATE_CHECK_TRANSIENT = 'jetpack_sync_last_checked_queue_state';
13 const QUEUE_STATE_CHECK_TIMEOUT = 300; // 5 minutes
14
15 private $sync_queue;
16 private $full_sync_queue;
17 private $sync_queue_size_limit;
18 private $sync_queue_lag_limit;
19
20 // singleton functions
21 private static $instance;
22
23 public static function get_instance() {
24 if ( null === self::$instance ) {
25 self::$instance = new self();
26 }
27
28 return self::$instance;
29 }
30
31 // this is necessary because you can't use "new" when you declare instance properties >:(
32 protected function __construct() {
33 $this->set_defaults();
34 $this->init();
35 }
36
37 private function init() {
38 $handler = array( $this, 'action_handler' );
39 $full_sync_handler = array( $this, 'full_sync_action_handler' );
40
41 foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
42 $module->init_listeners( $handler );
43 $module->init_full_sync_listeners( $full_sync_handler );
44 }
45
46 // Module Activation
47 add_action( 'jetpack_activate_module', $handler );
48 add_action( 'jetpack_deactivate_module', $handler );
49
50 // Jetpack Upgrade
51 add_action( 'updating_jetpack_version', $handler, 10, 2 );
52
53 // Send periodic checksum
54 add_action( 'jetpack_sync_checksum', $handler );
55 }
56
57 function get_sync_queue() {
58 return $this->sync_queue;
59 }
60
61 function get_full_sync_queue() {
62 return $this->full_sync_queue;
63 }
64
65 function set_queue_size_limit( $limit ) {
66 $this->sync_queue_size_limit = $limit;
67 }
68
69 function get_queue_size_limit() {
70 return $this->sync_queue_size_limit;
71 }
72
73 function set_queue_lag_limit( $age ) {
74 $this->sync_queue_lag_limit = $age;
75 }
76
77 function get_queue_lag_limit() {
78 return $this->sync_queue_lag_limit;
79 }
80
81 function force_recheck_queue_limit() {
82 delete_transient( self::QUEUE_STATE_CHECK_TRANSIENT . '_' . $this->sync_queue->id );
83 delete_transient( self::QUEUE_STATE_CHECK_TRANSIENT . '_' . $this->full_sync_queue->id );
84 }
85
86 // prevent adding items to the queue if it hasn't sent an item for 15 mins
87 // AND the queue is over 1000 items long (by default)
88 function can_add_to_queue( $queue ) {
89 if ( ! Jetpack_Sync_Settings::is_sync_enabled() ) {
90 return false;
91 }
92
93 $state_transient_name = self::QUEUE_STATE_CHECK_TRANSIENT . '_' . $queue->id;
94
95 $queue_state = get_transient( $state_transient_name );
96
97 if ( false === $queue_state ) {
98 $queue_state = array( $queue->size(), $queue->lag() );
99 set_transient( $state_transient_name, $queue_state, self::QUEUE_STATE_CHECK_TIMEOUT );
100 }
101
102 list( $queue_size, $queue_age ) = $queue_state;
103
104 return ( $queue_age < $this->sync_queue_lag_limit )
105 ||
106 ( ( $queue_size + 1 ) < $this->sync_queue_size_limit );
107 }
108
109 function full_sync_action_handler() {
110 $args = func_get_args();
111 $this->enqueue_action( current_filter(), $args, $this->full_sync_queue );
112 }
113
114 function action_handler() {
115 $args = func_get_args();
116 $this->enqueue_action( current_filter(), $args, $this->sync_queue );
117 }
118
119 // add many actions to the queue directly, without invoking them
120
121 /**
122 * Bulk add action to the queue.
123 *
124 * @param $action_name String the name the full sync action.
125 * @param $args_array Array of chunked arguments
126 */
127 function bulk_enqueue_full_sync_actions( $action_name, $args_array ) {
128 $queue = $this->get_full_sync_queue();
129
130 // periodically check the size of the queue, and disable adding to it if
131 // it exceeds some limit AND the oldest item exceeds the age limit (i.e. sending has stopped)
132 if ( ! $this->can_add_to_queue( $queue ) ) {
133 return;
134 }
135
136 // if we add any items to the queue, we should try to ensure that our script
137 // can't be killed before they are sent
138 if ( function_exists( 'ignore_user_abort' ) ) {
139 ignore_user_abort( true );
140 }
141
142 $data_to_enqueue = array();
143 $user_id = get_current_user_id();
144 $currtime = microtime( true );
145 $is_importing = Jetpack_Sync_Settings::is_importing();
146
147 foreach ( $args_array as $args ) {
148 $previous_end = isset( $args['previous_end'] ) ? $args['previous_end'] : null;
149 $args = isset( $args['ids'] ) ? $args['ids'] : $args;
150
151
152 /**
153 * Modify or reject the data within an action before it is enqueued locally.
154 *
155 * @since 4.2.0
156 *
157 * @module sync
158 *
159 * @param array The action parameters
160 */
161 $args = apply_filters( "jetpack_sync_before_enqueue_$action_name", $args );
162 $action_data = array( $args );
163 if ( ! is_null( $previous_end ) ) {
164 $action_data[] = $previous_end;
165 }
166 // allow listeners to abort
167 if ( $args === false ) {
168 continue;
169 }
170
171 $data_to_enqueue[] = array(
172 $action_name,
173 $action_data,
174 $user_id,
175 $currtime,
176 $is_importing,
177 );
178 }
179
180 $queue->add_all( $data_to_enqueue );
181 }
182
183 function enqueue_action( $current_filter, $args, $queue ) {
184 // don't enqueue an action during the outbound http request - this prevents recursion
185 if ( Jetpack_Sync_Settings::is_sending() ) {
186 return;
187 }
188
189 /**
190 * Add an action hook to execute when anything on the whitelist gets sent to the queue to sync.
191 *
192 * @module sync
193 *
194 * @since 5.9.0
195 */
196 do_action( 'jetpack_sync_action_before_enqueue' );
197
198 /**
199 * Modify or reject the data within an action before it is enqueued locally.
200 *
201 * @since 4.2.0
202 *
203 * @param array The action parameters
204 */
205 $args = apply_filters( "jetpack_sync_before_enqueue_$current_filter", $args );
206
207 // allow listeners to abort
208 if ( $args === false ) {
209 return;
210 }
211
212 // periodically check the size of the queue, and disable adding to it if
213 // it exceeds some limit AND the oldest item exceeds the age limit (i.e. sending has stopped)
214 if ( ! $this->can_add_to_queue( $queue ) ) {
215 return;
216 }
217
218 // if we add any items to the queue, we should try to ensure that our script
219 // can't be killed before they are sent
220 if ( function_exists( 'ignore_user_abort' ) ) {
221 ignore_user_abort( true );
222 }
223
224 if (
225 'sync' === $queue->id ||
226 in_array(
227 $current_filter,
228 array(
229 'jetpack_full_sync_start',
230 'jetpack_full_sync_end',
231 'jetpack_full_sync_cancel',
232 )
233 )
234 ) {
235 $queue->add(
236 array(
237 $current_filter,
238 $args,
239 get_current_user_id(),
240 microtime( true ),
241 Jetpack_Sync_Settings::is_importing(),
242 $this->get_actor( $current_filter, $args ),
243 )
244 );
245 } else {
246 $queue->add(
247 array(
248 $current_filter,
249 $args,
250 get_current_user_id(),
251 microtime( true ),
252 Jetpack_Sync_Settings::is_importing(),
253 )
254 );
255 }
256
257 // since we've added some items, let's try to load the sender so we can send them as quickly as possible
258 if ( ! Jetpack_Sync_Actions::$sender ) {
259 add_filter( 'jetpack_sync_sender_should_load', '__return_true' );
260 if ( did_action( 'init' ) ) {
261 Jetpack_Sync_Actions::add_sender_shutdown();
262 }
263 }
264 }
265
266 function get_actor( $current_filter, $args ) {
267 if ( 'wp_login' === $current_filter ) {
268 $user = get_user_by( 'ID', $args[1]->data->ID );
269 } else {
270 $user = wp_get_current_user();
271 }
272
273 $translated_role = Jetpack::translate_user_to_role( $user );
274
275 $actor = array(
276 'wpcom_user_id' => null,
277 'external_user_id' => isset( $user->ID ) ? $user->ID : null,
278 'display_name' => isset( $user->display_name ) ? $user->display_name : null,
279 'user_email' => isset( $user->user_email ) ? $user->user_email : null,
280 'user_roles' => isset( $user->roles ) ? $user->roles : null,
281 'translated_role' => $translated_role ? $translated_role : null,
282 'is_cron' => defined( 'DOING_CRON' ) ? DOING_CRON : false,
283 'is_rest' => defined( 'REST_API_REQUEST' ) ? REST_API_REQUEST : false,
284 'is_xmlrpc' => defined( 'XMLRPC_REQUEST' ) ? XMLRPC_REQUEST : false,
285 'is_wp_rest' => defined( 'REST_REQUEST' ) ? REST_REQUEST : false,
286 'is_ajax' => defined( 'DOING_AJAX' ) ? DOING_AJAX : false,
287 'is_wp_admin' => is_admin(),
288 'is_cli' => defined( 'WP_CLI' ) ? WP_CLI : false,
289 'from_url' => $this->get_request_url(),
290 );
291
292 if ( $this->should_send_user_data_with_actor( $current_filter ) ) {
293 require_once JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php';
294 $actor['ip'] = jetpack_protect_get_ip();
295 $actor['user_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'unknown';
296 }
297
298 return $actor;
299 }
300
301 function should_send_user_data_with_actor( $current_filter ) {
302 $should_send = in_array( $current_filter, array( 'jetpack_wp_login', 'wp_logout', 'jetpack_valid_failed_login_attempt' ) );
303 /**
304 * Allow or deny sending actor's user data ( IP and UA ) during a sync event
305 *
306 * @since 5.8.0
307 *
308 * @module sync
309 *
310 * @param bool True if we should send user data
311 * @param string The current filter that is performing the sync action
312 */
313 return apply_filters( 'jetpack_sync_actor_user_data', $should_send, $current_filter );
314 }
315
316 function set_defaults() {
317 $this->sync_queue = new Jetpack_Sync_Queue( 'sync' );
318 $this->full_sync_queue = new Jetpack_Sync_Queue( 'full_sync' );
319 $this->set_queue_size_limit( Jetpack_Sync_Settings::get_setting( 'max_queue_size' ) );
320 $this->set_queue_lag_limit( Jetpack_Sync_Settings::get_setting( 'max_queue_lag' ) );
321 }
322
323 function get_request_url() {
324 if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
325 return 'http' . ( isset( $_SERVER['HTTPS'] ) ? 's' : '' ) . '://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
326 }
327 return is_admin() ? get_admin_url( get_current_blog_id() ) : home_url();
328 }
329 }
330