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