PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 6.9
Jetpack – WP Security, Backup, Speed, & Growth v6.9
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / sync / class.jetpack-sync-listener.php
class.jetpack-sync-listener.php
313 lines 9.2 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::get_setting( 'disable' ) ) {
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 function bulk_enqueue_full_sync_actions( $action_name, $args_array ) {
121 $queue = $this->get_full_sync_queue();
122
123 // periodically check the size of the queue, and disable adding to it if
124 // it exceeds some limit AND the oldest item exceeds the age limit (i.e. sending has stopped)
125 if ( ! $this->can_add_to_queue( $queue ) ) {
126 return;
127 }
128
129 // if we add any items to the queue, we should try to ensure that our script
130 // can't be killed before they are sent
131 if ( function_exists( 'ignore_user_abort' ) ) {
132 ignore_user_abort( true );
133 }
134
135 $data_to_enqueue = array();
136 $user_id = get_current_user_id();
137 $currtime = microtime( true );
138 $is_importing = Jetpack_Sync_Settings::is_importing();
139
140 foreach( $args_array as $args ) {
141
142 /**
143 * Modify or reject the data within an action before it is enqueued locally.
144 *
145 * @since 4.2.0
146 *
147 * @module sync
148 *
149 * @param array The action parameters
150 */
151 $args = apply_filters( "jetpack_sync_before_enqueue_$action_name", $args );
152
153 // allow listeners to abort
154 if ( $args === false ) {
155 continue;
156 }
157
158 $data_to_enqueue[] = array(
159 $action_name,
160 array( $args ),
161 $user_id,
162 $currtime,
163 $is_importing,
164 );
165 }
166
167 $queue->add_all( $data_to_enqueue );
168 }
169
170 function enqueue_action( $current_filter, $args, $queue ) {
171 // don't enqueue an action during the outbound http request - this prevents recursion
172 if ( Jetpack_Sync_Settings::is_sending() ) {
173 return;
174 }
175
176 /**
177 * Add an action hook to execute when anything on the whitelist gets sent to the queue to sync.
178 *
179 * @module sync
180 *
181 * @since 5.9.0
182 */
183 do_action( 'jetpack_sync_action_before_enqueue' );
184
185 /**
186 * Modify or reject the data within an action before it is enqueued locally.
187 *
188 * @since 4.2.0
189 *
190 * @param array The action parameters
191 */
192 $args = apply_filters( "jetpack_sync_before_enqueue_$current_filter", $args );
193
194 // allow listeners to abort
195 if ( $args === false ) {
196 return;
197 }
198
199 // periodically check the size of the queue, and disable adding to it if
200 // it exceeds some limit AND the oldest item exceeds the age limit (i.e. sending has stopped)
201 if ( ! $this->can_add_to_queue( $queue ) ) {
202 return;
203 }
204
205 // if we add any items to the queue, we should try to ensure that our script
206 // can't be killed before they are sent
207 if ( function_exists( 'ignore_user_abort' ) ) {
208 ignore_user_abort( true );
209 }
210
211 if (
212 'sync' === $queue->id ||
213 in_array(
214 $current_filter,
215 array(
216 'jetpack_full_sync_start',
217 'jetpack_full_sync_end',
218 'jetpack_full_sync_cancel'
219 )
220 )
221 ) {
222 $queue->add( array(
223 $current_filter,
224 $args,
225 get_current_user_id(),
226 microtime( true ),
227 Jetpack_Sync_Settings::is_importing(),
228 $this->get_actor( $current_filter, $args ),
229 ) );
230 } else {
231 $queue->add( array(
232 $current_filter,
233 $args,
234 get_current_user_id(),
235 microtime( true ),
236 Jetpack_Sync_Settings::is_importing()
237 ) );
238 }
239
240 // since we've added some items, let's try to load the sender so we can send them as quickly as possible
241 if ( ! Jetpack_Sync_Actions::$sender ) {
242 add_filter( 'jetpack_sync_sender_should_load', '__return_true' );
243 if ( did_action( 'init' ) ) {
244 Jetpack_Sync_Actions::add_sender_shutdown();
245 }
246 }
247 }
248
249 function get_actor( $current_filter, $args ) {
250 if ( 'wp_login' === $current_filter ) {
251 $user = get_user_by( 'ID', $args[1]->data->ID );
252 } else {
253 $user = wp_get_current_user();
254 }
255
256 $translated_role = Jetpack::translate_user_to_role( $user );
257
258 $actor = array(
259 'wpcom_user_id' => null,
260 'external_user_id' => isset( $user->ID ) ? $user->ID : null,
261 'display_name' => isset( $user->display_name ) ? $user->display_name : null,
262 'user_email' => isset( $user->user_email ) ? $user->user_email : null,
263 'user_roles' => isset( $user->roles ) ? $user->roles : null,
264 'translated_role' => $translated_role ? $translated_role : null,
265 'is_cron' => defined( 'DOING_CRON' ) ? DOING_CRON : false,
266 'is_rest' => defined( 'REST_API_REQUEST' ) ? REST_API_REQUEST : false,
267 'is_xmlrpc' => defined( 'XMLRPC_REQUEST' ) ? XMLRPC_REQUEST : false,
268 'is_wp_rest' => defined( 'REST_REQUEST' ) ? REST_REQUEST : false,
269 'is_ajax' => defined( 'DOING_AJAX' ) ? DOING_AJAX : false,
270 'is_wp_admin' => is_admin(),
271 'is_cli' => defined( 'WP_CLI' ) ? WP_CLI : false,
272 'from_url' => $this->get_request_url(),
273 );
274
275 if ( $this->should_send_user_data_with_actor( $current_filter ) ) {
276 require_once( JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php' );
277 $actor['ip'] = jetpack_protect_get_ip();
278 $actor['user_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'unknown';
279 }
280
281 return $actor;
282 }
283
284 function should_send_user_data_with_actor( $current_filter ) {
285 $should_send = in_array( $current_filter, array( 'wp_login', 'wp_logout', 'jetpack_valid_failed_login_attempt' ) );
286 /**
287 * Allow or deny sending actor's user data ( IP and UA ) during a sync event
288 *
289 * @since 5.8.0
290 *
291 * @module sync
292 *
293 * @param bool True if we should send user data
294 * @param string The current filter that is performing the sync action
295 */
296 return apply_filters( 'jetpack_sync_actor_user_data', $should_send, $current_filter );
297 }
298
299 function set_defaults() {
300 $this->sync_queue = new Jetpack_Sync_Queue( 'sync' );
301 $this->full_sync_queue = new Jetpack_Sync_Queue( 'full_sync' );
302 $this->set_queue_size_limit( Jetpack_Sync_Settings::get_setting( 'max_queue_size' ) );
303 $this->set_queue_lag_limit( Jetpack_Sync_Settings::get_setting( 'max_queue_lag' ) );
304 }
305
306 function get_request_url() {
307 if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
308 return 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
309 }
310 return is_admin() ? get_admin_url( get_current_blog_id() ) : home_url();
311 }
312 }
313