1 <?php
2 /**
3 * @package Joomla.Legacy
4 * @subpackage Error
5 *
6 * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE.txt
8 */
9
10 defined('JPATH_PLATFORM') or die;
11
12 /**
13 * Error Definition: Illegal Options
14 *
15 * @var integer
16 * @since 1.5
17 * @deprecated 1.7
18 */
19 const JERROR_ILLEGAL_OPTIONS = 1;
20
21 /**
22 * Error Definition: Callback does not exist
23 *
24 * @var integer
25 * @since 1.5
26 * @deprecated 1.7
27 */
28 const JERROR_CALLBACK_NOT_CALLABLE = 2;
29
30 /**
31 * Error Definition: Illegal Handler
32 *
33 * @var integer
34 * @since 1.5
35 * @deprecated 1.7
36 */
37 const JERROR_ILLEGAL_MODE = 3;
38
39 /**
40 * Error Handling Class
41 *
42 * This class is inspired in design and concept by patErrorManager <http://www.php-tools.net>
43 *
44 * patErrorManager contributors include:
45 * - gERD Schaufelberger <gerd@php-tools.net>
46 * - Sebastian Mordziol <argh@php-tools.net>
47 * - Stephan Schmidt <scst@php-tools.net>
48 *
49 * @since 1.5
50 * @deprecated 1.7
51 */
52 abstract class JError
53 {
54 /**
55 * Legacy error handling marker
56 *
57 * @var boolean True to enable legacy error handling using JError, false to use exception handling. This flag
58 * is present to allow an easy transition into exception handling for code written against the
59 * existing JError API in Joomla.
60 * @since 1.7
61 * @deprecated 1.7
62 */
63 public static $legacy = false;
64
65 /**
66 * Array of message levels
67 *
68 * @var array
69 * @since 1.6
70 * @deprecated 1.7
71 */
72 protected static $levels = array(E_NOTICE => 'Notice', E_WARNING => 'Warning', E_ERROR => 'Error');
73
74 /**
75 * Array of message handlers
76 *
77 * @var array
78 * @since 1.6
79 * @deprecated 1.7
80 */
81 protected static $handlers = array(
82 E_NOTICE => array('mode' => 'ignore'),
83 E_WARNING => array('mode' => 'ignore'),
84 E_ERROR => array('mode' => 'ignore'),
85 );
86
87 /**
88 * Array containing the error stack
89 *
90 * @var JException[]
91 * @since 1.6
92 * @deprecated 1.7
93 */
94 protected static $stack = array();
95
96 /**
97 * Method to determine if a value is an exception object.
98 *
99 * @param mixed $object Object to check.
100 *
101 * @return boolean True if argument is an exception, false otherwise.
102 *
103 * @since 1.5
104 * @deprecated 1.7
105 */
106 public static function isError($object)
107 {
108 JLog::add('JError::isError() is deprecated.', JLog::WARNING, 'deprecated');
109
110 return $object instanceof Exception;
111 }
112
113 /**
114 * Method for retrieving the last exception object in the error stack
115 *
116 * @param boolean $unset True to remove the error from the stack.
117 *
118 * @return JException|boolean Last JException object in the error stack or boolean false if none exist
119 *
120 * @since 1.5
121 * @deprecated 1.7
122 */
123 public static function getError($unset = false)
124 {
125 JLog::add('JError::getError() is deprecated.', JLog::WARNING, 'deprecated');
126
127 if (!isset(self::$stack[0]))
128 {
129 return false;
130 }
131
132 if ($unset)
133 {
134 $error = array_shift(self::$stack);
135 }
136 else
137 {
138 $error = &self::$stack[0];
139 }
140
141 return $error;
142 }
143
144 /**
145 * Method for retrieving the exception stack
146 *
147 * @return JException[] Chronological array of errors that have been stored during script execution
148 *
149 * @since 1.5
150 * @deprecated 1.7
151 */
152 public static function getErrors()
153 {
154 JLog::add('JError::getErrors() is deprecated.', JLog::WARNING, 'deprecated');
155
156 return self::$stack;
157 }
158
159 /**
160 * Method to add non-JError thrown JExceptions to the JError stack for debugging purposes
161 *
162 * @param JException &$e Add an exception to the stack.
163 *
164 * @return void
165 *
166 * @since 1.6
167 * @deprecated 1.7
168 */
169 public static function addToStack(JException &$e)
170 {
171 JLog::add('JError::addToStack() is deprecated.', JLog::WARNING, 'deprecated');
172
173 self::$stack[] = &$e;
174 }
175
176 /**
177 * Create a new JException object given the passed arguments
178 *
179 * @param integer $level The error level - use any of PHP's own error levels for
180 * this: E_ERROR, E_WARNING, E_NOTICE, E_USER_ERROR,
181 * E_USER_WARNING, E_USER_NOTICE.
182 * @param string $code The application-internal error code for this error
183 * @param string $msg The error message, which may also be shown the user if need be.
184 * @param mixed $info Optional: Additional error information (usually only
185 * developer-relevant information that the user should never see,
186 * like a database DSN).
187 * @param boolean $backtrace Add a stack backtrace to the exception.
188 *
189 * @return JException
190 *
191 * @since 1.5
192 * @deprecated 1.7
193 * @see JException
194 */
195 public static function raise($level, $code, $msg, $info = null, $backtrace = false)
196 {
197 JLog::add('JError::raise() is deprecated.', JLog::WARNING, 'deprecated');
198
199 // Build error object
200 $exception = new JException($msg, $code, $level, $info, $backtrace);
201
202 return self::throwError($exception);
203 }
204
205 /**
206 * Throw an error
207 *
208 * @param JException &$exception An exception to throw.
209 *
210 * @return JException A reference to the handled JException object
211 *
212 * @since 1.6
213 * @deprecated 1.7
214 * @see JException
215 */
216 public static function throwError(&$exception)
217 {
218 JLog::add('JError::throwError() is deprecated.', JLog::WARNING, 'deprecated');
219
220 static $thrown = false;
221
222 // If thrown is hit again, we've come back to JError in the middle of throwing another JError, so die!
223 if ($thrown)
224 {
225 self::handleEcho($exception, array());
226
227 // Inifite loop.
228 jexit();
229 }
230
231 $thrown = true;
232 $level = $exception->get('level');
233
234 // See what to do with this kind of error
235 $handler = self::getErrorHandling($level);
236
237 $function = 'handle' . ucfirst($handler['mode']);
238
239 if (is_callable(array('JError', $function)))
240 {
241 $reference = call_user_func_array(array('JError', $function), array(&$exception, isset($handler['options']) ? $handler['options'] : array()));
242 }
243 else
244 {
245 // This is required to prevent a very unhelpful white-screen-of-death
246 jexit(
247 'JError::raise -> Static method JError::' . $function . ' does not exist. Contact a developer to debug' .
248 '<br /><strong>Error was</strong> <br />' . $exception->getMessage()
249 );
250 }
251 // We don't need to store the error, since JException already does that for us!
252 // Remove loop check
253 $thrown = false;
254
255 return $reference;
256 }
257
258 /**
259 * Wrapper method for the raise() method with predefined error level of E_ERROR and backtrace set to true.
260 *
261 * @param string $code The application-internal error code for this error
262 * @param string $msg The error message, which may also be shown the user if need be.
263 * @param mixed $info Optional: Additional error information (usually only
264 * developer-relevant information that the user should
265 * never see, like a database DSN).
266 *
267 * @return JException $error The thrown JException object
268 *
269 * @since 1.5
270 * @deprecated 1.7
271 * @see JError::raise()
272 */
273 public static function raiseError($code, $msg, $info = null)
274 {
275 JLog::add('JError::raiseError() is deprecated.', JLog::WARNING, 'deprecated');
276
277 return self::raise(E_ERROR, $code, $msg, $info, true);
278 }
279
280 /**
281 * Wrapper method for the {@link raise()} method with predefined error level of E_WARNING and backtrace set to false.
282 *
283 * @param string $code The application-internal error code for this error
284 * @param string $msg The error message, which may also be shown the user if need be.
285 * @param mixed $info Optional: Additional error information (usually only
286 * developer-relevant information that
287 * the user should never see, like a database DSN).
288 *
289 * @return JException $error The thrown JException object
290 *
291 * @since 1.5
292 * @deprecated 1.7
293 * @see JError::raise()
294 */
295 public static function raiseWarning($code, $msg, $info = null)
296 {
297 JLog::add('JError::raiseWarning() is deprecated.', JLog::WARNING, 'deprecated');
298
299 return self::raise(E_WARNING, $code, $msg, $info);
300 }
301
302 /**
303 * Wrapper method for the {@link raise()} method with predefined error level of E_NOTICE and backtrace set to false.
304 *
305 * @param string $code The application-internal error code for this error
306 * @param string $msg The error message, which may also be shown the user if need be.
307 * @param mixed $info Optional: Additional error information (usually only
308 * developer-relevant information that the user
309 * should never see, like a database DSN).
310 *
311 * @return JException $error The thrown JException object
312 *
313 * @since 1.5
314 * @deprecated 1.7
315 * @see JError::raise()
316 */
317 public static function raiseNotice($code, $msg, $info = null)
318 {
319 JLog::add('JError::raiseNotice() is deprecated.', JLog::WARNING, 'deprecated');
320
321 return self::raise(E_NOTICE, $code, $msg, $info);
322 }
323
324 /**
325 * Method to get the current error handler settings for a specified error level.
326 *
327 * @param integer $level The error level to retrieve. This can be any of PHP's
328 * own error levels, e.g. E_ALL, E_NOTICE...
329 *
330 * @return array All error handling details
331 *
332 * @since 1.5
333 * @deprecated 1.7
334 */
335 public static function getErrorHandling($level)
336 {
337 JLog::add('JError::getErrorHandling() is deprecated.', JLog::WARNING, 'deprecated');
338
339 return self::$handlers[$level];
340 }
341
342 /**
343 * Method to set the way the JError will handle different error levels. Use this if you want to override the default settings.
344 *
345 * Error handling modes:
346 * - ignore
347 * - echo
348 * - verbose
349 * - die
350 * - message
351 * - log
352 * - callback
353 *
354 * You may also set the error handling for several modes at once using PHP's bit operations.
355 * Examples:
356 * - E_ALL = Set the handling for all levels
357 * - E_ERROR | E_WARNING = Set the handling for errors and warnings
358 * - E_ALL ^ E_ERROR = Set the handling for all levels except errors
359 *
360 * @param integer $level The error level for which to set the error handling
361 * @param string $mode The mode to use for the error handling.
362 * @param mixed $options Optional: Any options needed for the given mode.
363 *
364 * @return boolean|JException True on success or a JException object if failed.
365 *
366 * @since 1.5
367 * @deprecated 1.7
368 */
369 public static function setErrorHandling($level, $mode, $options = null)
370 {
371 JLog::add('JError::setErrorHandling() is deprecated.', JLog::WARNING, 'deprecated');
372
373 $levels = self::$levels;
374
375 $function = 'handle' . ucfirst($mode);
376
377 if (!is_callable(array('JError', $function)))
378 {
379 return self::raiseError(E_ERROR, 'JError:' . JERROR_ILLEGAL_MODE, 'Error Handling mode is not known', 'Mode: ' . $mode . ' is not implemented.');
380 }
381
382 foreach ($levels as $eLevel => $eTitle)
383 {
384 if (($level & $eLevel) != $eLevel)
385 {
386 continue;
387 }
388
389 // Set callback options
390 if ($mode == 'callback')
391 {
392 if (!is_array($options))
393 {
394 return self::raiseError(E_ERROR, 'JError:' . JERROR_ILLEGAL_OPTIONS, 'Options for callback not valid');
395 }
396
397 if (!is_callable($options))
398 {
399 $tmp = array('GLOBAL');
400
401 if (is_array($options))
402 {
403 $tmp[0] = $options[0];
404 $tmp[1] = $options[1];
405 }
406 else
407 {
408 $tmp[1] = $options;
409 }
410
411 return self::raiseError(
412 E_ERROR,
413 'JError:' . JERROR_CALLBACK_NOT_CALLABLE,
414 'Function is not callable',
415 'Function:' . $tmp[1] . ' scope ' . $tmp[0] . '.'
416 );
417 }
418 }
419
420 // Save settings
421 self::$handlers[$eLevel] = array('mode' => $mode);
422
423 if ($options != null)
424 {
425 self::$handlers[$eLevel]['options'] = $options;
426 }
427 }
428
429 return true;
430 }
431
432 /**
433 * Method that attaches the error handler to JError
434 *
435 * @return void
436 *
437 * @since 1.5
438 * @deprecated 1.7
439 * @see set_error_handler
440 */
441 public static function attachHandler()
442 {
443 JLog::add('JError::getErrorHandling() is deprecated.', JLog::WARNING, 'deprecated');
444
445 set_error_handler(array('JError', 'customErrorHandler'));
446 }
447
448 /**
449 * Method that detaches the error handler from JError
450 *
451 * @return void
452 *
453 * @since 1.5
454 * @deprecated 1.7
455 * @see restore_error_handler
456 */
457 public static function detachHandler()
458 {
459 JLog::add('JError::detachHandler() is deprecated.', JLog::WARNING, 'deprecated');
460
461 restore_error_handler();
462 }
463
464 /**
465 * Method to register a new error level for handling errors
466 *
467 * This allows you to add custom error levels to the built-in
468 * - E_NOTICE
469 * - E_WARNING
470 * - E_NOTICE
471 *
472 * @param integer $level Error level to register
473 * @param string $name Human readable name for the error level
474 * @param string $handler Error handler to set for the new error level [optional]
475 *
476 * @return boolean True on success; false if the level already has been registered
477 *
478 * @since 1.5
479 * @deprecated 1.7
480 */
481 public static function registerErrorLevel($level, $name, $handler = 'ignore')
482 {
483 JLog::add('JError::registerErrorLevel() is deprecated.', JLog::WARNING, 'deprecated');
484
485 if (isset(self::$levels[$level]))
486 {
487 return false;
488 }
489
490 self::$levels[$level] = $name;
491 self::setErrorHandling($level, $handler);
492
493 return true;
494 }
495
496 /**
497 * Translate an error level integer to a human readable string
498 * e.g. E_ERROR will be translated to 'Error'
499 *
500 * @param integer $level Error level to translate
501 *
502 * @return string|boolean Human readable error level name or boolean false if it doesn't exist
503 *
504 * @since 1.5
505 * @deprecated 1.7
506 */
507 public static function translateErrorLevel($level)
508 {
509 JLog::add('JError::translateErrorLevel() is deprecated.', JLog::WARNING, 'deprecated');
510
511 if (isset(self::$levels[$level]))
512 {
513 return self::$levels[$level];
514 }
515
516 return false;
517 }
518
519 /**
520 * Ignore error handler
521 * - Ignores the error
522 *
523 * @param JException &$error Exception object to handle
524 * @param array $options Handler options
525 *
526 * @return JException The exception object
527 *
528 * @since 1.5
529 * @deprecated 1.7
530 * @see JError::raise()
531 */
532 public static function handleIgnore(&$error, $options)
533 {
534 JLog::add('JError::handleIgnore() is deprecated.', JLog::WARNING, 'deprecated');
535
536 return $error;
537 }
538
539 /**
540 * Echo error handler
541 * - Echos the error message to output
542 *
543 * @param JException &$error Exception object to handle
544 * @param array $options Handler options
545 *
546 * @return JException The exception object
547 *
548 * @since 1.5
549 * @deprecated 1.7
550 * @see JError::raise()
551 */
552 public static function handleEcho(&$error, $options)
553 {
554 JLog::add('JError::handleEcho() is deprecated.', JLog::WARNING, 'deprecated');
555
556 $level_human = self::translateErrorLevel($error->get('level'));
557
558 // If system debug is set, then output some more information.
559 if (JDEBUG)
560 {
561 $backtrace = $error->getTrace();
562 $trace = '';
563
564 for ($i = count($backtrace) - 1; $i >= 0; $i--)
565 {
566 if (isset($backtrace[$i]['class']))
567 {
568 $trace .= sprintf("\n%s %s %s()", $backtrace[$i]['class'], $backtrace[$i]['type'], $backtrace[$i]['function']);
569 }
570 else
571 {
572 $trace .= sprintf("\n%s()", $backtrace[$i]['function']);
573 }
574
575 if (isset($backtrace[$i]['file']))
576 {
577 $trace .= sprintf(' @ %s:%d', $backtrace[$i]['file'], $backtrace[$i]['line']);
578 }
579 }
580 }
581
582 if (isset($_SERVER['HTTP_HOST']))
583 {
584 // Output as html
585 echo "<br /><b>jos-$level_human</b>: "
586 . $error->get('message') . "<br />\n"
587 . (JDEBUG ? nl2br($trace) : '');
588 }
589 else
590 {
591 // Output as simple text
592 if (defined('STDERR'))
593 {
594 fwrite(STDERR, "J$level_human: " . $error->get('message') . "\n");
595
596 if (JDEBUG)
597 {
598 fwrite(STDERR, $trace);
599 }
600 }
601 else
602 {
603 echo "J$level_human: " . $error->get('message') . "\n";
604
605 if (JDEBUG)
606 {
607 echo $trace;
608 }
609 }
610 }
611
612 return $error;
613 }
614
615 /**
616 * Verbose error handler
617 * - Echos the error message to output as well as related info
618 *
619 * @param JException &$error Exception object to handle
620 * @param array $options Handler options
621 *
622 * @return JException The exception object
623 *
624 * @since 1.5
625 * @deprecated 1.7
626 * @see JError::raise()
627 */
628 public static function handleVerbose(&$error, $options)
629 {
630 JLog::add('JError::handleVerbose() is deprecated.', JLog::WARNING, 'deprecated');
631
632 $level_human = self::translateErrorLevel($error->get('level'));
633 $info = $error->get('info');
634
635 if (isset($_SERVER['HTTP_HOST']))
636 {
637 // Output as html
638 echo "<br /><b>J$level_human</b>: " . $error->get('message') . "<br />\n";
639
640 if ($info != null)
641 {
642 echo '   ' . $info . "<br />\n";
643 }
644
645 echo $error->getBacktrace(true);
646 }
647 else
648 {
649 // Output as simple text
650 echo "J$level_human: " . $error->get('message') . "\n";
651
652 if ($info != null)
653 {
654 echo "\t" . $info . "\n";
655 }
656 }
657
658 return $error;
659 }
660
661 /**
662 * Die error handler
663 * - Echos the error message to output and then dies
664 *
665 * @param JException &$error Exception object to handle
666 * @param array $options Handler options
667 *
668 * @return void Calls die()
669 *
670 * @since 1.5
671 * @deprecated 1.7
672 * @see JError::raise()
673 */
674 public static function handleDie(&$error, $options)
675 {
676 JLog::add('JError::handleDie() is deprecated.', JLog::WARNING, 'deprecated');
677
678 $level_human = self::translateErrorLevel($error->get('level'));
679
680 if (isset($_SERVER['HTTP_HOST']))
681 {
682 // Output as html
683 jexit("<br /><b>J$level_human</b>: " . $error->get('message') . "<br />\n");
684 }
685 else
686 {
687 // Output as simple text
688 if (defined('STDERR'))
689 {
690 fwrite(STDERR, "J$level_human: " . $error->get('message') . "\n");
691 jexit();
692 }
693 else
694 {
695 jexit("J$level_human: " . $error->get('message') . "\n");
696 }
697 }
698
699 return $error;
700 }
701
702 /**
703 * Message error handler
704 * Enqueues the error message into the system queue
705 *
706 * @param JException &$error Exception object to handle
707 * @param array $options Handler options
708 *
709 * @return JException The exception object
710 *
711 * @since 1.5
712 * @deprecated 1.7
713 * @see JError::raise()
714 */
715 public static function handleMessage(&$error, $options)
716 {
717 JLog::add('JError::hanleMessage() is deprecated.', JLog::WARNING, 'deprecated');
718
719 $appl = JFactory::getApplication();
720 $type = ($error->get('level') == E_NOTICE) ? 'notice' : 'error';
721 $appl->enqueueMessage($error->get('message'), $type);
722
723 return $error;
724 }
725
726 /**
727 * Log error handler
728 * Logs the error message to a system log file
729 *
730 * @param JException &$error Exception object to handle
731 * @param array $options Handler options
732 *
733 * @return JException The exception object
734 *
735 * @since 1.5
736 * @deprecated 1.7
737 * @see JError::raise()
738 */
739 public static function handleLog(&$error, $options)
740 {
741 JLog::add('JError::handleLog() is deprecated.', JLog::WARNING, 'deprecated');
742
743 static $log;
744
745 if ($log == null)
746 {
747 $options['text_file'] = date('Y-m-d') . '.error.log';
748 $options['format'] = "{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}";
749 JLog::addLogger($options, JLog::ALL, array('error'));
750 }
751
752 $entry = new JLogEntry(
753 str_replace(array("\r", "\n"), array('', '\\n'), $error->get('message')),
754 $error->get('level'),
755 'error'
756 );
757 $entry->code = $error->get('code');
758 JLog::add($entry);
759
760 return $error;
761 }
762
763 /**
764 * Callback error handler
765 * - Send the error object to a callback method for error handling
766 *
767 * @param JException &$error Exception object to handle
768 * @param array $options Handler options
769 *
770 * @return JException The exception object
771 *
772 * @since 1.5
773 * @deprecated 1.7
774 * @see JError::raise()
775 */
776 public static function handleCallback(&$error, $options)
777 {
778 JLog::add('JError::handleCallback() is deprecated.', JLog::WARNING, 'deprecated');
779
780 return call_user_func($options, $error);
781 }
782
783 /**
784 * Display a custom error page and exit gracefully
785 *
786 * @param JException $error Exception object
787 *
788 * @return void
789 *
790 * @since 1.5
791 * @deprecated 1.7
792 */
793 public static function customErrorPage($error)
794 {
795 JLog::add('JError::customErrorPage() is deprecated, use JErrorPage::render() instead.', JLog::WARNING, 'deprecated');
796
797 JErrorPage::render($error);
798 }
799
800 /**
801 * Display a message to the user
802 *
803 * @param integer $level The error level - use any of PHP's own error levels
804 * for this: E_ERROR, E_WARNING, E_NOTICE, E_USER_ERROR,
805 * E_USER_WARNING, E_USER_NOTICE.
806 * @param string $msg Error message, shown to user if need be.
807 *
808 * @return void
809 *
810 * @since 1.5
811 * @deprecated 1.7
812 */
813 public static function customErrorHandler($level, $msg)
814 {
815 JLog::add('JError::customErrorHandler() is deprecated.', JLog::WARNING, 'deprecated');
816
817 self::raise($level, '', $msg);
818 }
819
820 /**
821 * Render the backtrace
822 *
823 * @param Exception $error The error
824 *
825 * @return string Contents of the backtrace
826 *
827 * @since 1.6
828 * @deprecated 1.7
829 */
830 public static function renderBacktrace($error)
831 {
832 JLog::add('JError::renderBacktrace() is deprecated.', JLog::WARNING, 'deprecated');
833
834 return JLayoutHelper::render('joomla.error.backtrace', array('backtrace' => $error->getTrace()));
835 }
836 }
837