Completed
Push — add/error-reporting ( 023862 )
by Yaroslav
59:55 queued 52:40
created

error-monitoring.php ➔ jp_error_shutdown()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 8
nop 0
dl 0
loc 20
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * File doc comment
4
 *
5
 * @package whatever
6
 */
7
8
// phpcs:disable
9
// TODO: remove above line before merging
10
11
/**
12
 * In load-jetpack.php
13
require_once JETPACK__PLUGIN_DIR . 'tools/error-monitoring.php';
14
15
set_error_handler( 'jp_error_handler' );
16
register_shutdown_function( 'jp_error_shutdown' );
17
18
$q = SCRIPT_DEBUG_qwe;
19
 */
20
21
function jp_error_shutdown() {
22
	$last = error_get_last();
23
24
	if ( is_null( $last ) ) {
25
		return;
26
	}
27
28
	switch ( $last['type'] ) {
29
		case E_CORE_ERROR: // we may not be able to capture this one.
30
		case E_COMPILE_ERROR: // or this one.
31
		case E_PARSE: // we can't actually capture this one.
32
		case E_ERROR:
33
		case E_USER_ERROR:
34
		case E_RECOVERABLE_ERROR:
35
			error_log( print_r( 'jp_error_shutdown START', 1 ) );
36
			jp_custom_error_handler( false, $last['type'], $last['message'], $last['file'], $last['line'] );
37
			error_log( print_r( 'jp_error_shutdown END', 1 ) );
38
39
	}
40
}
41
42
function jp_error_handler( $type, $message, $file, $line ) {
43
	error_log( print_r( 'jp_error_handler START', 1 ) );
44
	jp_custom_error_handler( true, $type, $message, $file, $line );
45
	error_log( print_r( 'jp_error_handler END', 1 ) );
46
47
	// Returning false here to make sure the default error_handler is being fired.
48
	return false;
49
}
50
51
/**
52
 * Shared Error Handler run as a Custom Error Handler and at Shutdown as an error handler of last resort.
53
 * When we run at shutdown we must not die as then the pretty printing of the Error doesn't happen which is lame sauce.
54
 */
