Completed
Branch FET/10339/exit-modal-for-ee-de... (81712e)
by
unknown
29:29 queued 13:19
created

EE_Error::storeNotices()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
4
use EventEspresso\core\exceptions\InvalidDataTypeException;
5
use EventEspresso\core\exceptions\InvalidInterfaceException;
6
use EventEspresso\core\services\container\exceptions\ServiceNotFoundException;
7
use EventEspresso\core\services\loaders\LoaderFactory;
8
use EventEspresso\core\services\notifications\PersistentAdminNoticeManager;
9
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
10
11
// if you're a dev and want to receive all errors via email
12
// add this to your wp-config.php: define( 'EE_ERROR_EMAILS', TRUE );
13
if (defined('WP_DEBUG') && WP_DEBUG === true && defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS === true) {
14
    set_error_handler(array('EE_Error', 'error_handler'));
15
    register_shutdown_function(array('EE_Error', 'fatal_error_handler'));
16
}
17
18
19
20
/**
21
 * Error Handling Class
22
 *
23
 * @package               Event Espresso
24
 * @subpackage            includes/classes/EE_Exceptions.class.php
25
 * @author                Brent Christensen
26
 */
27
class EE_Error extends Exception
28
{
29
30
    const OPTIONS_KEY_NOTICES = 'ee_notices';
31
32
33
    /**
34
     * name of the file to log exceptions to
35
     *
36
     * @var string
37
     */
38
    private static $_exception_log_file = 'espresso_error_log.txt';
0 ignored issues
show
Unused Code introduced by
The property $_exception_log_file is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
39
40
    /**
41
     *    stores details for all exception
42
     *
43
     * @var array
44
     */
45
    private static $_all_exceptions = array();
46
47
    /**
48
     *    tracks number of errors
49
     *
50
     * @var int
51
     */
52
    private static $_error_count = 0;
53
54
    /**
55
     * @var array $_espresso_notices
56
     */
57
    private static $_espresso_notices = array('success' => false, 'errors' => false, 'attention' => false);
58
59
60
61
    /**
62
     * @override default exception handling
63
     * @param string         $message
64
     * @param int            $code
65
     * @param Exception|null $previous
66
     */
67
    public function __construct($message, $code = 0, Exception $previous = null)
68
    {
69
        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
70
            parent::__construct($message, $code);
71
        } else {
72
            parent::__construct($message, $code, $previous);
73
        }
74
    }
75
76
77
    /**
78
     *    error_handler
79
     *
80
     * @param $code
81
     * @param $message
82
     * @param $file
83
     * @param $line
84
     * @return void
85
     */
86
    public static function error_handler($code, $message, $file, $line)
87
    {
88
        $type = EE_Error::error_type($code);
89
        $site = site_url();
90
        switch ($site) {
91
            case 'http://ee4.eventespresso.com/' :
92
            case 'http://ee4decaf.eventespresso.com/' :
93
            case 'http://ee4hf.eventespresso.com/' :
94
            case 'http://ee4a.eventespresso.com/' :
95
            case 'http://ee4ad.eventespresso.com/' :
96
            case 'http://ee4b.eventespresso.com/' :
97
            case 'http://ee4bd.eventespresso.com/' :
98
            case 'http://ee4d.eventespresso.com/' :
99
            case 'http://ee4dd.eventespresso.com/' :
100
                $to = '[email protected]';
101
                break;
102
            default :
103
                $to = get_option('admin_email');
104
        }
105
        $subject = $type . ' ' . $message . ' in ' . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
106
        $msg = EE_Error::_format_error($type, $message, $file, $line);
107
        if (function_exists('wp_mail')) {
108
            add_filter('wp_mail_content_type', array('EE_Error', 'set_content_type'));
109
            wp_mail($to, $subject, $msg);
110
        }
111
        echo '<div id="message" class="espresso-notices error"><p>';
112
        echo $type . ': ' . $message . '<br />' . $file . ' line ' . $line;
113
        echo '<br /></p></div>';
114
    }
115
116
117
118
    /**
119
     * error_type
120
     * http://www.php.net/manual/en/errorfunc.constants.php#109430
121
     *
122
     * @param $code
123
     * @return string
124
     */
125
    public static function error_type($code)
126
    {
127
        switch ($code) {
128
            case E_ERROR: // 1 //
129
                return 'E_ERROR';
130
            case E_WARNING: // 2 //
131
                return 'E_WARNING';
132
            case E_PARSE: // 4 //
133
                return 'E_PARSE';
134
            case E_NOTICE: // 8 //
135
                return 'E_NOTICE';
136
            case E_CORE_ERROR: // 16 //
137
                return 'E_CORE_ERROR';
138
            case E_CORE_WARNING: // 32 //
139
                return 'E_CORE_WARNING';
140
            case E_COMPILE_ERROR: // 64 //
141
                return 'E_COMPILE_ERROR';
142
            case E_COMPILE_WARNING: // 128 //
143
                return 'E_COMPILE_WARNING';
144
            case E_USER_ERROR: // 256 //
145
                return 'E_USER_ERROR';
146
            case E_USER_WARNING: // 512 //
147
                return 'E_USER_WARNING';
148
            case E_USER_NOTICE: // 1024 //
149
                return 'E_USER_NOTICE';
150
            case E_STRICT: // 2048 //
151
                return 'E_STRICT';
152
            case E_RECOVERABLE_ERROR: // 4096 //
153
                return 'E_RECOVERABLE_ERROR';
154
            case E_DEPRECATED: // 8192 //
155
                return 'E_DEPRECATED';
156
            case E_USER_DEPRECATED: // 16384 //
157
                return 'E_USER_DEPRECATED';
158
            case E_ALL: // 16384 //
159
                return 'E_ALL';
160
        }
161
        return '';
162
    }
