Completed
Push — add/handling-connection-errors ( 287a33...b95e3b )
by
unknown
27:58 queued 20:46
created

Error_Handler::report_error()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * The Jetpack Connection error class file.
4
 *
5
 * @package automattic/jetpack-connection
6
 */
7
8
namespace Automattic\Jetpack\Connection;
9
10
/**
11
 * The Jetpack Connection Errors that handles errors
12
 */
13
class Error_Handler {
14
15
	/**
16
	 * The name of the option that stores the errors
17
	 *
18
	 * @var string
19
	 */
20
	const STORED_ERRORS_OPTION = 'jetpack_connection_xmlrpc_errors';
21
22
	/**
23
	 * The prefix of the transient that controls the gate for each error code
24
	 *
25
	 * @var string
26
	 */
27
	const ERROR_REPORTING_GATE = 'jetpack_connection_error_reporting_gate_';
28
29
	/**
30
	 * Keep track of a connection error that was encoutered
31
	 *
32
	 * @param \WP_Error $error the error object.
33
	 * @param boolean   $force Force the report, even if should_report_error is false.
34
	 * @return void
35
	 */
36
	public function report_error( \WP_Error $error, $force = false ) {
37
		if ( $this->should_report_error( $error ) || $force ) {
38
			$this->store_error( $error );
39
		}
40
	}
41
42
	/**
43
	 * Checks the status of the gate
44
	 *
45
	 * This protects the site (and WPCOM) against over loads.
46
	 *
47
	 * @param \WP_Error $error the error object.
48
	 * @return boolean $should_report True if gate is open and the error should be reported.
49
	 */
50
	public function should_report_error( \WP_Error $error ) {
51
52
		if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) {
53
			return true;
54
		}
55
56
		$transient = self::ERROR_REPORTING_GATE . $error->get_error_code();
0 ignored issues
show
Bug introduced by
The method get_error_code() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
57
58
		if ( get_transient( $transient ) ) {
59
			return false;
60
		}
61
62
		set_transient( $transient, true, HOUR_IN_SECONDS );
63
		return true;
64
	}
65
66
	/**
67
	 * Stores the error in the database so we know there is an issue and can inform the user
68
	 *
69
	 * @param \WP_Error $error the error object.
70
	 * @return boolean False if stored errors were not updated and true if stored errors were updated.
71
	 */
72
	public function store_error( \WP_Error $error ) {
73
		$stored_errors = $this->get_stored_errors();
74
75
		$data       = $error->get_error_data();
0 ignored issues
show
Bug introduced by
The method get_error_data() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
76
		$error_code = $error->get_error_code();
0 ignored issues
show
Bug introduced by
The method get_error_code() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
77
78
		if ( ! isset( $data['signature_details'] ) || ! is_array( $data['signature_details'] ) ) {
79
			return false;
80
		}
81
82
		$data = $data['signature_details'];
83
84
		if ( ! isset( $data['token'] ) || empty( $data['token'] ) ) {
85
			return false;
86
		}
87
88
		$user_id = $this->get_user_id_from_token( $data['token'] );
89
90
		if ( ! isset( $stored_errors[ $error_code ] ) || ! is_array( $stored_errors[ $error_code ] ) ) {
91
			$stored_errors[ $error_code ] = array();
92
		}
93
94
		$stored_errors[ $error_code ][ $user_id ] = array(
95
			'error_code'    => $error_code,
96
			'error_message' => $error->get_error_message(),
0 ignored issues
show
Bug introduced by
The method get_error_message() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
97
			'error_data'    => $data,
98
			'timestamp'     => time(),
99
			'nonce'         => wp_generate_password( 10, false ),
100
		);
101
102
		// Let's store a maximum of 5 different user ids for each error code.
103
		if ( count( $stored_errors[ $error_code ] ) > 5 ) {
104
			array_shift( $stored_errors[ $error_code ] );
105
		}
106
107
		return update_option( self::STORED_ERRORS_OPTION, $stored_errors );
108
	}
109
110
	/**
111
	 * Extracts the user ID from a token
112
	 *
113
	 * @param string $token the token used to make the xml-rpc request.
114
	 * @return string $the user id or `invalid` if user id not present.
115
	 */
116
	public function get_user_id_from_token( $token ) {
117
		$parsed_token = explode( ':', wp_unslash( $token ) );
118
119
		if ( isset( $parsed_token[2] ) && ! empty( $parsed_token[2] ) && ctype_digit( $parsed_token[2] ) ) {
120
			$user_id = $parsed_token[2];
121
		} else {
122
			$user_id = 'invalid';
123
		}
124
125
		return $user_id;
126
127
	}
128
129
	/**
130
	 * Gets the reported errors stored in the database
131
	 *
132
	 * @return array $errors
133
	 */
134
	public function get_stored_errors() {
135
		$stored_errors = get_option( self::STORED_ERRORS_OPTION );
136
		if ( ! is_array( $stored_errors ) ) {
137
			$stored_errors = array();
138
		}
139
		return $stored_errors;
140
	}
141
142
	/**
143
	 * Delete the reported errors stored in the database
144
	 *
145
	 * @return boolean True, if option is successfully deleted. False on failure.
146
	 */
147
	public function delete_stored_errors() {
148
		return delete_option( self::STORED_ERRORS_OPTION );
149
	}
150
151
}
152