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 : ' '; |
99
|
|
|
$line = ! empty( $line ) ? $line : ' '; |
100
|
|
|
$file = ! empty( $file ) ? $file : ' '; |
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> <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> <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
|
|
|
' <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[] = ' '; |
221
|
|
|
} |
222
|
|
|
if ( is_string( $arg ) ) { |
223
|
|
|
if ( ! $array && strlen( $arg ) > 75 ) { |
224
|
|
|
$args[] = "<br />"; |
225
|
|
|
for ( $i = 0; $i <= $indent; $i++ ) { |
226
|
|
|
$args[] = ' '; |
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[] = ' '; |
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 = '' ) { |
|
|
|
|
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 ) { |
|
|
|
|
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 |
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.