163
164
165
166
    /**
167
     *    fatal_error_handler
168
     *
169
     * @return void
170
     */
171
    public static function fatal_error_handler()
172
    {
173
        $last_error = error_get_last();
174
        if ($last_error['type'] === E_ERROR) {
175
            EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
176
        }
177
    }
178
179
180
181
    /**
182
     * _format_error
183
     *
184
     * @param $code
185
     * @param $message
186
     * @param $file
187
     * @param $line
188
     * @return string
189
     */
190
    private static function _format_error($code, $message, $file, $line)
191
    {
192
        $html = "<table cellpadding='5'><thead bgcolor='#f8f8f8'><th>Item</th><th align='left'>Details</th></thead><tbody>";
193
        $html .= "<tr valign='top'><td><b>Code</b></td><td>$code</td></tr>";
194
        $html .= "<tr valign='top'><td><b>Error</b></td><td>$message</td></tr>";
195
        $html .= "<tr valign='top'><td><b>File</b></td><td>$file</td></tr>";
196
        $html .= "<tr valign='top'><td><b>Line</b></td><td>$line</td></tr>";
197
        $html .= '</tbody></table>';
198
        return $html;
199
    }
200
201
202
203
    /**
204
     * set_content_type
205
     *
206
     * @param $content_type
207
     * @return string
208
     */
209
    public static function set_content_type($content_type)
210
    {
211
        return 'text/html';
212
    }
213
214
215
216
    /**
217
     * @return void
218
     * @throws EE_Error
219
     * @throws ReflectionException
220
     */
221
    public function get_error()
222
    {
223
        if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
224
            throw $this;
225
        }
226
        // get separate user and developer messages if they exist
227
        $msg = explode('||', $this->getMessage());
228
        $user_msg = $msg[0];
229
        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
230
        $msg = WP_DEBUG ? $dev_msg : $user_msg;
231
        // add details to _all_exceptions array
232
        $x_time = time();
233
        self::$_all_exceptions[$x_time]['name'] = get_class($this);
234
        self::$_all_exceptions[$x_time]['file'] = $this->getFile();
235
        self::$_all_exceptions[$x_time]['line'] = $this->getLine();
236
        self::$_all_exceptions[$x_time]['msg'] = $msg;
237
        self::$_all_exceptions[$x_time]['code'] = $this->getCode();
238
        self::$_all_exceptions[$x_time]['trace'] = $this->getTrace();
239
        self::$_all_exceptions[$x_time]['string'] = $this->getTraceAsString();
240
        self::$_error_count++;
241
        //add_action( 'shutdown', array( $this, 'display_errors' ));
242
        $this->display_errors();
243
    }
244
245
246
    /**
247
     * @param bool   $check_stored
248
     * @param string $type_to_check
249
     * @return bool
250
     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
251
     * @throws \InvalidArgumentException
252
     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
253
     * @throws InvalidInterfaceException
254
     */
255
    public static function has_error($check_stored = false, $type_to_check = 'errors')
256
    {
257
        $has_error = isset(self::$_espresso_notices[$type_to_check])
258
                     && ! empty(self::$_espresso_notices[$type_to_check])
259
            ? true
260
            : false;
261
        if ($check_stored && ! $has_error) {
262
            $notices = EE_Error::getStoredNotices();
263
            foreach ($notices as $type => $notice) {
264
                if ($type === $type_to_check && $notice) {
265
                    return true;
266
                }
267
            }
268
        }
269
        return $has_error;
270
    }
271
272
273
274
    /**
275
     * @echo string
276
     * @throws \ReflectionException
277
     */
278
    public function display_errors()
279
    {
280
        $trace_details = '';
281
        $output = '
282
<style type="text/css">
283
	#ee-error-message {
284
		max-width:90% !important;
285
		margin: 0 5%;
286
	}
287
	.ee-error-dev-msg-pg,
288
	.error .ee-error-dev-msg-pg {
289
		padding:1em;
290
		margin:0 0 1em;
291
		border:2px solid #E44064;
292
		background:#fff;
293
		border-radius:3px;
294
	}
295
	#ee-trace-details {
296
		padding:3px;
297
		margin:0 0 1em;
298
		border:1px solid #666;
299
		background:#fff;
300
		border-radius:3px;
301
	}
302
	#ee-trace-details table {
303
		border:1px solid #666;
304
		border-bottom:none;
305
		background:#f9f9f9;
306
	}
307
	#ee-trace-details table th {
308
		background:#eee;
309
		border-bottom:1px solid #666;
310
	}
311
	#ee-trace-details table td {
312
		border-bottom:1px solid #666;
313
	}
314
	#ee-trace-details table td.odd {
315
		background:#f3f3f3;
316
	}
317
	.display-ee-error-trace-lnk {
318
		color:blue;
319
		cursor:pointer;
320
	}
321
	.display-ee-error-trace-lnk:hover {
322
		text-decoration:underline;
323
	}
324
	.hidden {
325
		display:none;
326
	}
327
	.small-text {
328
		font-size: .85em;
329
		line-height: 1.4em;
330
		letter-spacing: 1px;
331
	}
