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 / _inc / lib / debugger / class-jetpack-debug-data.php
class-jetpack-debug-data.php
396 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Jetpack Debug Data for the legacy Jetpack debugger page and the WP 5.2-era Site Health sections.
4 *
5 * @package jetpack
6 */
7
8 /**
9 * Class Jetpack_Debug_Data
10 *
11 * Collect and return debug data for Jetpack.
12 *
13 * @since 7.3.0
14 */
15 class Jetpack_Debug_Data {
16 /**
17 * Determine the active plan and normalize it for the debugger results.
18 *
19 * @since 7.3.0
20 *
21 * @return string The plan slug.
22 */
23 public static function what_jetpack_plan() {
24 $plan = Jetpack_Plan::get();
25 return ! empty( $plan['class'] ) ? $plan['class'] : 'undefined';
26 }
27
28 /**
29 * Convert seconds to human readable time.
30 *
31 * A dedication function instead of using Core functionality to allow for output in seconds.
32 *
33 * @since 7.3.0
34 *
35 * @param int $seconds Number of seconds to convert to human time.
36 *
37 * @return string Human readable time.
38 */
39 public static function seconds_to_time( $seconds ) {
40 $seconds = intval( $seconds );
41 $units = array(
42 'week' => WEEK_IN_SECONDS,
43 'day' => DAY_IN_SECONDS,
44 'hour' => HOUR_IN_SECONDS,
45 'minute' => MINUTE_IN_SECONDS,
46 'second' => 1,
47 );
48 // specifically handle zero.
49 if ( 0 === $seconds ) {
50 return '0 seconds';
51 }
52 $human_readable = '';
53 foreach ( $units as $name => $divisor ) {
54 $quot = intval( $seconds / $divisor );
55 if ( $quot ) {
56 $human_readable .= "$quot $name";
57 $human_readable .= ( abs( $quot ) > 1 ? 's' : '' ) . ', ';
58 $seconds -= $quot * $divisor;
59 }
60 }
61 return substr( $human_readable, 0, -2 );
62 }
63
64 /**
65 * Return debug data in the format expected by Core's Site Health Info tab.
66 *
67 * @since 7.3.0
68 *
69 * @param array $debug {
70 * The debug information already compiled by Core.
71 *
72 * @type string $label The title for this section of the debug output.
73 * @type string $description Optional. A description for your information section which may contain basic HTML
74 * markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
75 * @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
76 * this section.
77 * @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
78 * from the copy-paste text area.
79 * @type array $fields {
80 * An associative array containing the data to be displayed.
81 *
82 * @type string $label The label for this piece of information.
83 * @type string $value The output that is of interest for this field.
84 * @type boolean $private Optional. If set to `true` the field will not be included in the copy-paste text area
85 * on top of the page, allowing you to show, for example, API keys here.
86 * }
87 * }
88 *
89 * @return array $args Debug information in the same format as the initial argument.
90 */
91 public static function core_debug_data( $debug ) {
92 $jetpack = array(
93 'jetpack' => array(
94 'label' => __( 'Jetpack', 'jetpack' ),
95 'description' => sprintf(
96 /* translators: %1$s is URL to jetpack.com's contact support page. %2$s accessibility text */
97 __(
98 'Diagnostic information helpful to <a href="%1$s" target="_blank" rel="noopener noreferrer">your Jetpack Happiness team<span class="screen-reader-text">%2$s</span></a>',
99 'jetpack'
100 ),
101 esc_html( 'https://jetpack.com/contact-support/' ),
102 __( '(opens in a new tab)', 'jetpack' )
103 ),
104 'fields' => self::debug_data(),
105 ),
106 );
107 $debug = array_merge( $debug, $jetpack );
108 return $debug;
109 }
110
111 /**
112 * Compile and return array of debug information.
113 *
114 * @since 7.3.0
115 *
116 * @return array $args {
117 * Associated array of arrays with the following.
118 * @type string $label The label for this piece of information.
119 * @type string $value The output that is of interest for this field.
120 * @type boolean $private Optional. Set to true if data is sensitive (API keys, etc).
121 * }
122 */
123 public static function debug_data() {
124 $debug_info = array();
125
126 /* Add various important Jetpack options */
127 $debug_info['site_id'] = array(
128 'label' => 'Jetpack Site ID',
129 'value' => Jetpack_Options::get_option( 'id' ),
130 'private' => false,
131 );
132 $debug_info['ssl_cert'] = array(
133 'label' => 'Jetpack SSL Verfication Bypass',
134 'value' => ( Jetpack_Options::get_option( 'fallback_no_verify_ssl_certs' ) ) ? 'Yes' : 'No',
135 'private' => false,
136 );
137 $debug_info['time_diff'] = array(
138 'label' => "Offset between Jetpack server's time and this server's time.",
139 'value' => Jetpack_Options::get_option( 'time_diff' ),
140 'private' => false,
141 );
142 $debug_info['version_option'] = array(
143 'label' => 'Current Jetpack Version Option',
144 'value' => Jetpack_Options::get_option( 'version' ),
145 'private' => false,
146 );
147 $debug_info['old_version'] = array(
148 'label' => 'Previous Jetpack Version',
149 'value' => Jetpack_Options::get_option( 'old_version' ),
150 'private' => false,
151 );
152 $debug_info['public'] = array(
153 'label' => 'Jetpack Site Public',
154 'value' => ( Jetpack_Options::get_option( 'public' ) ) ? 'Public' : 'Private',
155 'private' => false,
156 );
157 $debug_info['master_user'] = array(
158 'label' => 'Jetpack Master User',
159 'value' => self::human_readable_master_user(),
160 'private' => false,
161 );
162
163 /**
164 * Token information is private, but awareness if there one is set is helpful.
165 *
166 * To balance out information vs privacy, we only display and include the "key",
167 * which is a segment of the token prior to a period within the token and is
168 * technically not private.
169 *
170 * If a token does not contain a period, then it is malformed and we report it as such.
171 */
172 $user_id = get_current_user_id();
173 $blog_token = Jetpack_Data::get_access_token();
174 $user_token = Jetpack_Data::get_access_token( $user_id );
175
176 $tokenset = '';
177 if ( $blog_token ) {
178 $tokenset = 'Blog ';
179 $blog_key = substr( $blog_token->secret, 0, strpos( $blog_token->secret, '.' ) );
180 // Intentionally not translated since this is helpful when sent to Happiness.
181 $blog_key = ( $blog_key ) ? $blog_key : 'Potentially Malformed Token.';
182 }
183 if ( $user_token ) {
184 $tokenset .= 'User';
185 $user_key = substr( $user_token->secret, 0, strpos( $user_token->secret, '.' ) );
186 // Intentionally not translated since this is helpful when sent to Happiness.
187 $user_key = ( $user_key ) ? $user_key : 'Potentially Malformed Token.';
188 }
189 if ( ! $tokenset ) {
190 $tokenset = 'None';
191 }
192
193 $debug_info['current_user'] = array(
194 'label' => 'Current User',
195 'value' => self::human_readable_user( $user_id ),
196 'private' => false,
197 );
198 $debug_info['tokens_set'] = array(
199 'label' => 'Tokens defined',
200 'value' => $tokenset,
201 'private' => false,
202 );
203 $debug_info['blog_token'] = array(
204 'label' => 'Blog Public Key',
205 'value' => ( $blog_token ) ? $blog_key : 'Not set.',
206 'private' => false,
207 );
208 $debug_info['user_token'] = array(
209 'label' => 'User Public Key',
210 'value' => ( $user_token ) ? $user_key : 'Not set.',
211 'private' => false,
212 );
213
214 /** Jetpack Environmental Information */
215 $debug_info['version'] = array(
216 'label' => 'Jetpack Version',
217 'value' => JETPACK__VERSION,
218 'private' => false,
219 );
220 $debug_info['jp_plugin_dir'] = array(
221 'label' => 'Jetpack Directory',
222 'value' => JETPACK__PLUGIN_DIR,
223 'private' => false,
224 );
225 $debug_info['plan'] = array(
226 'label' => 'Plan Type',
227 'value' => self::what_jetpack_plan(),
228 'private' => false,
229 );
230
231 foreach ( array(
232 'HTTP_HOST',
233 'SERVER_PORT',
234 'HTTPS',
235 'GD_PHP_HANDLER',
236 'HTTP_AKAMAI_ORIGIN_HOP',
237 'HTTP_CF_CONNECTING_IP',
238 'HTTP_CLIENT_IP',
239 'HTTP_FASTLY_CLIENT_IP',
240 'HTTP_FORWARDED',
241 'HTTP_FORWARDED_FOR',
242 'HTTP_INCAP_CLIENT_IP',
243 'HTTP_TRUE_CLIENT_IP',
244 'HTTP_X_CLIENTIP',
245 'HTTP_X_CLUSTER_CLIENT_IP',
246 'HTTP_X_FORWARDED',
247 'HTTP_X_FORWARDED_FOR',
248 'HTTP_X_IP_TRAIL',
249 'HTTP_X_REAL_IP',
250 'HTTP_X_VARNISH',
251 'REMOTE_ADDR',
252 ) as $header ) {
253 if ( isset( $_SERVER[ $header ] ) ) {
254 $debug_info[ $header ] = array(
255 'label' => 'Server Variable ' . $header,
256 'value' => ( $_SERVER[ $header ] ) ? $_SERVER[ $header ] : 'false',
257 'private' => false,
258 );
259 }
260 }
261
262 $debug_info['protect_header'] = array(
263 'label' => 'Trusted IP',
264 'value' => wp_json_encode( get_site_option( 'trusted_ip_header' ) ),
265 'private' => false,
266 );
267
268 /** Sync Debug Information */
269 /** Load Sync modules */
270 require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-modules.php';
271 /** Load Sync sender */
272 require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-sender.php';
273 /** Load Sync functions */
274 require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-functions.php';
275
276 $sync_module = Jetpack_Sync_Modules::get_module( 'full-sync' );
277 if ( $sync_module ) {
278 $sync_statuses = $sync_module->get_status();
279 $human_readable_sync_status = array();
280 foreach ( $sync_statuses as $sync_status => $sync_status_value ) {
281 $human_readable_sync_status[ $sync_status ] =
282 in_array( $sync_status, array( 'started', 'queue_finished', 'send_started', 'finished' ), true )
283 ? date( 'r', $sync_status_value ) : $sync_status_value;
284 }
285 $debug_info['full_sync'] = array(
286 'label' => 'Full Sync Status',
287 'value' => wp_json_encode( $human_readable_sync_status ),
288 'private' => false,
289 );
290 }
291
292 $queue = Jetpack_Sync_Sender::get_instance()->get_sync_queue();
293
294 $debug_info['sync_size'] = array(
295 'label' => 'Sync Queue Size',
296 'value' => $queue->size(),
297 'private' => false,
298 );
299 $debug_info['sync_lag'] = array(
300 'label' => 'Sync Queue Lag',
301 'value' => self::seconds_to_time( $queue->lag() ),
302 'private' => false,
303 );
304
305 $full_sync_queue = Jetpack_Sync_Sender::get_instance()->get_full_sync_queue();
306
307 $debug_info['full_sync_size'] = array(
308 'label' => 'Full Sync Queue Size',
309 'value' => $full_sync_queue->size(),
310 'private' => false,
311 );
312 $debug_info['full_sync_lag'] = array(
313 'label' => 'Full Sync Queue Lag',
314 'value' => self::seconds_to_time( $full_sync_queue->lag() ),
315 'private' => false,
316 );
317
318 /**
319 * IDC Information
320 *
321 * Must follow sync debug since it depends on sync functionality.
322 */
323 $idc_urls = array(
324 'home' => Jetpack_Sync_Functions::home_url(),
325 'siteurl' => Jetpack_Sync_Functions::site_url(),
326 'WP_HOME' => Jetpack_Constants::is_defined( 'WP_HOME' ) ? Jetpack_Constants::get_constant( 'WP_HOME' ) : '',
327 'WP_SITEURL' => Jetpack_Constants::is_defined( 'WP_SITEURL' ) ? Jetpack_Constants::get_constant( 'WP_SITEURL' ) : '',
328 );
329
330 $debug_info['idc_urls'] = array(
331 'label' => 'IDC URLs',
332 'value' => wp_json_encode( $idc_urls ),
333 'private' => false,
334 );
335 $debug_info['idc_error_option'] = array(
336 'label' => 'IDC Error Option',
337 'value' => wp_json_encode( Jetpack_Options::get_option( 'sync_error_idc' ) ),
338 'private' => false,
339 );
340 $debug_info['idc_optin'] = array(
341 'label' => 'IDC Opt-in',
342 'value' => Jetpack::sync_idc_optin(),
343 'private' => false,
344 );
345
346 // @todo -- Add testing results?
347 $cxn_tests = new Jetpack_Cxn_Tests();
348 $debug_info['cxn_tests'] = array(
349 'label' => 'Connection Tests',
350 'value' => '',
351 'private' => false,
352 );
353 if ( $cxn_tests->pass() ) {
354 $debug_info['cxn_tests']['value'] = 'All Pass.';
355 } else {
356 $debug_info['cxn_tests']['value'] = wp_json_encode( $cxn_tests->list_fails() );
357 }
358
359 return $debug_info;
360 }
361
362 /**
363 * Returns a human readable string for which user is the master user.
364 *
365 * @return string
366 */
367 private static function human_readable_master_user() {
368 $master_user = Jetpack_Options::get_option( 'master_user' );
369
370 if ( ! $master_user ) {
371 return __( 'No master user set.', 'jetpack' );
372 }
373
374 $user = new WP_User( $master_user );
375
376 if ( ! $user ) {
377 return __( 'Master user no longer exists. Please disconnect and reconnect Jetpack.', 'jetpack' );
378 }
379
380 return self::human_readable_user( $user );
381 }
382
383 /**
384 * Return human readable string for a given user object.
385 *
386 * @param WP_User|int $user Object or ID.
387 *
388 * @return string
389 */
390 private static function human_readable_user( $user ) {
391 $user = new WP_User( $user );
392
393 return sprintf( '#%1$d %2$s (%3$s)', $user->ID, $user->user_login, $user->user_email ); // Format: "#1 username (user@example.com)".
394 }
395 }
396