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