332
	.lt-grey-text {
333
		color: #a8a8a8;
334
	}
335
</style>
336
<div id="ee-error-message" class="error">';
337
        if (! WP_DEBUG) {
338
            $output .= '
339
	<p>';
340
        }
341
        // cycle thru errors
342
        foreach (self::$_all_exceptions as $time => $ex) {
343
            $error_code = '';
344
            // process trace info
345
            if (empty($ex['trace'])) {
346
                $trace_details .= __(
347
                    'Sorry, but no trace information was available for this exception.',
348
                    'event_espresso'
349
                );
350
            } else {
351
                $trace_details .= '
352
			<div id="ee-trace-details">
353
			<table width="100%" border="0" cellpadding="5" cellspacing="0">
354
				<tr>
355
					<th scope="col" align="right" style="width:2.5%;">#</th>
356
					<th scope="col" align="right" style="width:3.5%;">Line</th>
357
					<th scope="col" align="left" style="width:40%;">File</th>
358
					<th scope="col" align="left">Class</th>
359
					<th scope="col" align="left">Method( arguments )</th>
360
				</tr>';
361
                $last_on_stack = count($ex['trace']) - 1;
362
                // reverse array so that stack is in proper chronological order
363
                $sorted_trace = array_reverse($ex['trace']);
364
                foreach ($sorted_trace as $nmbr => $trace) {
365
                    $file = isset($trace['file']) ? $trace['file'] : '';
366
                    $class = isset($trace['class']) ? $trace['class'] : '';
367
                    $type = isset($trace['type']) ? $trace['type'] : '';
368
                    $function = isset($trace['function']) ? $trace['function'] : '';
369
                    $args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
370
                    $line = isset($trace['line']) ? $trace['line'] : '';
371
                    $zebra = ($nmbr % 2) ? ' odd' : '';
372 View Code Duplication
                    if (empty($file) && ! empty($class)) {
373
                        $a = new ReflectionClass($class);
374
                        $file = $a->getFileName();
375
                        if (empty($line) && ! empty($function)) {
376
                            try {
377
                                //if $function is a closure, this throws an exception
378
                                $b = new ReflectionMethod($class, $function);
379
                                $line = $b->getStartLine();
380
                            } catch (Exception $closure_exception) {
381
                                $line = 'unknown';
382
                            }
383
                        }
384
                    }
385
                    if ($nmbr === $last_on_stack) {
386
                        $file = $ex['file'] !== '' ? $ex['file'] : $file;
387
                        $line = $ex['line'] !== '' ? $ex['line'] : $line;
388
                        $error_code = self::generate_error_code($file, $trace['function'], $line);
389
                    }
390
                    $nmbr_dsply = ! empty($nmbr) ? $nmbr : '&nbsp;';
391
                    $line_dsply = ! empty($line) ? $line : '&nbsp;';
392
                    $file_dsply = ! empty($file) ? $file : '&nbsp;';
393
                    $class_dsply = ! empty($class) ? $class : '&nbsp;';
394
                    $type_dsply = ! empty($type) ? $type : '&nbsp;';
395
                    $function_dsply = ! empty($function) ? $function : '&nbsp;';
396
                    $args_dsply = ! empty($args) ? '( ' . $args . ' )' : '';
397
                    $trace_details .= '
398
					<tr>
399
						<td align="right" class="' . $zebra . '">' . $nmbr_dsply . '</td>
400
						<td align="right" class="' . $zebra . '">' . $line_dsply . '</td>
401
						<td align="left" class="' . $zebra . '">' . $file_dsply . '</td>
402
						<td align="left" class="' . $zebra . '">' . $class_dsply . '</td>
403
						<td align="left" class="' . $zebra . '">' . $type_dsply . $function_dsply . $args_dsply . '</td>
404
					</tr>';
405
                }
406
                $trace_details .= '
407
			 </table>
408
			</div>';
409
            }
410
            $ex['code'] = $ex['code'] ? $ex['code'] : $error_code;
411
            // add generic non-identifying messages for non-privileged users
412
            if (! WP_DEBUG) {
413
                $output .= '<span class="ee-error-user-msg-spn">'
414
                           . trim($ex['msg'])
415
                           . '</span> &nbsp; <sup>'
416
                           . $ex['code']
417
                           . '</sup><br />';
418
            } else {
419
                // or helpful developer messages if debugging is on
420
                $output .= '
421
		<div class="ee-error-dev-msg-dv">
422
			<p class="ee-error-dev-msg-pg">
423
				<strong class="ee-error-dev-msg-str">An '
424
                           . $ex['name']
425
                           . ' exception was thrown!</strong>  &nbsp; <span>code: '
426
                           . $ex['code']
427
                           . '</span><br />
428
				<span class="big-text">"'
429
                           . trim($ex['msg'])
430
                           . '"</span><br/>
431
				<a id="display-ee-error-trace-'
432
                           . self::$_error_count
433
                           . $time
434
                           . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
435
                           . self::$_error_count
436
                           . $time
437
                           . '">
438
					'
439
                           . __('click to view backtrace and class/method details', 'event_espresso')
440
                           . '
441
				</a><br />
442
				<span class="small-text lt-grey-text">'
443
                           . $ex['file']
444
                           . ' &nbsp; ( line no: '
445
                           . $ex['line']
446
                           . ' )</span>
447
			</p>
448
			<div id="ee-error-trace-'
449
                           . self::$_error_count
450
                           . $time
451
                           . '-dv" class="ee-error-trace-dv" style="display: none;">
452
				'
453
                           . $trace_details;
454
                if (! empty($class)) {
455
                    $output .= '
456
				<div style="padding:3px; margin:0 0 1em; border:1px solid #666; background:#fff; border-radius:3px;">
457
					<div style="padding:1em 2em; border:1px solid #666; background:#f9f9f9;">
458
						<h3>Class Details</h3>';
459
                    $a = new ReflectionClass($class);
460
                    $output .= '
461
						<pre>' . $a . '</pre>
462
					</div>
463
				</div>';
464
                }
465
                $output .= '
466
			</div>
467
		</div>
468
		<br />';
469
            }
470
            $this->write_to_error_log($time, $ex);
471
        }
