Completed
Push — update/debug-data-user-and-tok... ( 658a74 )
by
unknown
20:15 queued 12:29
created

Jetpack_Debug_Data::seconds_to_time()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 1
dl 0
loc 24
rs 9.2248
c 0
b 0
f 0
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
		/* Token information is private, but awareness if there one is set is helpful. */
164
		$user_id     = get_current_user_id();
165
		$user_tokens = Jetpack_Options::get_option( 'user_tokens' );
166
		$blog_token  = Jetpack_Options::get_option( 'blog_token' );
167
		$user_token  = null;
168
		if ( is_array( $user_tokens ) && array_key_exists( $user_id, $user_tokens ) ) {
169
			$user_token = $user_tokens[ $user_id ];
170
		}
171
		unset( $user_tokens );
172
173
		$tokenset = '';
174
		if ( $blog_token ) {
175
			$tokenset = 'Blog ';
176
		}
177
		if ( $user_token ) {
178
			$tokenset .= 'User';
179
		}
180
		if ( ! $tokenset ) {
181
			$tokenset = 'None';
182
		}
183
184
		$debug_info['current_user'] = array(
185
			'label'   => 'Current User',
186
			'value'   => $user_id,
187
			'private' => false,
188
		);
189
		$debug_info['tokens_set']   = array(
190
			'label' => 'Tokens defined',
191
			'value' => $tokenset,
192
			'private => false,',
193
		);
194
195
		/** Jetpack Environmental Information */
196
		$debug_info['version']       = array(
197
			'label'   => 'Jetpack Version',
198
			'value'   => JETPACK__VERSION,
199
			'private' => false,
200
		);
201
		$debug_info['jp_plugin_dir'] = array(
202
			'label'   => 'Jetpack Directory',
203
			'value'   => JETPACK__PLUGIN_DIR,
204
			'private' => false,
205
		);
206
		$debug_info['plan']          = array(
207
			'label'   => 'Plan Type',
208
			'value'   => self::what_jetpack_plan(),
209
			'private' => false,
210
		);
211
212
		foreach ( array(
213
			'HTTP_HOST',
214
			'SERVER_PORT',
215
			'HTTPS',
216
			'GD_PHP_HANDLER',
217
			'HTTP_AKAMAI_ORIGIN_HOP',
218
			'HTTP_CF_CONNECTING_IP',
219
			'HTTP_CLIENT_IP',
220
			'HTTP_FASTLY_CLIENT_IP',
221
			'HTTP_FORWARDED',
222
			'HTTP_FORWARDED_FOR',
223
			'HTTP_INCAP_CLIENT_IP',
224
			'HTTP_TRUE_CLIENT_IP',
225
			'HTTP_X_CLIENTIP',
226
			'HTTP_X_CLUSTER_CLIENT_IP',
227
			'HTTP_X_FORWARDED',
228
			'HTTP_X_FORWARDED_FOR',
229
			'HTTP_X_IP_TRAIL',
230
			'HTTP_X_REAL_IP',
231
			'HTTP_X_VARNISH',
232
			'REMOTE_ADDR',
233
		) as $header ) {
234
			if ( isset( $_SERVER[ $header ] ) ) {
235
				$debug_info[ $header ] = array(
236
					'label'   => 'Server Variable ' . $header,
237
					'value'   => ( $_SERVER[ $header ] ) ? $_SERVER[ $header ] : 'false',
238
					'private' => false,
239
				);
240
			}
241
		}
242
243
		$debug_info['protect_header'] = array(
244
			'label'   => 'Trusted IP',
245
			'value'   => wp_json_encode( get_site_option( 'trusted_ip_header' ) ),
246
			'private' => false,
247
		);
248
249
		/** Sync Debug Information */
250
		/** Load Sync modules */
251
		require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-modules.php';
252
		/** Load Sync sender */
253
		require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-sender.php';
254
		/** Load Sync functions */
255
		require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-functions.php';
256
257
		$sync_module = Jetpack_Sync_Modules::get_module( 'full-sync' );
