Completed
Branch BUG-9871-email-validation (e62b1a)
by
unknown
350:41 queued 333:27
created

ExceptionStackTraceDisplay::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace EventEspresso\core\exceptions;
3
4
if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
5
	exit( 'No direct script access allowed' );
6
}
7
8
9
10
/**
11
 * Class ExceptionStackTraceDisplay
12
 * displays exceptions with a stack trace and class description for where the exception was thrown
13
 *
14
 * @package       Event Espresso
15
 * @author        Brent Christensen
16
 * @since         4.9.0
17
 */
18
class ExceptionStackTraceDisplay {
19
20
21
22
	/**
23
	 * @param \Exception $exception
24
	 */
25
	public function __construct( \Exception $exception ) {
26
		if ( WP_DEBUG ) {
27
			$this->displayException( $exception );
28
		}
29
	}
30
31
32
33
	/**
34
	 * @access protected
35
	 * @param \Exception $exception
36
	 */
37
	protected function displayException( \Exception $exception ) {
38
39
		$error_code = '';
40
		$trace_details = '';
41
		$time = time();
42
		$trace = $exception->getTrace();
43
		// get separate user and developer messages if they exist
44
		$msg = explode( '||', $exception->getMessage() );
45
		$user_msg = $msg[0];
46
		$dev_msg = isset( $msg[1] ) ? $msg[1] : $msg[0];
47
		$msg = WP_DEBUG ? $dev_msg : $user_msg;
48
		// start gathering output
49
		$output = $this->exceptionStyles();
50
		$output .= '
51
<div id="ee-error-message" class="error">';
52
		if ( ! WP_DEBUG ) {
53
			$output .= '
54
	<p>';
55
		}
56
			// process trace info
57
			if ( empty( $trace ) ) {
58
				$trace_details .= __(
59
					'Sorry, but no trace information was available for this exception.',
60
					'event_espresso'
61
				);
62
			} else {
63
				$trace_details .= '
64
			<div id="ee-trace-details">
65
			<table width="100%" border="0" cellpadding="5" cellspacing="0">
66
				<tr>
67
					<th scope="col" align="right" style="width:2.5%;">#</th>
68
					<th scope="col" align="right" style="width:3.5%;">Line</th>
69
					<th scope="col" align="left" style="width:40%;">File</th>
70
					<th scope="col" align="left">' . __( 'Class', 'event_espresso' ) . '->' . __( 'Method( arguments )', 'event_espresso' ) . '</th>
71
				</tr>';
72
				$last_on_stack = count( $trace ) - 1;
73
				// reverse array so that stack is in proper chronological order
74
				$sorted_trace = array_reverse( $trace );
75
				foreach ( $sorted_trace as $nmbr => $trace ) {
76
					$file = isset( $trace['file'] ) ? $trace['file'] : '';
77
					$class = isset( $trace['class'] ) ? $trace['class'] : '';
78
					$type = isset( $trace['type'] ) ? $trace['type'] : '';
79
					$function = isset( $trace['function'] ) ? $trace['function'] : '';
80
					$args = isset( $trace['args'] ) ? $this->_convert_args_to_string( $trace['args'] ) : '';
81
					$args = isset( $trace['args'] ) && count( $trace['args'] ) > 4  ? ' <br />' . $args . '<br />' : $args;
82
					$line = isset( $trace['line'] ) ? $trace['line'] : '';
83
					$zebra = $nmbr % 2 !== 0 ? ' odd' : '';
84 View Code Duplication
					if ( empty( $file ) && ! empty( $class ) ) {
85
						$a = new \ReflectionClass( $class );
86
						$file = $a->getFileName();
87
						if ( empty( $line ) && ! empty( $function ) ) {
88
							$b = new \ReflectionMethod( $class, $function );
89
							$line = $b->getStartLine();
90
						}
91
					}
92
					if ( $nmbr === $last_on_stack ) {
93
						$file = $exception->getFile() !== '' ? $exception->getFile() : $file;
94
						$line = $exception->getLine() !== '' ? $exception->getLine() : $line;
95
						$error_code = $this->generate_error_code( $file, $trace['function'], $line );
96
					}
97
					$file = \EEH_File::standardise_directory_separators( $file );
98
					$nmbr = ! empty( $nmbr ) ? $nmbr : '&nbsp;';
99
					$line = ! empty( $line ) ? $line : '&nbsp;';
100
					$file = ! empty( $file ) ? $file : '&nbsp;';
101
					$class_display = ! empty( $class ) ? $class : '';
102
					$type = ! empty( $type ) ? $type : '';
103
					$function = ! empty( $function ) ? $function : '';
104
					$args = ! empty( $args ) ? '( ' . $args . ' )' : '()';
105
					$trace_details .= '
106
					<tr>
107
						<td align="right" valign="top" class="' . $zebra . '">' . $nmbr . '</td>
108
						<td align="right" valign="top" class="' . $zebra . '">' . $line . '</td>
109
						<td align="left" valign="top" class="' . $zebra . '">' . $file . '</td>
110
						<td align="left" valign="top" class="' . $zebra . '">' . $class_display . $type . $function . $args . '</td>
111
					</tr>';
112
				}
113
				$trace_details .= '
114
			 </table>
115
			</div>';
116
			}
117
			$code = $exception->getCode() ? $exception->getCode() : $error_code;
118
			// add generic non-identifying messages for non-privileged users
119
			if ( ! WP_DEBUG ) {
120
				$output .= '<span class="ee-error-user-msg-spn">'
121
				           . trim( $msg )
122
				           . '</span> &nbsp; <sup>'
123
				           . $code
124
				           . '</sup><br />';
125
			} else {
126
				// or helpful developer messages if debugging is on
127
				$output .= '
128
		<div class="ee-error-dev-msg-dv">
129
			<p class="ee-error-dev-msg-pg">
130
				'
131
				. sprintf(
132
					__( '%1$sAn %2$s was thrown!%3$s code: %4$s', 'event_espresso' ),
133
				    '<strong class="ee-error-dev-msg-str">',
134
					get_class( $exception ),
135
					'</strong>  &nbsp; <span>',
136
					$code . '</span>'
137
				)
138
				. '<br />
139
				<span class="big-text">"'
140
				           . trim( $msg )
141
				           . '"</span><br/>
142
				<a id="display-ee-error-trace-1'
143
				           . $time
144
				           . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
145
				           . $time
146
				           . '">
147
					'
148
				           . __( 'click to view backtrace and class/method details', 'event_espresso' )
149
				           . '
150
				</a><br />
151
				'
152
				           . $exception->getFile()
153
				           . sprintf(
154
					           __( '%1$s( line no: %2$s )%3$s', 'event_espresso' ),
155
					           ' &nbsp; <span class="small-text lt-grey-text">',
156
					           $exception->getLine(),
157
					           '</span>'
158
				           )
159
				           . '
160
			</p>
161
			<div id="ee-error-trace-1'
162
				           . $time
163
				           . '-dv" class="ee-error-trace-dv" style="display: none;">
164
				'
165
				           . $trace_details;
166
				if ( ! empty( $class ) ) {
167
					$output .= '
168
				<div style="padding:3px; margin:0 0 1em; border:1px solid #999; background:#fff; border-radius:3px;">
169
					<div style="padding:1em 2em; border:1px solid #999; background:#fcfcfc;">
170
						<h3>' . __( 'Class Details', 'event_espresso' ) . '</h3>';
171
					$a = new \ReflectionClass( $class );
172
					$output .= '
173
						<pre>' . $a . '</pre>
174
					</div>
175
				</div>';
176
				}
177
				$output .= '
178
			</div>
179
		</div>
180
		<br />';
181
			}
182
		// remove last linebreak
183
		$output = substr( $output, 0, count( $output ) - 7 );
184
		if ( ! WP_DEBUG ) {
185
			$output .= '
186
	</p>';
187
		}
188
		$output .= '
189
</div>';
190
		$output .= $this->printScripts( true );
191
		if ( defined( 'DOING_AJAX' ) ) {
192
			echo json_encode( array( 'error' => $output ) );
193
			exit();
194
		}
195
		echo $output;
196
		die();
197
	}
198
199
200
201
	/**
202
	 * generate string from exception trace args
203
	 *
204
	 * @param array $arguments
205
	 * @param int   $indent
206
	 * @param bool  $array
207
	 * @return string
208
	 */
209
	private function _convert_args_to_string( $arguments = array(), $indent = 0, $array = false ) {
210
		$args = array();
211
		$args_count = count( $arguments );
212
		if ( $args_count > 2 ) {
213
			$indent++;
214
			$args[] = '<br />';
215
		}
216
		$x = 0;
217
		foreach ( $arguments as $arg ) {
218
			$x++;
219
			for( $i = 0; $i < $indent; $i++ ) {
220
				$args[] = ' &nbsp;&nbsp; ';
221
			}
222
			if ( is_string( $arg ) ) {
223
				if ( ! $array && strlen( $arg ) > 75 ) {
224
					$args[] = "<br />";
225
					for ( $i = 0; $i <= $indent; $i++ ) {
226
						$args[] = ' &nbsp;&nbsp; ';
227
					}
228
					$args[] = "'" . $arg . "'<br />";
229
				} else {
230
					$args[] = " '" . $arg . "'";
231
				}
232
			} elseif ( is_array( $arg ) ) {
233
				$arg_count = count( $arg );
234
				if ( $arg_count > 2 ) {
235
					$indent++;
236
					$args[] = " array(" . $this->_convert_args_to_string( $arg, $indent, true ) . ")";
237
					$indent--;
238
				} else if ( $arg_count === 0 ) {
239
					$args[] = " array()";
240
				} else {
241
					$args[] = " array( " . $this->_convert_args_to_string( $arg ) . " )";
242
				}
243
			} elseif ( $arg === null ) {
244
				$args[] = ' null';
245
			} elseif ( is_bool( $arg ) ) {
246
				$args[] = $arg ? ' true' : ' false';
247
			} elseif ( is_object( $arg ) ) {
248
				$args[] = get_class( $arg );
249
			} elseif ( is_resource( $arg ) ) {
250
				$args[] = get_resource_type( $arg );
251
			} else {
252
				$args[] = $arg;
253
			}
254
			if ( $x === $args_count ) {
255
				if ( $args_count > 2 ) {
256
					$args[] = "<br />";
257
					$indent--;
258
					for ( $i = 1; $i < $indent; $i++ ) {
259
						$args[] = ' &nbsp;&nbsp; ';
260
					}
261
				}
262
			} else {
263
				$args[] = $args_count > 2 ? ",<br />" : ', ';
264
			}
265
		}
266
		return implode( '', $args );
267
	}
268
269
270
271
	/**
272
	 * create error code from filepath, function name,
273
	 * and line number where exception or error was thrown
274
	 *
275
	 * @access protected
276
	 * @param string $file
277
	 * @param string $func
278
	 * @param string $line
279
	 * @return string
280
	 */
281 View Code Duplication
	protected function generate_error_code( $file = '', $func = '', $line = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
		$file_bits = explode( '.', basename( $file ) );
283
		$error_code = ! empty( $file_bits[0] ) ? $file_bits[0] : '';
284
		$error_code .= ! empty( $func ) ? ' - ' . $func : '';
285
		$error_code .= ! empty( $line ) ? ' - ' . $line : '';
286
		return $error_code;
287
	}
288
289
290
291
292
293
294
295
296
	/**
297
	 * _exception_styles
298
	 *
299
	 * @return string
300
	 */
301
	private static function exceptionStyles() {
302
		return '
303
<style type="text/css">
304
	#ee-error-message {
305
		max-width:90% !important;
306
		margin: 0 5%;
307
	}
308
	.ee-error-dev-msg-pg,
309
	.error .ee-error-dev-msg-pg {
310
		padding:1em;
311
		margin:0 0 1em;
312
		border:2px solid #E44064;
313
		background:#fff;
314
		border-radius:3px;
315
		line-height: 1.5em;;
316
	}
317
	#ee-trace-details {
318
		padding:3px;
319
		margin:0 0 1em;
320
		border:1px solid #999;
321
		background:#f9f9f9;
322
		border-radius:3px;
323
	}