472
        // remove last linebreak
473
        $output = substr($output, 0, -6);
474
        if (! WP_DEBUG) {
475
            $output .= '
476
	</p>';
477
        }
478
        $output .= '
479
</div>';
480
        $output .= self::_print_scripts(true);
481
        if (defined('DOING_AJAX')) {
482
            echo wp_json_encode(array('error' => $output));
483
            exit();
484
        }
485
        echo $output;
486
        die();
487
    }
488
489
490
491
    /**
492
     *    generate string from exception trace args
493
     *
494
     * @param array $arguments
495
     * @param bool  $array
496
     * @return string
497
     */
498
    private function _convert_args_to_string($arguments = array(), $array = false)
499
    {
500
        $arg_string = '';
501
        if (! empty($arguments)) {
502
            $args = array();
503
            foreach ($arguments as $arg) {
504
                if (! empty($arg)) {
505
                    if (is_string($arg)) {
506
                        $args[] = " '" . $arg . "'";
507
                    } elseif (is_array($arg)) {
508
                        $args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
509
                    } elseif ($arg === null) {
510
                        $args[] = ' NULL';
511
                    } elseif (is_bool($arg)) {
512
                        $args[] = ($arg) ? ' TRUE' : ' FALSE';
513
                    } elseif (is_object($arg)) {
514
                        $args[] = ' OBJECT ' . get_class($arg);
515
                    } elseif (is_resource($arg)) {
516
                        $args[] = get_resource_type($arg);
517
                    } else {
518
                        $args[] = $arg;
519
                    }
520
                }
521
            }
522
            $arg_string = implode(', ', $args);
523
        }
524
        if ($array) {
525
            $arg_string .= ' )';
526
        }
527
        return $arg_string;
528
    }
529
530
531
532
    /**
533
     *    add error message
534
     *
535
     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
536
     *                            separate messages for user || dev
537
     * @param        string $file the file that the error occurred in - just use __FILE__
538
     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
539
     * @param        string $line the line number where the error occurred - just use __LINE__
540
     * @return        void
541
     */
542
    public static function add_error($msg = null, $file = null, $func = null, $line = null)
543
    {
544
        self::_add_notice('errors', $msg, $file, $func, $line);
545
        self::$_error_count++;
546
    }
547
548
549
550
    /**
551
     * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
552
     * adds an error
553
     *
554
     * @param string $msg
555
     * @param string $file
556
     * @param string $func
557
     * @param string $line
558
     * @throws EE_Error
559
     */
560
    public static function throw_exception_if_debugging($msg = null, $file = null, $func = null, $line = null)
561
    {
562
        if (WP_DEBUG) {
563
            throw new EE_Error($msg);
564
        }
565
        EE_Error::add_error($msg, $file, $func, $line);
566
    }
567
568
569
570
    /**
571
     *    add success message
572
     *
573
     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
574
     *                            separate messages for user || dev
575
     * @param        string $file the file that the error occurred in - just use __FILE__
576
     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
577
     * @param        string $line the line number where the error occurred - just use __LINE__
578
     * @return        void
579
     */
580
    public static function add_success($msg = null, $file = null, $func = null, $line = null)
581
    {
582
        self::_add_notice('success', $msg, $file, $func, $line);
583
    }
584
585
586
587
    /**
588
     *    add attention message
589
     *
590
     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
591
     *                            separate messages for user || dev
592
     * @param        string $file the file that the error occurred in - just use __FILE__
593
     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
594
     * @param        string $line the line number where the error occurred - just use __LINE__
595
     * @return        void
596
     */
597
    public static function add_attention($msg = null, $file = null, $func = null, $line = null)
598
    {
599
        self::_add_notice('attention', $msg, $file, $func, $line);
600
    }
601
602
603
604
    /**
605
     * @param string $type whether the message is for a success or error notification
606
     * @param string $msg the message to display to users or developers
607
     *                    - adding a double pipe || (OR) creates separate messages for user || dev
608
     * @param string $file the file that the error occurred in - just use __FILE__
609
     * @param string $func the function/method that the error occurred in - just use __FUNCTION__
610
     * @param string $line the line number where the error occurred - just use __LINE__
611
     * @return void
612
     */
613
    private static function _add_notice($type = 'success', $msg = '', $file = '', $func = '', $line = '')
614
    {
615
        if (empty($msg)) {
616
            EE_Error::doing_it_wrong(
617
                'EE_Error::add_' . $type . '()',
618
                sprintf(
619
                    __('Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
620
                        'event_espresso'),
621
                    $type,
622
                    $file,
623
                    $line
624
                ),
625
                EVENT_ESPRESSO_VERSION
626
            );
627
        }
628
        if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
629
            EE_Error::doing_it_wrong(
630
                'EE_Error::add_error()',
631
                __('You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
632
                    'event_espresso'),
633
                EVENT_ESPRESSO_VERSION
634
            );
635
        }