258
		if ( $sync_module ) {
259
			$sync_statuses              = $sync_module->get_status();
260
			$human_readable_sync_status = array();
261
			foreach ( $sync_statuses as $sync_status => $sync_status_value ) {
262
				$human_readable_sync_status[ $sync_status ] =
263
					in_array( $sync_status, array( 'started', 'queue_finished', 'send_started', 'finished' ), true )
264
						? date( 'r', $sync_status_value ) : $sync_status_value;
265
			}
266
			$debug_info['full_sync'] = array(
267
				'label'   => 'Full Sync Status',
268
				'value'   => wp_json_encode( $human_readable_sync_status ),
269
				'private' => false,
270
			);
271
		}
272
273
		$queue = Jetpack_Sync_Sender::get_instance()->get_sync_queue();
274
275
		$debug_info['sync_size'] = array(
276
			'label'   => 'Sync Queue Size',
277
			'value'   => $queue->size(),
278
			'private' => false,
279
		);
280
		$debug_info['sync_lag']  = array(
281
			'label'   => 'Sync Queue Lag',
282
			'value'   => self::seconds_to_time( $queue->lag() ),
283
			'private' => false,
284
		);
285
286
		$full_sync_queue = Jetpack_Sync_Sender::get_instance()->get_full_sync_queue();
287
288
		$debug_info['full_sync_size'] = array(
289
			'label'   => 'Full Sync Queue Size',
290
			'value'   => $full_sync_queue->size(),
291
			'private' => false,
292
		);
293
		$debug_info['full_sync_lag']  = array(
294
			'label'   => 'Full Sync Queue Lag',
295
			'value'   => self::seconds_to_time( $full_sync_queue->lag() ),
296
			'private' => false,
297
		);
298
299
		/**
300
		 * IDC Information
301
		 *
302
		 * Must follow sync debug since it depends on sync functionality.
303
		 */
304
		$idc_urls = array(
305
			'home'       => Jetpack_Sync_Functions::home_url(),
306
			'siteurl'    => Jetpack_Sync_Functions::site_url(),
307
			'WP_HOME'    => Jetpack_Constants::is_defined( 'WP_HOME' ) ? Jetpack_Constants::get_constant( 'WP_HOME' ) : '',
308
			'WP_SITEURL' => Jetpack_Constants::is_defined( 'WP_SITEURL' ) ? Jetpack_Constants::get_constant( 'WP_SITEURL' ) : '',
309
		);
310
311
		$debug_info['idc_urls']         = array(
312
			'label'   => 'IDC URLs',
313
			'value'   => wp_json_encode( $idc_urls ),
314
			'private' => false,
315
		);
316
		$debug_info['idc_error_option'] = array(
317
			'label'   => 'IDC Error Option',
318
			'value'   => wp_json_encode( Jetpack_Options::get_option( 'sync_error_idc' ) ),
319
			'private' => false,
320
		);
321
		$debug_info['idc_optin']        = array(
322
			'label'   => 'IDC Opt-in',
323
			'value'   => Jetpack::sync_idc_optin(),
324
			'private' => false,
325
		);
326
327
		// @todo -- Add testing results?
328
		$cxn_tests               = new Jetpack_Cxn_Tests();
329
		$debug_info['cxn_tests'] = array(
330
			'label'   => 'Connection Tests',
331
			'value'   => '',
332
			'private' => false,
333
		);
334
		if ( $cxn_tests->pass() ) {
335
			$debug_info['cxn_tests']['value'] = 'All Pass.';
336
		} else {
337
			$debug_info['cxn_tests']['value'] = wp_json_encode( $cxn_tests->list_fails() );
338
		}
339
340
		return $debug_info;
341
	}
342
343
	/**
344
	 * Returns a human readable string for which user is the master user.
345
	 *
346
	 * @return string
347
	 */
348
	private function human_readable_master_user() {
349
		$master_user = Jetpack_Options::get_option( 'master_user' );
350
351
		if ( ! $master_user ) {
352
			return 'No master user set.';
353
		}
354
355
		$user = new WP_User( $master_user );
356
357
		if ( ! $user ) {
358
			return 'Master user no longer exists. Please disconnect and reconnect Jetpack.';
359
		}
360
361
		return sprintf( '#%1$d %2$s (%3$s)', $user->ID, $user->user_login, $user->user_email ); // Format: "#1 username ([email protected])".
362
	}
363
}
364