324
	#ee-trace-details table {
325
		border:1px solid #999;
326
		border-bottom:none;
327
		background:#fff;
328
	}
329
	#ee-trace-details table th {
330
		background:#eee;
331
		border-bottom:1px solid #ccc;
332
	}
333
	#ee-trace-details table td {
334
		border-bottom:1px solid #e8e8e8;
335
		padding: 10px 5px;
336
	}
337
	#ee-trace-details table td.odd {
338
		background:#fdfdfd;
339
	}
340
	.display-ee-error-trace-lnk {
341
		color:blue;
342
		cursor:pointer;
343
	}
344
	.display-ee-error-trace-lnk:hover {
345
		text-decoration:underline;
346
	}
347
	.hidden {
348
		display:none;
349
	}
350
	.small-text {
351
		font-size: .85em;
352
		line-height: 1.4em;
353
		letter-spacing: 1px;
354
	}
355
	.lt-grey-text {
356
		color: #999;
357
	}
358
</style>';
359
	}
360
361
362
363
	/**
364
	 * _print_scripts
365
	 *
366
	 * @param bool $force_print
367
	 * @return string|void
368
	 */
369 View Code Duplication
	private function printScripts( $force_print = false ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
370
		if ( ! $force_print  && ( did_action( 'admin_enqueue_scripts' ) || did_action( 'wp_enqueue_scripts' ) ) ) {
371
			if ( wp_script_is( 'ee_error_js', 'enqueued' ) ) {
372
				return '';
373
			} else if ( wp_script_is( 'ee_error_js', 'registered' ) ) {
374
				add_filter( 'FHEE_load_css', '__return_true' );
375
				add_filter( 'FHEE_load_js', '__return_true' );
376
				wp_enqueue_script( 'ee_error_js' );
377
				wp_localize_script( 'ee_error_js', 'ee_settings', array( 'wp_debug' => WP_DEBUG ) );
378
			}
379
		} else {
380
			return '
381
<script>
382
/* <![CDATA[ */
383
var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
384
/* ]]> */
385
</script>
386
<script src="' . includes_url() . 'js/jquery/jquery.js" type="text/javascript"></script>
387
<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
388
<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
389
';
390
		}
391
		return '';
392
	}
393
394
395
396
}
397
// End of file ExceptionStackTraceDisplay.php
398
// Location: /core/exceptions/ExceptionStackTraceDisplay.php