636
        // get separate user and developer messages if they exist
637
        $msg      = explode('||', $msg);
638
        $user_msg = $msg[0];
639
        $dev_msg  = isset($msg[1]) ? $msg[1] : $msg[0];
640
        /**
641
         * Do an action so other code can be triggered when a notice is created
642
         *
643
         * @param string $type     can be 'errors', 'attention', or 'success'
644
         * @param string $user_msg message displayed to user when WP_DEBUG is off
645
         * @param string $user_msg message displayed to user when WP_DEBUG is on
646
         * @param string $file     file where error was generated
647
         * @param string $func     function where error was generated
648
         * @param string $line     line where error was generated
649
         */
650
        do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
651
        $msg = WP_DEBUG ? $dev_msg : $user_msg;
652
        // add notice if message exists
653
        if (! empty($msg)) {
654
            // get error code
655
            $notice_code = EE_Error::generate_error_code($file, $func, $line);
656
            if (WP_DEBUG && $type === 'errors') {
657
                $msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
658
            }
659
            // add notice. Index by code if it's not blank
660
            if ($notice_code) {
661
                self::$_espresso_notices[$type][$notice_code] = $msg;
662
            } else {
663
                self::$_espresso_notices[$type][] = $msg;
664
            }
665
            add_action('wp_footer', array('EE_Error', 'enqueue_error_scripts'), 1);
666
        }
667
    }
668
669
670
    /**
671
     * in some case it may be necessary to overwrite the existing success messages
672
     *
673
     * @return        void
674
     */
675
    public static function overwrite_success()
676
    {
677
        self::$_espresso_notices['success'] = false;
678
    }
679
680
681
682
    /**
683
     * in some case it may be necessary to overwrite the existing attention messages
684
     *
685
     * @return void
686
     */
687
    public static function overwrite_attention()
688
    {
689
        self::$_espresso_notices['attention'] = false;
690
    }
691
692
693
694
    /**
695
     * in some case it may be necessary to overwrite the existing error messages
696
     *
697
     * @return void
698
     */
699
    public static function overwrite_errors()
700
    {
701
        self::$_espresso_notices['errors'] = false;
702
    }
703
704
705
706
    /**
707
     * @return void
708
     */
709
    public static function reset_notices()
710
    {
711
        self::$_espresso_notices['success']   = false;
712
        self::$_espresso_notices['attention'] = false;
713
        self::$_espresso_notices['errors']    = false;
714
    }
715
716
717
718
    /**
719
     * @return int
720
     */
721
    public static function has_notices()
722
    {
723
        $has_notices = 0;
724
        // check for success messages
725
        $has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])
726
            ? 3
727
            : $has_notices;
728
        // check for attention messages
729
        $has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])
730
            ? 2
731
            : $has_notices;
732
        // check for error messages
733
        $has_notices = self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])
734
            ? 1
735
            : $has_notices;
736
        return $has_notices;
737
    }
738
739
740
    /**
741
     * This simply returns non formatted error notices as they were sent into the EE_Error object.
742
     *
743
     * @since 4.9.0
744
     * @return array
745
     */
746
    public static function get_vanilla_notices()
747
    {
748
        return array(
749
            'success'   => isset(self::$_espresso_notices['success'])
750
                ? self::$_espresso_notices['success']
751
                : array(),
752
            'attention' => isset(self::$_espresso_notices['attention'])
753
                ? self::$_espresso_notices['attention']
754
                : array(),
755
            'errors'    => isset(self::$_espresso_notices['errors'])
756
                ? self::$_espresso_notices['errors']
757
                : array(),
758
        );
759
    }
760
761
762
    /**
763
     * @return array
764
     * @throws InvalidArgumentException
765
     * @throws InvalidDataTypeException
766
     * @throws InvalidInterfaceException
767
     */
768
    public static function getStoredNotices()
769
    {
770
        if ($user_id = get_current_user_id()) {
771
            // get notices for logged in user
772
            $notices = get_user_option(EE_Error::OPTIONS_KEY_NOTICES, $user_id);
773
            return is_array($notices) ? $notices : array();
774
        }
775
        if (EE_Session::isLoadedAndActive()) {
776
            // get notices for user currently engaged in a session
777
            $session_data = EE_Session::instance()->get_session_data(EE_Error::OPTIONS_KEY_NOTICES);
778
            return is_array($session_data) ? $session_data : array();
779
        }
780
        // get global notices and hope they apply to the current site visitor
781
        $notices = get_option(EE_Error::OPTIONS_KEY_NOTICES, array());
782
        return is_array($notices) ? $notices : array();
783
    }
784
785
786
    /**
787
     * @param array $notices
788
     * @return bool
789
     * @throws InvalidArgumentException
790
     * @throws InvalidDataTypeException
791
     * @throws InvalidInterfaceException
792
     */
793
    public static function storeNotices(array $notices)
794
    {
795
        if ($user_id = get_current_user_id()) {
796
            // store notices for logged in user
797
            return (bool) update_user_option(
798
                $user_id,
799
                EE_Error::OPTIONS_KEY_NOTICES,
800
                $notices
801
            );
802
        }
803
        if (EE_Session::isLoadedAndActive()) {
804
            // store notices for user currently engaged in a session
805
            return EE_Session::instance()->set_session_data(
806
                array(EE_Error::OPTIONS_KEY_NOTICES => $notices)
807
            );
808
        }
809
        // store global notices and hope they apply to the same site visitor on the next request
810
        return update_option(EE_Error::OPTIONS_KEY_NOTICES, $notices);
811
    }
