PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 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 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-connection/src/class-heartbeat.php +174 -0 13.5.2 → 16.3 View file →
@@ -8,8 +8,9 @@
8 8 namespace Automattic\Jetpack;
9 9
10 10 use Automattic\Jetpack\Connection\Rest_Authentication;
11 11 use Automattic\Jetpack\Connection\REST_Connector;
12 +use Automattic\Jetpack\Connection\Utils;
12 13 use Jetpack_Options;
13 14 use WP_CLI;
14 15 use WP_Error;
15 16 use WP_REST_Request;
@@ -170,8 +171,181 @@
170 171 $return[ "$prefix$stat" ] = $value;
171 172 }
172 173
173 174 return $return;
175 + }
176 +
177 + /**
178 + * Generates the site environment stats that are reported in the heartbeat.
179 + *
180 + * These describe the host environment (WordPress/PHP versions, site configuration, etc.)
181 + * rather than the Jetpack plugin itself, so they live in the Connection package and are
182 + * reported for every connected site, including standalone-connection installs.
183 + *
184 + * @since 8.7.9
185 + *
186 + * @return array The environment stats array, keyed by unprefixed stat name.
187 + */
188 + public static function get_environment_stats() {
189 + $stats = array();
190 +
191 + $stats['wp-version'] = get_bloginfo( 'version' );
192 + $stats['php-version'] = PHP_VERSION;
193 + $stats['wp-branch'] = (float) get_bloginfo( 'version' );
194 + $stats['php-branch'] = (float) PHP_VERSION;
195 + $stats['public'] = Jetpack_Options::get_option( 'public' );
196 + $stats['ssl'] = self::permit_ssl();
197 + $stats['is-https'] = is_ssl() ? 'https' : 'http';
198 + $stats['language'] = get_bloginfo( 'language' );
199 + $stats['charset'] = get_bloginfo( 'charset' );
200 + $stats['is-multisite'] = is_multisite() ? 'multisite' : 'singlesite';
201 + $stats['plugins'] = implode( ',', self::get_active_plugins() );
202 +
203 + if ( function_exists( 'get_mu_plugins' ) ) {
204 + $stats['mu-plugins'] = implode( ',', array_keys( get_mu_plugins() ) );
205 + }
206 +
207 + if ( function_exists( 'get_space_used' ) ) { // Only available in multisite.
208 + $space_used = get_space_used();
209 + } else {
210 + // This is the same as `get_space_used`, except it does not apply the short-circuit filter.
211 + $upload_dir = wp_upload_dir();
212 + $space_used = get_dirsize( $upload_dir['basedir'] ) / MB_IN_BYTES;
213 + }
214 +
215 + $stats['space-used'] = $space_used;
216 +
217 + // is-multi-network can have three values, `single-site`, `single-network`, and `multi-network`.
218 + $stats['is-multi-network'] = 'single-site';
219 + if ( is_multisite() ) {
220 + $stats['is-multi-network'] = ( new Status() )->is_multi_network() ? 'multi-network' : 'single-network';
221 + }
222 +
223 + if ( ! empty( $_SERVER['SERVER_ADDR'] ) || ! empty( $_SERVER['LOCAL_ADDR'] ) ) {
224 + $ip = ! empty( $_SERVER['SERVER_ADDR'] ) ? wp_unslash( $_SERVER['SERVER_ADDR'] ) : wp_unslash( $_SERVER['LOCAL_ADDR'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized just below.
225 + $ip_arr = array_map( 'intval', explode( '.', $ip ) );
226 + if ( 4 === count( $ip_arr ) ) {
227 + $stats['ip-2-octets'] = implode( '.', array_slice( $ip_arr, 0, 2 ) );
228 + }
229 + }
230 +
231 + return $stats;
232 + }
233 +
234 + /**
235 + * Checks whether the site can connect to WordPress.com over SSL.
236 + *
237 + * This is the canonical SSL connectivity check. It caches both the boolean result (in the
238 + * `jetpack_https_test` transient) and a structured failure reason (via
239 + * {@see self::get_ssl_test_error()}) so a single check serves both the `ssl` heartbeat stat
240 + * and consumers such as the Jetpack plugin's admin notice, which renders a localized message
241 + * from the reason code. This avoids duplicate network checks and keeps translated strings out
242 + * of the package.
243 + *
244 + * @since 8.7.9
245 + *
246 + * @param bool $force_recheck Force the SSL recheck instead of using the cached result.
247 + * @return bool Whether the site can connect to WordPress.com over SSL.
248 + */
249 + public static function permit_ssl( $force_recheck = false ) {
250 + $ssl = false;
251 + if ( ! $force_recheck ) {
252 + $ssl = get_transient( 'jetpack_https_test' );
253 + }
254 +
255 + if ( $force_recheck || false === $ssl ) {
256 + $error = array(
257 + 'code' => '',
258 + 'detail' => '',
259 + );
260 +
261 + $api_base = Constants::get_constant( 'JETPACK__API_BASE' );
262 + if ( ! $api_base ) {
263 + $api_base = Utils::DEFAULT_JETPACK__API_BASE;
264 + }
265 +
266 + if ( ! str_starts_with( $api_base, 'https' ) ) {
267 + $ssl = 0;
268 + } else {
269 + $ssl = 1;
270 +
271 + if ( ! wp_http_supports( array( 'ssl' => true ) ) ) {
272 + $ssl = 0;
273 + $error['code'] = 'no_ssl_support';
274 + } else {
275 + $response = wp_remote_get( $api_base . 'test/1/' );
276 + if ( is_wp_error( $response ) ) {
277 + $ssl = 0;
278 + $error['code'] = 'no_ssl_support';
279 + } elseif ( 'OK' !== wp_remote_retrieve_body( $response ) ) {
280 + $ssl = 0;
281 + $error['code'] = 'bad_response';
282 + $error['detail'] = wp_remote_retrieve_body( $response );
283 + }
284 + }
285 + }
286 + set_transient( 'jetpack_https_test', $ssl, DAY_IN_SECONDS );
287 + set_transient( 'jetpack_https_test_error', $error, DAY_IN_SECONDS );
288 + }
289 +
290 + return (bool) $ssl;
291 + }
292 +
293 + /**
294 + * Returns the structured reason for the last SSL connectivity failure.
295 + *
296 + * Consumers can map the returned reason code to a localized message. The `detail` value
297 + * carries any additional context (e.g. the unexpected response body for `bad_response`).
298 + *
299 + * @since 8.7.9
300 + *
301 + * @return array {
302 + * The last SSL test error.
303 + *
304 + * @type string $code Reason code: '' (no error), 'no_ssl_support', or 'bad_response'.
305 + * @type string $detail Additional context for the failure, if any.
306 + * }
307 + */
308 + public static function get_ssl_test_error() {
309 + $error = get_transient( 'jetpack_https_test_error' );
310 +
311 + if ( ! is_array( $error ) ) {
312 + $error = array();
313 + }
314 +
315 + return array(
316 + 'code' => isset( $error['code'] ) ? (string) $error['code'] : '',
317 + 'detail' => isset( $error['detail'] ) ? (string) $error['detail'] : '',
318 + );
319 + }
320 +
321 + /**
322 + * Gets all plugins currently active, regardless of whether they're traditionally
323 + * activated or network activated.
324 + *
325 + * Ported from the Jetpack plugin so the `plugins` heartbeat stat can be generated from
326 + * the Connection package. This is the canonical implementation; the Jetpack plugin's
327 + * `Jetpack::get_active_plugins()` delegates to it.
328 + *
329 + * @since 8.7.9
330 + *
331 + * @return array
332 + */
333 + public static function get_active_plugins() {
334 + $active_plugins = (array) get_option( 'active_plugins', array() );
335 +
336 + if ( is_multisite() ) {
337 + // Due to legacy code, active_sitewide_plugins stores them in the keys,
338 + // whereas active_plugins stores them in the values.
339 + $network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
340 + if ( $network_plugins ) {
341 + $active_plugins = array_merge( $active_plugins, $network_plugins );
342 + }
343 + }
344 +
345 + sort( $active_plugins );
346 +
347 + return array_unique( $active_plugins );
174 348 }
175 349
176 350 /**
177 351 * Registers jetpack.getHeartbeatData xmlrpc method