55
function jp_custom_error_handler( $whether_i_may_die, $type, $message, $file, $line ) {
56
	if ( ! ( $type & ini_get( 'error_reporting' ) ) ) {
57
		return true;
58
	}
59
60
	$die = false;
61
	switch ( $type ) {
62
		case E_CORE_ERROR: // we may not be able to capture this one.
63
			$string = 'Core error';
64
			$die    = true;
65
			break;
66
		case E_COMPILE_ERROR: // or this one.
67
			$string = 'Compile error';
68
			$die    = true;
69
			break;
70
		case E_PARSE: // we can't actually capture this one.
71
			$string = 'Parse error';
72
			$die    = true;
73
			break;
74
		case E_ERROR:
75
		case E_USER_ERROR:
76
			$string = 'Fatal error';
77
			$die    = true;
78
			break;
79
		case E_WARNING:
80
		case E_USER_WARNING:
81
			$string = 'Warning';
82
			break;
83
		case E_NOTICE:
84
		case E_USER_NOTICE:
85
			$string = 'Notice';
86
			break;
87
		case E_STRICT:
88
			$string = 'Strict Standards';
89
			break;
90
		case E_RECOVERABLE_ERROR:
91
			$string = 'Catchable fatal error';
92
			$die    = true;
93
			break;
94
		case E_DEPRECATED:
95
		case E_USER_DEPRECATED:
96
			$string = 'Deprecated';
97
			break;
98
		case 0:
99
			return true;
100
	}
101
102
	$log_json = array();
103
104
	// @ error suppression
105
	if ( 0 === error_reporting() ) {
106
		$string = '[Suppressed] ' . $string;
0 ignored issues
show
Bug introduced by
The variable $string does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
107
	}
108
109
	$backtrace = jp_get_error_backtrace( $file, $type );
110
111
	if ( ! empty( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_URI'] ) ) {
112
		$source = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
113
	} else {
114
		// What's happening here?
115
		$source = '$ ' . @join( ' ', $GLOBALS['argv'] );
116
	}
117
118
	// Maybe not needed, since it should be handled by default error_handler, and it might not be needed for shutdown handler.
119
	// $display_errors = ini_get( 'display_errors' );
120
	// if ( $display_errors ) {
121
	// 	if ( ini_get( 'html_errors' ) ) {
122
	// 		$display_errors_format = "<br />\n<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br />\n[%s]<br />\n[%s]<br /><br />\n";
123
	// 	} else {
124
	// 		$display_errors_format = "\n%s: %s in %s on line %d [%s] [%s]\n";
125
	// 	}
126
127
	// 	if ( 'stderr' === $display_errors && defined( 'STDERR' ) && is_resource( STDERR ) ) {
128
	// 		fwrite( STDERR, sprintf( $display_errors_format, $string, $message, $file, $line, htmlspecialchars( $source ), htmlspecialchars( $backtrace ) ) );
129
	// 	} else {
130
	// 		printf( $display_errors_format, $string, $message, $file, $line, htmlspecialchars( $source ), htmlspecialchars( $backtrace ) );
131
	// 	}
132
	// }
133
134
	if ( ini_get( 'log_errors' ) ) {
135
		error_log(
136
			sprintf(
137
				'XXXXX ::: %s: %s in %s on line %d [%s] [%s]%s',
138
				$string,
139
				$message,
140
				$file,
141
				$line,
142
				$source,
143
				$backtrace,
144
				empty( $log_json ) ? '' : ' log-json:' . json_encode( $log_json )
145
			)
146
		);
147
	}
148
149
	do_stuff();
150
151
		// When we run at shutdown we must not die as then the pretty printing of the Error doesn't happen which is lame sauce.
152
	if ( $die && $whether_i_may_die ) {
153
		die( 1 );
154
	}
155
	return true;
156
}
157
158
159
function jp_get_error_backtrace( $last_error_file, $last_error_type, $for_irc = false ) {
160
	if ( in_array( $last_error_type, array( E_ERROR, E_USER_ERROR ), true ) ) {
161
		return ''; // The standard debug backtrace is useless for Fatal Errors.
162
	} else {
163
		$backtrace = debug_backtrace( 0 );
164
	}
165
166
	$call_path = array();
167
	foreach ( $backtrace as $bt_key => $call ) {
168
		if ( ! isset( $call['args'] ) ) {
169
			$call['args'] = array( '' );
170
		}
171
172
		if ( in_array( $call['function'], array( __FUNCTION__, 'jp_custom_error_handler', 'jp_error_handler', 'jp_error_shutdown' ), true ) ) {
173
			continue;
174
		}
175
176
		$path  = isset( $call['file'] ) ? str_replace( array( WP_CONTENT_DIR, ABSPATH ), '', $call['file'] ) : '';
177
		$path .= isset( $call['line'] ) ? ':' . $call['line'] : '';
178
179
		if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ), true ) ) {
180
			if ( is_object( $call['args'][0] ) && ! method_exists( $call['args'][0], '__toString' ) ) {
181
				$path .= " {$call['function']}(Object)";
182
			} elseif ( is_array( $call['args'][0] ) ) {
183
				$path .= " {$call['function']}(Array)";
184
			} else {
185
				$path .= " {$call['function']}('{$call['args'][0]}')";
186
			}
187
		} elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ), true ) ) {
188
			$file  = 0 === $bt_key ? $last_error_file : $call['args'][0];
189
			$path .= " {$call['function']}('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ), '', $file ) . "')";
190
		} else {
191
			$path .= " {$call['function']}()";
192
		}
193
194
		$call_path[] = trim( $path );
195
	}
196
197
	return implode( "\n", $call_path );
198
}
199
200
function do_stuff() {
201
	$jp_options = get_option( 'jetpack_options', array() );
202
	$site_id = null;
203
204
	if ( in_array( 'id', $jp_options, true ) ) {
205
		$site_id = $jp_options['id'];
206
	}
207
208
	error_log( print_r( "~~~~~", 1) );
209
	error_log( print_r( $site_id, 1) );
210
}
211