812
813
814
    /**
815
     * @return bool|TRUE
816
     * @throws InvalidArgumentException
817
     * @throws InvalidDataTypeException
818
     * @throws InvalidInterfaceException
819
     */
820
    public static function clearNotices()
821
    {
822
        if ($user_id = get_current_user_id()) {
823
            // clear notices for logged in user
824
            return (bool) update_user_option(
825
                $user_id,
826
                EE_Error::OPTIONS_KEY_NOTICES,
827
                array()
828
            );
829
        }
830
        if (EE_Session::isLoadedAndActive()) {
831
            // clear notices for user currently engaged in a session
832
            return EE_Session::instance()->reset_data(EE_Error::OPTIONS_KEY_NOTICES);
833
        }
834
        // clear global notices and hope none belonged to some for some other site visitor
835
        return update_option(EE_Error::OPTIONS_KEY_NOTICES, array());
836
    }
837
838
839
    /**
840
     * saves notices to the db for retrieval on next request
841
     *
842
     * @return void
843
     * @throws InvalidArgumentException
844
     * @throws InvalidDataTypeException
845
     * @throws InvalidInterfaceException
846
     */
847
    public static function stashNoticesBeforeRedirect()
848
    {
849
        EE_Error::get_notices(false, true);
850
    }
851
852
853
    /**
854
     * compile all error or success messages into one string
855
     *
856
     * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
857
     * @param boolean $format_output            whether or not to format the messages for display in the WP admin
858
     * @param boolean $save_to_transient        whether or not to save notices to the db for retrieval on next request
859
     *                                          - ONLY do this just before redirecting
860
     * @param boolean $remove_empty             whether or not to unset empty messages
861
     * @return array
862
     * @throws InvalidArgumentException
863
     * @throws InvalidDataTypeException
864
     * @throws InvalidInterfaceException
865
     */
866
    public static function get_notices($format_output = true, $save_to_transient = false, $remove_empty = true)
867
    {
868
        $success_messages   = '';
869
        $attention_messages = '';
870
        $error_messages     = '';
871
        // either save notices to the db
872
        if ($save_to_transient || isset($_REQUEST['activate-selected'])) {
873
            self::$_espresso_notices = array_merge(
874
                EE_Error::getStoredNotices(),
875
                self::$_espresso_notices
876
            );
877
            EE_Error::storeNotices(self::$_espresso_notices);
878
            return array();
879
        }
880
        $print_scripts = EE_Error::combineExistingAndNewNotices();
881
        // check for success messages
882 View Code Duplication
        if (self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])) {
883
            // combine messages
884
            $success_messages .= implode(self::$_espresso_notices['success'], '<br />');
885
            $print_scripts    = true;
886
        }
887
        // check for attention messages
888 View Code Duplication
        if (self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])) {
889
            // combine messages
890
            $attention_messages .= implode(self::$_espresso_notices['attention'], '<br />');
891
            $print_scripts      = true;
892
        }
893
        // check for error messages
894
        if (self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])) {
895
            $error_messages .= count(self::$_espresso_notices['errors']) > 1
896
                ? __('The following errors have occurred:<br />', 'event_espresso')
897
                : __('An error has occurred:<br />', 'event_espresso');
898
            // combine messages
899
            $error_messages .= implode(self::$_espresso_notices['errors'], '<br />');
900
            $print_scripts  = true;
901
        }
902
        if ($format_output) {
903
            $notices = EE_Error::formatNoticesOutput(
904
                $success_messages,
905
                $attention_messages,
906
                $error_messages
907
            );
908
        } else {
909
            $notices = array(
910
                'success'   => $success_messages,
911
                'attention' => $attention_messages,
912
                'errors'    => $error_messages,
913
            );
914
            if ($remove_empty) {
915
                // remove empty notices
916
                foreach ($notices as $type => $notice) {
917
                    if (empty($notice)) {
918
                        unset($notices[$type]);
919
                    }
920
                }
921
            }
922
        }
923
        if ($print_scripts) {
924
            self::_print_scripts();
925
        }
926
        return $notices;
927
    }
928
929
930
    /**
931
     * @return bool
932
     * @throws InvalidArgumentException
933
     * @throws InvalidDataTypeException
934
     * @throws InvalidInterfaceException
935
     */
936
    private static function combineExistingAndNewNotices()
937
    {
938
        $print_scripts = false;
939
        // grab any notices that have been previously saved
940
        $notices = EE_Error::getStoredNotices();
941
        if (! empty($notices)) {
942
            foreach ($notices as $type => $notice) {
943
                if (is_array($notice) && ! empty($notice)) {
944
                    // make sure that existing notice type is an array
945
                    self::$_espresso_notices[ $type ] = is_array(self::$_espresso_notices[ $type ])
946
                                                        && ! empty(self::$_espresso_notices[ $type ])
947
                        ? self::$_espresso_notices[ $type ]
948
                        : array();
949
                    // add newly created notices to existing ones
950
                    self::$_espresso_notices[ $type ] += $notice;
951
                    $print_scripts = true;
952
                }
953
            }
954
            // now clear any stored notices
955
            EE_Error::clearNotices();
956
        }
957
        return $print_scripts;
958
    }
