PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/error/error.php

https://github.com/joebushi/joomla
PHP | 640 lines | 305 code | 52 blank | 283 comment | 40 complexity | a5573fa2f3479dfdaa2b4f20b7da4b2c MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @version $Id$
  4. * @package Joomla.Framework
  5. * @subpackage Error
  6. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. // No direct access
  10. defined('JPATH_BASE') or die;
  11. // Error Definition: Illegal Options
  12. define('JERROR_ILLEGAL_OPTIONS', 1);
  13. // Error Definition: Callback does not exist
  14. define('JERROR_CALLBACK_NOT_CALLABLE', 2);
  15. // Error Definition: Illegal Handler
  16. define('JERROR_ILLEGAL_MODE', 3);
  17. /**
  18. * Error Handling Class
  19. *
  20. * This class is inspired in design and concept by patErrorManager <http://www.php-tools.net>
  21. *
  22. * patErrorManager contributors include:
  23. * - gERD Schaufelberger <gerd@php-tools.net>
  24. * - Sebastian Mordziol <argh@php-tools.net>
  25. * - Stephan Schmidt <scst@php-tools.net>
  26. *
  27. * @static
  28. * @package Joomla.Framework
  29. * @subpackage Error
  30. * @since 1.5
  31. */
  32. abstract class JError
  33. {
  34. protected static $levels = array(
  35. E_NOTICE => 'Notice',
  36. E_WARNING => 'Warning',
  37. E_ERROR => 'Error'
  38. );
  39. protected static $handlers = array(
  40. E_NOTICE => array('mode' => 'message'),
  41. E_WARNING => array('mode' => 'message'),
  42. E_ERROR => array('mode' => 'callback', 'options' => array('JError','customErrorPage'))
  43. );
  44. protected static $stack = array();
  45. /**
  46. * Method to determine if a value is an exception object. This check supports both JException and PHP5 Exception objects
  47. *
  48. * @static
  49. * @access public
  50. * @param mixed &$object Object to check
  51. * @return boolean True if argument is an exception, false otherwise.
  52. * @since 1.5
  53. w
  54. */
  55. public static function isError(& $object)
  56. {
  57. if (!is_object($object)) {
  58. return false;
  59. }
  60. // supports PHP 5 exception handling
  61. return $object INSTANCEOF Exception;
  62. }
  63. /**
  64. * Method for retrieving the last exception object in the error stack
  65. *
  66. * @static
  67. * @access public
  68. * @return mixed Last exception object in the error stack or boolean false if none exist
  69. * @since 1.5
  70. */
  71. public static function getError($unset = false)
  72. {
  73. if (!isset(JError::$stack[0])) {
  74. return false;
  75. }
  76. if ($unset) {
  77. $error = array_shift(JError::$stack[0]);
  78. }
  79. else {
  80. $error = &JError::$stack[0];
  81. }
  82. return $error;
  83. }
  84. /**
  85. * Method for retrieving the exception stack
  86. *
  87. * @static
  88. * @access public
  89. * @return array Chronological array of errors that have been stored during script execution
  90. * @since 1.5
  91. */
  92. public static function getErrors()
  93. {
  94. return JError::$stack;
  95. }
  96. /**
  97. * Method to add non-JError thrown JExceptions to the JError stack for debugging purposes
  98. *
  99. * @access public
  100. * @param object JException
  101. * @return void
  102. * @since 1.6
  103. */
  104. public static function addToStack(JException &$e) {
  105. JError::$stack[0][] = &$e;
  106. }
  107. /**
  108. * Create a new JException object given the passed arguments
  109. *
  110. * @static
  111. * @param int $level The error level - use any of PHP's own error levels for this: E_ERROR, E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE.
  112. * @param string $code The application-internal error code for this error
  113. * @param string $msg The error message, which may also be shown the user if need be.
  114. * @param mixed $info Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
  115. * @return mixed The JException object
  116. * @since 1.5
  117. *
  118. * @see JException
  119. */
  120. public static function raise($level, $code, $msg, $info = null, $backtrace = false)
  121. {
  122. jimport('joomla.error.exception');
  123. // build error object
  124. $exception = new JException($msg, $code, $level, $info, $backtrace);
  125. return JError::throwError($exception);
  126. }
  127. public static function throwError(&$exception)
  128. {
  129. static $thrown = false;
  130. // If thrown is hit again, we've come back to JError in the middle of throwing another JError, so die!
  131. if ($thrown)
  132. {
  133. //echo debug_print_backtrace();
  134. jexit('Infinite loop detected in JError');
  135. }
  136. $thrown = true;
  137. $level = $exception->get('level');
  138. // see what to do with this kind of error
  139. $handler = JError::getErrorHandling($level);
  140. $function = 'handle'.ucfirst($handler['mode']);
  141. if (is_callable(array('JError', $function))) {
  142. $reference = &call_user_func_array(array('JError',$function), array(&$exception, (isset($handler['options'])) ? $handler['options'] : array()));
  143. }
  144. else {
  145. // This is required to prevent a very unhelpful white-screen-of-death
  146. jexit(
  147. 'JError::raise -> Static method JError::' . $function . ' does not exist.' .
  148. ' Contact a developer to debug' .
  149. '<br /><strong>Error was</strong> ' .
  150. '<br />' . $exception->getMessage()
  151. );
  152. }
  153. //we don't need to store the error, since JException already does that for us!
  154. //remove loop check
  155. $thrown = false;
  156. return $reference;
  157. }
  158. /**
  159. * Wrapper method for the {@link raise()} method with predefined error level of E_ERROR and backtrace set to true.
  160. *
  161. * @static
  162. * @param string $code The application-internal error code for this error
  163. * @param string $msg The error message, which may also be shown the user if need be.
  164. * @param mixed $info Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
  165. * @return object $error The configured JError object
  166. * @since 1.5
  167. */
  168. public static function raiseError($code, $msg, $info = null)
  169. {
  170. return JError::raise(E_ERROR, $code, $msg, $info, true);
  171. }
  172. /**
  173. * Wrapper method for the {@link raise()} method with predefined error level of E_WARNING and backtrace set to false.
  174. *
  175. * @static
  176. * @param string $code The application-internal error code for this error
  177. * @param string $msg The error message, which may also be shown the user if need be.
  178. * @param mixed $info Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
  179. * @return object $error The configured JError object
  180. * @since 1.5
  181. */
  182. public static function raiseWarning($code, $msg, $info = null)
  183. {
  184. return JError::raise(E_WARNING, $code, $msg, $info);
  185. }
  186. /**
  187. * Wrapper method for the {@link raise()} method with predefined error level of E_NOTICE and backtrace set to false.
  188. *
  189. * @static
  190. * @param string $code The application-internal error code for this error
  191. * @param string $msg The error message, which may also be shown the user if need be.
  192. * @param mixed $info Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
  193. * @return object $error The configured JError object
  194. * @since 1.5
  195. */
  196. public static function raiseNotice($code, $msg, $info = null)
  197. {
  198. return JError::raise(E_NOTICE, $code, $msg, $info);
  199. }
  200. /**
  201. * Method to get the current error handler settings for a specified error level.
  202. *
  203. * @static
  204. * @param int $level The error level to retrieve. This can be any of PHP's own error levels, e.g. E_ALL, E_NOTICE...
  205. * @return array All error handling details
  206. * @since 1.5
  207. */
  208. public static function getErrorHandling($level)
  209. {
  210. return JError::$handlers[$level];
  211. }
  212. /**
  213. * Method to set the way the JError will handle different error levels. Use this if you want to override the default settings.
  214. *
  215. * Error handling modes:
  216. * - ignore
  217. * - echo
  218. * - verbose
  219. * - die
  220. * - message
  221. * - log
  222. * - callback
  223. *
  224. * You may also set the error handling for several modes at once using PHP's bit operations.
  225. * Examples:
  226. * - E_ALL = Set the handling for all levels
  227. * - E_ERROR | E_WARNING = Set the handling for errors and warnings
  228. * - E_ALL ^ E_ERROR = Set the handling for all levels except errors
  229. *
  230. * @static
  231. * @param int $level The error level for which to set the error handling
  232. * @param string $mode The mode to use for the error handling.
  233. * @param mixed $options Optional: Any options needed for the given mode.
  234. * @return mixed True on success, or a JException object if failed.
  235. * @since 1.5
  236. */
  237. public static function setErrorHandling($level, $mode, $options = null)
  238. {
  239. $levels = JError::$levels;
  240. $function = 'handle'.ucfirst($mode);
  241. if (!is_callable(array ('JError',$function))) {
  242. return JError::raiseError(E_ERROR, 'JError:'.JERROR_ILLEGAL_MODE, 'Error Handling mode is not known', 'Mode: '.$mode.' is not implemented.');
  243. }
  244. foreach ($levels as $eLevel => $eTitle)
  245. {
  246. if (($level & $eLevel) != $eLevel) {
  247. continue;
  248. }
  249. // set callback options
  250. if ($mode == 'callback')
  251. {
  252. if (!is_array($options)) {
  253. return JError::raiseError(E_ERROR, 'JError:'.JERROR_ILLEGAL_OPTIONS, 'Options for callback not valid');
  254. }
  255. if (!is_callable($options))
  256. {
  257. $tmp = array ('GLOBAL');
  258. if (is_array($options)) {
  259. $tmp[0] = $options[0];
  260. $tmp[1] = $options[1];
  261. }
  262. else {
  263. $tmp[1] = $options;
  264. }
  265. return JError::raiseError(E_ERROR, 'JError:'.JERROR_CALLBACK_NOT_CALLABLE, 'Function is not callable', 'Function:'.$tmp[1].' scope '.$tmp[0].'.');
  266. }
  267. }
  268. // save settings
  269. JError::$handlers[$eLevel] = array ('mode' => $mode);
  270. if ($options != null) {
  271. JError::$handlers[$eLevel]['options'] = $options;
  272. }
  273. }
  274. return true;
  275. }
  276. /**
  277. * Method that attaches the error handler to JError
  278. *
  279. * @access public
  280. * @see set_error_handler
  281. */
  282. public static function attachHandler()
  283. {
  284. set_error_handler(array('JError', 'customErrorHandler'));
  285. }
  286. /**
  287. * Method that dettaches the error handler from JError
  288. *
  289. * @access public
  290. * @see restore_error_handler
  291. */
  292. public static function detachHandler()
  293. {
  294. restore_error_handler();
  295. }
  296. /**
  297. * Method to register a new error level for handling errors
  298. *
  299. * This allows you to add custom error levels to the built-in
  300. * - E_NOTICE
  301. * - E_WARNING
  302. * - E_NOTICE
  303. *
  304. * @static
  305. * @param int $level Error level to register
  306. * @param string $name Human readable name for the error level
  307. * @param string $handler Error handler to set for the new error level [optional]
  308. * @return boolean True on success; false if the level already has been registered
  309. * @since 1.5
  310. */
  311. public static function registerErrorLevel($level, $name, $handler = 'ignore')
  312. {
  313. if (isset(JError::$levels[$level])) {
  314. return false;
  315. }
  316. JError::$levels[$level] = $name;
  317. JError::setErrorHandling($level, $handler);
  318. return true;
  319. }
  320. /**
  321. * Translate an error level integer to a human readable string
  322. * e.g. E_ERROR will be translated to 'Error'
  323. *
  324. * @static
  325. * @param int $level Error level to translate
  326. * @return mixed Human readable error level name or boolean false if it doesn't exist
  327. * @since 1.5
  328. */
  329. public static function translateErrorLevel($level)
  330. {
  331. if (isset(JError::$levels[$level])) {
  332. return JError::$levels[$level];
  333. }
  334. return false;
  335. }
  336. /**
  337. * Ignore error handler
  338. * - Ignores the error
  339. *
  340. * @static
  341. * @param object $error Exception object to handle
  342. * @param array $options Handler options
  343. * @return object The exception object
  344. * @since 1.5
  345. *
  346. * @see raise()
  347. */
  348. public static function handleIgnore(&$error, $options)
  349. {
  350. return $error;
  351. }
  352. /**
  353. * Echo error handler
  354. * - Echos the error message to output
  355. *
  356. * @static
  357. * @param object $error Exception object to handle
  358. * @param array $options Handler options
  359. * @return object The exception object
  360. * @since 1.5
  361. *
  362. * @see raise()
  363. */
  364. public static function handleEcho(&$error, $options)
  365. {
  366. $level_human = JError::translateErrorLevel($error->get('level'));
  367. if (isset ($_SERVER['HTTP_HOST']))
  368. {
  369. // output as html
  370. echo "<br /><b>jos-$level_human</b>: ".$error->get('message')."<br />\n";
  371. }
  372. else
  373. {
  374. // output as simple text
  375. if (defined('STDERR')) {
  376. fwrite(STDERR, "J$level_human: ".$error->get('message')."\n");
  377. }
  378. else {
  379. echo "J$level_human: ".$error->get('message')."\n";
  380. }
  381. }
  382. return $error;
  383. }
  384. /**
  385. * Verbose error handler
  386. * - Echos the error message to output as well as related info
  387. *
  388. * @static
  389. * @param object $error Exception object to handle
  390. * @param array $options Handler options
  391. * @return object The exception object
  392. * @since 1.5
  393. *
  394. * @see raise()
  395. */
  396. public static function handleVerbose(& $error, $options)
  397. {
  398. $level_human = JError::translateErrorLevel($error->get('level'));
  399. $info = $error->get('info');
  400. if (isset ($_SERVER['HTTP_HOST']))
  401. {
  402. // output as html
  403. echo "<br /><b>J$level_human</b>: ".$error->get('message')."<br />\n";
  404. if ($info != null) {
  405. echo "&nbsp;&nbsp;&nbsp;".$info."<br />\n";
  406. }
  407. echo $error->getBacktrace(true);
  408. }
  409. else
  410. {
  411. // output as simple text
  412. echo "J$level_human: ".$error->get('message')."\n";
  413. if ($info != null) {
  414. echo "\t".$info."\n";
  415. }
  416. }
  417. return $error;
  418. }
  419. /**
  420. * Die error handler
  421. * - Echos the error message to output and then dies
  422. *
  423. * @static
  424. * @param object $error Exception object to handle
  425. * @param array $options Handler options
  426. * @return object The exception object
  427. * @since 1.5
  428. *
  429. * @see raise()
  430. */
  431. public static function handleDie(& $error, $options)
  432. {
  433. $level_human = JError::translateErrorLevel($error->get('level'));
  434. if (isset ($_SERVER['HTTP_HOST']))
  435. {
  436. // output as html
  437. jexit("<br /><b>J$level_human</b> ".$error->get('message')."<br />\n");
  438. }
  439. else
  440. {
  441. // output as simple text
  442. if (defined('STDERR')) {
  443. fwrite(STDERR, "J$level_human ".$error->get('message')."\n");
  444. }
  445. else {
  446. jexit("J$level_human ".$error->get('message')."\n");
  447. }
  448. }
  449. return $error;
  450. }
  451. /**
  452. * Message error handler
  453. * - Enqueues the error message into the system queue
  454. *
  455. * @static
  456. * @param object $error Exception object to handle
  457. * @param array $options Handler options
  458. * @return object The exception object
  459. * @since 1.5
  460. *
  461. * @see raise()
  462. */
  463. public static function handleMessage(& $error, $options)
  464. {
  465. $appl = JFactory::getApplication();
  466. $type = ($error->get('level') == E_NOTICE) ? 'notice' : 'error';
  467. $appl->enqueueMessage($error->get('message'), $type);
  468. return $error;
  469. }
  470. /**
  471. * Log error handler
  472. * - Logs the error message to a system log file
  473. *
  474. * @static
  475. * @param object $error Exception object to handle
  476. * @param array $options Handler options
  477. * @return object The exception object
  478. * @since 1.5
  479. *
  480. * @see raise()
  481. */
  482. public static function handleLog(& $error, $options)
  483. {
  484. static $log;
  485. if ($log == null)
  486. {
  487. jimport('joomla.error.log');
  488. $fileName = date('Y-m-d').'.error.log';
  489. $options['format'] = "{DATE}\t{TIME}\t{LEVEL}\t{CODE}\t{MESSAGE}";
  490. $log = & JLog::getInstance($fileName, $options);
  491. }
  492. $entry['level'] = $error->get('level');
  493. $entry['code'] = $error->get('code');
  494. $entry['message'] = str_replace(array ("\r","\n"), array ('','\\n'), $error->get('message'));
  495. $log->addEntry($entry);
  496. return $error;
  497. }
  498. /**
  499. * Callback error handler
  500. * - Send the error object to a callback method for error handling
  501. *
  502. * @static
  503. * @param object $error Exception object to handle
  504. * @param array $options Handler options
  505. * @return object The exception object
  506. * @since 1.5
  507. *
  508. * @see raise()
  509. */
  510. public static function handleCallback(&$error, $options)
  511. {
  512. return call_user_func($options, $error);
  513. }
  514. /**
  515. * Display a custom error page and exit gracefully
  516. *
  517. * @static
  518. * @param object $error Exception object
  519. * @return void
  520. * @since 1.5
  521. */
  522. public static function customErrorPage(& $error)
  523. {
  524. // Initialise variables.
  525. jimport('joomla.document.document');
  526. $app = & JFactory::getApplication();
  527. $document = & JDocument::getInstance('error');
  528. $config = & JFactory::getConfig();
  529. // Get the current template from the application
  530. $template = $app->getTemplate();
  531. // Push the error object into the document
  532. $document->setError($error);
  533. @ob_end_clean();
  534. $document->setTitle(JText::_('Error').': '.$error->get('code'));
  535. $data = $document->render(false, array (
  536. 'template' => $template,
  537. 'directory' => JPATH_THEMES,
  538. 'debug' => $config->getValue('config.debug')
  539. ));
  540. JResponse::setBody($data);
  541. echo JResponse::toString();
  542. $app->close(0);
  543. }
  544. public static function customErrorHandler($level, $msg)
  545. {
  546. JError::raise($level, '', $msg);
  547. }
  548. public static function renderBacktrace($error)
  549. {
  550. $contents = null;
  551. $backtrace = $error->getTrace();
  552. if (is_array($backtrace))
  553. {
  554. ob_start();
  555. $j = 1;
  556. echo '<table border="0" cellpadding="0" cellspacing="0" class="Table">';
  557. echo ' <tr>';
  558. echo ' <td colspan="3" align="left" class="TD"><strong>Call stack</strong></td>';
  559. echo ' </tr>';
  560. echo ' <tr>';
  561. echo ' <td class="TD"><strong>#</strong></td>';
  562. echo ' <td class="TD"><strong>Function</strong></td>';
  563. echo ' <td class="TD"><strong>Location</strong></td>';
  564. echo ' </tr>';
  565. for ($i = count($backtrace)-1; $i >= 0 ; $i--)
  566. {
  567. echo ' <tr>';
  568. echo ' <td class="TD">'.$j.'</td>';
  569. if (isset($backtrace[$i]['class'])) {
  570. echo ' <td class="TD">'.$backtrace[$i]['class'].$backtrace[$i]['type'].$backtrace[$i]['function'].'()</td>';
  571. } else {
  572. echo ' <td class="TD">'.$backtrace[$i]['function'].'()</td>';
  573. }
  574. if (isset($backtrace[$i]['file'])) {
  575. echo ' <td class="TD">'.$backtrace[$i]['file'].':'.$backtrace[$i]['line'].'</td>';
  576. } else {
  577. echo ' <td class="TD">&nbsp;</td>';
  578. }
  579. echo ' </tr>';
  580. $j++;
  581. }
  582. echo '</table>';
  583. $contents = ob_get_contents();
  584. ob_end_clean();
  585. }
  586. return $contents;
  587. }
  588. }