959
960
961
    /**
962
     * @param string $success_messages
963
     * @param string $attention_messages
964
     * @param string $error_messages
965
     * @return string
966
     */
967
    private static function formatNoticesOutput($success_messages, $attention_messages, $error_messages)
968
    {
969
        $notices = '<div id="espresso-notices">';
970
        $close   = is_admin()
971
            ? ''
972
            : '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"/></a>';
973 View Code Duplication
        if ($success_messages !== '') {
974
            $css_id    = is_admin() ? 'message' : 'espresso-notices-success';
975
            $css_class = is_admin() ? 'updated fade' : 'success fade-away';
976
            //showMessage( $success_messages );
977
            $notices .= '<div id="' . $css_id . '" '
978
                        . 'class="espresso-notices ' . $css_class . '" '
979
                        . 'style="display:none;">'
980
                        . '<p>' . $success_messages . '</p>'
981
                        . $close
982
                        . '</div>';
983
        }
984 View Code Duplication
        if ($attention_messages !== '') {
985
            $css_id    = is_admin() ? 'message' : 'espresso-notices-attention';
986
            $css_class = is_admin() ? 'updated ee-notices-attention' : 'attention fade-away';
987
            //showMessage( $error_messages, TRUE );
988
            $notices .= '<div id="' . $css_id . '" '
989
                        . 'class="espresso-notices ' . $css_class . '" '
990
                        . 'style="display:none;">'
991
                        . '<p>' . $attention_messages . '</p>'
992
                        . $close
993
                        . '</div>';
994
        }
995 View Code Duplication
        if ($error_messages !== '') {
996
            $css_id    = is_admin() ? 'message' : 'espresso-notices-error';
997
            $css_class = is_admin() ? 'error' : 'error fade-away';
998
            //showMessage( $error_messages, TRUE );
999
            $notices .= '<div id="' . $css_id . '" '
1000
                        . 'class="espresso-notices ' . $css_class . '" '
1001
                        . 'style="display:none;">'
1002
                        . '<p>' . $error_messages . '</p>'
1003
                        . $close
1004
                        . '</div>';
1005
        }
1006
        $notices .= '</div>';
1007
        return $notices;
1008
    }
1009
1010
1011
1012
    /**
1013
     * _print_scripts
1014
     *
1015
     * @param    bool $force_print
1016
     * @return    string
1017
     */
1018 View Code Duplication
    private static function _print_scripts($force_print = false)
1019
    {
1020
        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
1021
            if (wp_script_is('ee_error_js', 'enqueued')) {
1022
                return '';
1023
            }
1024
            if (wp_script_is('ee_error_js', 'registered')) {
1025
                wp_enqueue_style('espresso_default');
1026
                wp_enqueue_style('espresso_custom_css');
1027
                wp_enqueue_script('ee_error_js');
1028
                wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
1029
            }
1030
        } else {
1031
            return '
1032
<script>
1033
/* <![CDATA[ */
1034
var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
1035
/* ]]> */
1036
</script>
1037
<script src="' . includes_url() . 'js/jquery/jquery.js" type="text/javascript"></script>
1038
<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
1039
<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
1040
';
1041
        }
1042
        return '';
1043
    }
1044
1045
1046
1047
    /**
1048
     * @return void
1049
     */
1050
    public static function enqueue_error_scripts()
1051
    {
1052
        self::_print_scripts();
1053
    }
1054
1055
1056
1057
    /**
1058
     * create error code from filepath, function name,
1059
     * and line number where exception or error was thrown
1060
     *
1061
     * @param string $file
1062
     * @param string $func
1063
     * @param string $line
1064
     * @return string
1065
     */
1066 View Code Duplication
    public static function generate_error_code($file = '', $func = '', $line = '')
1067
    {
1068
        $file       = explode('.', basename($file));
1069
        $error_code = ! empty($file[0]) ? $file[0] : '';
1070
        $error_code .= ! empty($func) ? ' - ' . $func : '';
1071
        $error_code .= ! empty($line) ? ' - ' . $line : '';
1072
        return $error_code;
1073
    }
1074
1075
1076
1077
    /**
1078
     * write exception details to log file
1079
     * Since 4.9.53.rc.006 this writes to the standard PHP log file, not EE's custom log file
1080
     *
1081
     * @param int   $time
1082
     * @param array $ex
1083
     * @param bool  $clear
1084
     * @return void
1085
     */
1086
    public function write_to_error_log($time = 0, $ex = array(), $clear = false)
1087
    {
1088
        if (empty($ex)) {
1089
            return;
1090
        }
1091
        if (! $time) {
1092
            $time = time();
1093
        }
1094
        $exception_log = '----------------------------------------------------------------------------------------'
1095
                         . PHP_EOL;
1096
        $exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
1097
        $exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
1098
        $exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
1099
        $exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
1100
        $exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
1101
        $exception_log .= 'Stack trace: ' . PHP_EOL;
1102
        $exception_log .= $ex['string'] . PHP_EOL;
1103
        $exception_log .= '----------------------------------------------------------------------------------------'
1104
                          . PHP_EOL;
1105
        try {
1106
            error_log($exception_log);
1107
        } catch (EE_Error $e) {
1108
            EE_Error::add_error(sprintf(__('Event Espresso error logging could not be setup because: %s',
1109
                'event_espresso'), $e->getMessage()));
1110
        }
1111
    }
1112
1113
1114
1115
    /**
1116
     * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1117
     * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1118
     * but the code execution is done in a manner that could lead to unexpected results
1119
     * (i.e. running to early, or too late in WP or EE loading process).
1120
     * A good test for knowing whether to use this method is:
1121
     * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1122
     * Yes -> use EE_Error::add_error() or throw new EE_Error()
1123
     * 2. If this is loaded before something else, it won't break anything,
1124
     * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1125
     *
1126
     * @uses   constant WP_DEBUG test if wp_debug is on or not
1127
     * @param string $function      The function that was called
1128
     * @param string $message       A message explaining what has been done incorrectly
1129
     * @param string $version       The version of Event Espresso where the error was added
1130
     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
1131
     *                              for a deprecated function. This allows deprecation to occur during one version,
1132
     *                              but not have any notices appear until a later version. This allows developers
1133
     *                              extra time to update their code before notices appear.
1134
     * @param int    $error_type
1135
     */
1136
    public static function doing_it_wrong(
1137
        $function,
1138
        $message,
1139
        $version,
1140
        $applies_when = '',
1141
        $error_type = null
1142
    ) {
1143
        if (defined('WP_DEBUG') && WP_DEBUG) {
1144
            EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1145
        }
1146
    }
1147
1148
1149
1150
    /**
1151
     * Like get_notices, but returns an array of all the notices of the given type.
1152
     *
1153
     * @return array {
1154
     *  @type array $success   all the success messages
1155
     *  @type array $errors    all the error messages
1156
     *  @type array $attention all the attention messages
1157
     * }
1158
     */
1159
    public static function get_raw_notices()
1160
    {
1161
        return self::$_espresso_notices;
1162
    }
1163
1164
1165
1166
    /**
1167
     * @deprecated 4.9.27
1168
     * @param string $pan_name     the name, or key of the Persistent Admin Notice to be stored
1169
     * @param string $pan_message  the message to be stored persistently until dismissed
1170
     * @param bool   $force_update allows one to enforce the reappearance of a persistent message.
1171
     * @return void
1172
     * @throws InvalidDataTypeException
1173
     */
1174
    public static function add_persistent_admin_notice($pan_name = '', $pan_message, $force_update = false)
1175
    {
1176
        new PersistentAdminNotice(
1177
            $pan_name,
1178
            $pan_message,
1179
            $force_update
1180
        );
1181
        EE_Error::doing_it_wrong(
1182
            __METHOD__,
1183
            sprintf(
1184
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1185
                '\EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
1186
            ),
1187
            '4.9.27'
1188
        );
1189
    }
1190
1191
1192
1193
    /**
1194
     * @deprecated 4.9.27
1195
     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
1196
     * @param bool   $purge
1197
     * @param bool   $return
1198
     * @throws DomainException
1199
     * @throws InvalidInterfaceException
1200
     * @throws InvalidDataTypeException
1201
     * @throws ServiceNotFoundException
1202
     * @throws InvalidArgumentException
1203
     */
1204
    public static function dismiss_persistent_admin_notice($pan_name = '', $purge = false, $return = false)
1205
    {
1206
        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
1207
        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
1208
            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1209
        );
1210
        $persistent_admin_notice_manager->dismissNotice($pan_name, $purge, $return);
1211
        EE_Error::doing_it_wrong(
1212
            __METHOD__,
1213
            sprintf(
1214
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1215
                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1216
            ),
1217
            '4.9.27'
1218
        );
1219
    }
1220
1221
1222
1223
    /**
1224
     * @deprecated 4.9.27
1225
     * @param  string $pan_name    the name, or key of the Persistent Admin Notice to be stored
1226
     * @param  string $pan_message the message to be stored persistently until dismissed
1227
     * @param  string $return_url  URL to go back to after nag notice is dismissed
1228
     */
1229
    public static function display_persistent_admin_notices($pan_name = '', $pan_message = '', $return_url = '')
1230
    {
1231
        EE_Error::doing_it_wrong(
1232
            __METHOD__,
1233
            sprintf(
1234
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1235
                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1236
            ),
1237
            '4.9.27'
1238
        );
1239
    }
1240
1241
1242
1243
    /**
1244
     * @deprecated 4.9.27
1245
     * @param string $return_url
1246
     */
1247
    public static function get_persistent_admin_notices($return_url = '')
1248
    {
1249
        EE_Error::doing_it_wrong(
1250
            __METHOD__,
1251
            sprintf(
1252
                __('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1253
                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1254
            ),
1255
            '4.9.27'
1256
        );
1257
    }
1258
1259
1260
1261
}
1262
// end of Class EE_Exceptions
1263
1264
1265
/**
1266
 * espresso_error_enqueue_scripts
1267
 *
1268
 * @return    void
1269
 */
1270
function espresso_error_enqueue_scripts()
1271
{
1272
    // js for error handling
1273
    wp_register_script(
1274
        'espresso_core',
1275
        EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1276
        array('jquery'),
1277
        EVENT_ESPRESSO_VERSION,
1278
        false
1279
    );
1280
    wp_register_script(
1281
        'ee_error_js',
1282
        EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1283
        array('espresso_core'),
1284
        EVENT_ESPRESSO_VERSION,
1285
        false
1286
    );
1287
}
1288
1289
if (is_admin()) {
1290
    add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1291
} else {
1292
    add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1293
}
1294
1295
1296
1297
1298
1299
/* End of file EE_Exceptions.class.php */
1300
/* Location: includes/classes/EE_Exceptions.class.php */
1301