PageRenderTime 27ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/system/debug/debug.php

https://bitbucket.org/pastor399/newcastleunifc
PHP | 929 lines | 546 code | 186 blank | 197 comment | 69 complexity | c6c898fdc37900638f384565197c6950 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Joomla.Plugin
  4. * @subpackage System.Debug
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('_JEXEC') or die;
  10. /**
  11. * Joomla! Debug plugin
  12. *
  13. * @package Joomla.Plugin
  14. * @subpackage System.Debug
  15. * @since 1.5
  16. */
  17. class PlgSystemDebug extends JPlugin
  18. {
  19. protected $linkFormat = '';
  20. /**
  21. * True if debug lang is on.
  22. *
  23. * @var boolean
  24. * @since 3.0
  25. */
  26. private $debugLang = false;
  27. /**
  28. * Holds log entries handled by the plugin.
  29. *
  30. * @var array
  31. * @since 3.1
  32. */
  33. private $logEntries = array();
  34. /**
  35. * Constructor.
  36. *
  37. * @param object &$subject The object to observe
  38. * @param array $config An array that holds the plugin configuration
  39. *
  40. * @since 1.5
  41. */
  42. public function __construct(&$subject, $config)
  43. {
  44. parent::__construct($subject, $config);
  45. // Log the deprecated API.
  46. if ($this->params->get('log-deprecated'))
  47. {
  48. JLog::addLogger(array('text_file' => 'deprecated.php'), JLog::ALL, array('deprecated'));
  49. }
  50. $this->debugLang = JFactory::getApplication()->getCfg('debug_lang');
  51. // Only if debugging or language debug is enabled
  52. if (JDEBUG || $this->debugLang)
  53. {
  54. JFactory::getConfig()->set('gzip', 0);
  55. ob_start();
  56. ob_implicit_flush(false);
  57. }
  58. $this->linkFormat = ini_get('xdebug.file_link_format');
  59. if ($this->params->get('logs', 1))
  60. {
  61. $priority = 0;
  62. foreach ($this->params->get('log_priorities', array()) as $p)
  63. {
  64. $const = 'JLog::'.strtoupper($p);
  65. if (!defined($const))
  66. {
  67. continue;
  68. }
  69. $priority |= constant($const);
  70. }
  71. // Split into an array at any character other than alphabet, numbers, _, ., or -
  72. $categories = array_filter(preg_split('/[^A-Z0-9_\.-]/i', $this->params->get('log_categories', '')));
  73. $mode = $this->params->get('log_category_mode', 0);
  74. JLog::addLogger(array('logger' => 'callback', 'callback' => array($this, 'logger')), $priority, $categories, $mode);
  75. }
  76. }
  77. /**
  78. * Add the CSS for debug. We can't do this in the constructor because
  79. * stuff breaks.
  80. *
  81. * @return void
  82. *
  83. * @since 2.5
  84. */
  85. public function onAfterDispatch()
  86. {
  87. // Only if debugging or language debug is enabled
  88. if ((JDEBUG || $this->debugLang) && $this->isAuthorisedDisplayDebug())
  89. {
  90. JHtml::_('stylesheet', 'cms/debug.css', array(), true);
  91. }
  92. }
  93. /**
  94. * Show the debug info
  95. *
  96. * @since 1.6
  97. */
  98. public function __destruct()
  99. {
  100. // Do not render if debugging or language debug is not enabled
  101. if (!JDEBUG && !$this->debugLang)
  102. {
  103. return;
  104. }
  105. // User has to be authorised to see the debug information
  106. if (!$this->isAuthorisedDisplayDebug())
  107. {
  108. return;
  109. }
  110. // Only render for HTML output
  111. if (JFactory::getDocument()->getType() !== 'html')
  112. {
  113. return;
  114. }
  115. // Capture output
  116. $contents = ob_get_contents();
  117. if ($contents)
  118. {
  119. ob_end_clean();
  120. }
  121. // No debug for Safari and Chrome redirection
  122. if (strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'webkit') !== false
  123. && substr($contents, 0, 50) == '<html><head><meta http-equiv="refresh" content="0;')
  124. {
  125. echo $contents;
  126. return;
  127. }
  128. // Load language
  129. $this->loadLanguage();
  130. $html = '';
  131. // Some "mousewheel protecting" JS
  132. $html .= "<script>function toggleContainer(name)
  133. {
  134. var e = document.getElementById(name);// MooTools might not be available ;)
  135. e.style.display = (e.style.display == 'none') ? 'block' : 'none';
  136. }</script>";
  137. $html .= '<div id="system-debug" class="profiler">';
  138. $html .= '<h1>' . JText::_('PLG_DEBUG_TITLE') . '</h1>';
  139. if (JDEBUG)
  140. {
  141. if (JError::getErrors())
  142. {
  143. $html .= $this->display('errors');
  144. }
  145. $html .= $this->display('session');
  146. if ($this->params->get('profile', 1))
  147. {
  148. $html .= $this->display('profile_information');
  149. }
  150. if ($this->params->get('memory', 1))
  151. {
  152. $html .= $this->display('memory_usage');
  153. }
  154. if ($this->params->get('queries', 1))
  155. {
  156. $html .= $this->display('queries');
  157. }
  158. if ($this->params->get('logs', 1) && !empty($this->logEntries))
  159. {
  160. $html .= $this->display('logs');
  161. }
  162. }
  163. if ($this->debugLang)
  164. {
  165. if ($this->params->get('language_errorfiles', 1))
  166. {
  167. $languageErrors = JFactory::getLanguage()->getErrorFiles();
  168. $html .= $this->display('language_files_in_error', $languageErrors);
  169. }
  170. if ($this->params->get('language_files', 1))
  171. {
  172. $html .= $this->display('language_files_loaded');
  173. }
  174. if ($this->params->get('language_strings'))
  175. {
  176. $html .= $this->display('untranslated_strings');
  177. }
  178. }
  179. $html .= '</div>';
  180. echo str_replace('</body>', $html . '</body>', $contents);
  181. }
  182. /**
  183. * Method to check if the current user is allowed to see the debug information or not.
  184. *
  185. * @return boolean True is access is allowed
  186. *
  187. * @since 3.0
  188. */
  189. private function isAuthorisedDisplayDebug()
  190. {
  191. static $result = null;
  192. if (!is_null($result))
  193. {
  194. return $result;
  195. }
  196. // If the user is not allowed to view the output then end here
  197. $filterGroups = (array) $this->params->get('filter_groups', null);
  198. if (!empty($filterGroups))
  199. {
  200. $userGroups = JFactory::getUser()->get('groups');
  201. if (!array_intersect($filterGroups, $userGroups))
  202. {
  203. $result = false;
  204. return false;
  205. }
  206. }
  207. $result = true;
  208. return true;
  209. }
  210. /**
  211. * General display method.
  212. *
  213. * @param string $item The item to display
  214. * @param array $errors Errors occured during execution
  215. *
  216. * @return string
  217. *
  218. * @since 2.5
  219. */
  220. protected function display($item, array $errors = array())
  221. {
  222. $title = JText::_('PLG_DEBUG_' . strtoupper($item));
  223. $status = '';
  224. if (count($errors))
  225. {
  226. $status = ' dbgerror';
  227. }
  228. $fncName = 'display' . ucfirst(str_replace('_', '', $item));
  229. if (!method_exists($this, $fncName))
  230. {
  231. return __METHOD__ . ' -- Unknown method: ' . $fncName . '<br />';
  232. }
  233. $html = '';
  234. $js = "toggleContainer('dbgContainer" . $item . "');";
  235. $class = 'dbgHeader' . $status;
  236. $html .= '<div class="' . $class . '" onclick="' . $js . '"><a href="javascript:void(0);"><h3>' . $title . '</h3></a></div>';
  237. // @todo set with js.. ?
  238. $style = ' style="display: none;"';
  239. $html .= '<div ' . $style . ' class="dbgContainer" id="dbgContainer' . $item . '">';
  240. $html .= $this->$fncName();
  241. $html .= '</div>';
  242. return $html;
  243. }
  244. /**
  245. * Display session information.
  246. *
  247. * Called recursive.
  248. *
  249. * @param string $key A session key
  250. * @param mixed $session The session array, initially null
  251. * @param integer $id The id is used for JS toggling the div
  252. *
  253. * @return string
  254. *
  255. * @since 2.5
  256. */
  257. protected function displaySession($key = '', $session = null, $id = 0)
  258. {
  259. if (!$session)
  260. {
  261. $session = $_SESSION;
  262. }
  263. static $html = '';
  264. static $id;
  265. if (!is_array($session))
  266. {
  267. $html .= $key . ' &rArr;' . $session . PHP_EOL;
  268. }
  269. else
  270. {
  271. foreach ($session as $sKey => $entries)
  272. {
  273. $display = true;
  274. if (is_array($entries) && $entries)
  275. {
  276. $display = false;
  277. }
  278. if (is_object($entries))
  279. {
  280. $o = JArrayHelper::fromObject($entries);
  281. if ($o)
  282. {
  283. $entries = $o;
  284. $display = false;
  285. }
  286. }
  287. if (!$display)
  288. {
  289. $js = "toggleContainer('dbgContainer_session" . $id . "');";
  290. $html .= '<div class="dbgHeader" onclick="' . $js . '"><a href="javascript:void(0);"><h3>' . $sKey . '</h3></a></div>';
  291. // @todo set with js.. ?
  292. $style = ' style="display: none;"';
  293. $html .= '<div ' . $style . ' class="dbgContainer" id="dbgContainer_session' . $id . '">';
  294. $id ++;
  295. // Recurse...
  296. $this->displaySession($sKey, $entries, $id);
  297. $html .= '</div>';
  298. continue;
  299. }
  300. if (is_array($entries))
  301. {
  302. $entries = implode($entries);
  303. }
  304. if (is_string($entries))
  305. {
  306. $html .= '<code>';
  307. $html .= $sKey . ' &rArr; ' . $entries . '<br />';
  308. $html .= '</code>';
  309. }
  310. }
  311. }
  312. return $html;
  313. }
  314. /**
  315. * Display errors.
  316. *
  317. * @return string
  318. *
  319. * @since 2.5
  320. */
  321. protected function displayErrors()
  322. {
  323. $html = '';
  324. $html .= '<ol>';
  325. while ($error = JError::getError(true))
  326. {
  327. $col = (E_WARNING == $error->get('level')) ? 'red' : 'orange';
  328. $html .= '<li>';
  329. $html .= '<b style="color: ' . $col . '">' . $error->getMessage() . '</b><br />';
  330. $info = $error->get('info');
  331. if ($info)
  332. {
  333. $html .= '<pre>' . print_r($info, true) . '</pre><br />';
  334. }
  335. $html .= $this->renderBacktrace($error);
  336. $html .= '</li>';
  337. }
  338. $html .= '</ol>';
  339. return $html;
  340. }
  341. /**
  342. * Display profile information.
  343. *
  344. * @return string
  345. *
  346. * @since 2.5
  347. */
  348. protected function displayProfileInformation()
  349. {
  350. $html = '';
  351. foreach (JProfiler::getInstance('Application')->getBuffer() as $mark)
  352. {
  353. $html .= '<div>' . $mark . '</div>';
  354. }
  355. return $html;
  356. }
  357. /**
  358. * Display memory usage
  359. *
  360. * @return string
  361. *
  362. * @since 2.5
  363. */
  364. protected function displayMemoryUsage()
  365. {
  366. $bytes = memory_get_usage();
  367. $html = '<code>';
  368. $html .= JHtml::_('number.bytes', $bytes);
  369. $html .= ' (' . number_format($bytes) . ' Bytes)';
  370. $html .= '</code>';
  371. return $html;
  372. }
  373. /**
  374. * Display logged queries.
  375. *
  376. * @return string
  377. *
  378. * @since 2.5
  379. */
  380. protected function displayQueries()
  381. {
  382. $db = JFactory::getDbo();
  383. $log = $db->getLog();
  384. if ( ! $log)
  385. {
  386. return;
  387. }
  388. $html = '';
  389. $html .= '<h4>' . JText::sprintf('PLG_DEBUG_QUERIES_LOGGED', $db->getCount()) . '</h4>';
  390. $html .= '<ol>';
  391. $selectQueryTypeTicker = array();
  392. $otherQueryTypeTicker = array();
  393. foreach ($log as $k => $query)
  394. {
  395. // Start Query Type Ticker Additions
  396. $fromStart = stripos($query, 'from');
  397. $whereStart = stripos($query, 'where', $fromStart);
  398. if ($whereStart === false)
  399. {
  400. $whereStart = stripos($query, 'order by', $fromStart);
  401. }
  402. if ($whereStart === false)
  403. {
  404. $whereStart = strlen($query) - 1;
  405. }
  406. $fromString = substr($query, 0, $whereStart);
  407. $fromString = str_replace("\t", " ", $fromString);
  408. $fromString = str_replace("\n", " ", $fromString);
  409. $fromString = trim($fromString);
  410. // Initialize the select/other query type counts the first time:
  411. if (!isset($selectQueryTypeTicker[$fromString]))
  412. {
  413. $selectQueryTypeTicker[$fromString] = 0;
  414. }
  415. if (!isset($otherQueryTypeTicker[$fromString]))
  416. {
  417. $otherQueryTypeTicker[$fromString] = 0;
  418. }
  419. // Increment the count:
  420. if (stripos($query, 'select') === 0)
  421. {
  422. $selectQueryTypeTicker[$fromString] = $selectQueryTypeTicker[$fromString] + 1;
  423. unset($otherQueryTypeTicker[$fromString]);
  424. }
  425. else
  426. {
  427. $otherQueryTypeTicker[$fromString] = $otherQueryTypeTicker[$fromString] + 1;
  428. unset($selectQueryTypeTicker[$fromString]);
  429. }
  430. $text = $this->highlightQuery($query);
  431. $html .= '<li><code>' . $text . '</code></li>';
  432. }
  433. $html .= '</ol>';
  434. if (!$this->params->get('query_types', 1))
  435. {
  436. return $html;
  437. }
  438. // Get the totals for the query types:
  439. $totalSelectQueryTypes = count($selectQueryTypeTicker);
  440. $totalOtherQueryTypes = count($otherQueryTypeTicker);
  441. $totalQueryTypes = $totalSelectQueryTypes + $totalOtherQueryTypes;
  442. $html .= '<h4>' . JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes) . '</h4>';
  443. if ($totalSelectQueryTypes)
  444. {
  445. $html .= '<h5>' . JText::sprintf('PLG_DEBUG_SELECT_QUERIES') . '</h5>';
  446. arsort($selectQueryTypeTicker);
  447. $html .= '<ol>';
  448. foreach ($selectQueryTypeTicker as $query => $occurrences)
  449. {
  450. $html .= '<li><code>'
  451. . JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES', $this->highlightQuery($query), $occurrences)
  452. . '</code></li>';
  453. }
  454. $html .= '</ol>';
  455. }
  456. if ($totalOtherQueryTypes)
  457. {
  458. $html .= '<h5>' . JText::sprintf('PLG_DEBUG_OTHER_QUERIES') . '</h5>';
  459. arsort($otherQueryTypeTicker);
  460. $html .= '<ol>';
  461. foreach ($otherQueryTypeTicker as $query => $occurrences)
  462. {
  463. $html .= '<li><code>'
  464. . JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES', $this->highlightQuery($query), $occurrences)
  465. . '</code></li>';
  466. }
  467. $html .= '</ol>';
  468. }
  469. return $html;
  470. }
  471. /**
  472. * Displays errors in language files.
  473. *
  474. * @return string
  475. *
  476. * @since 2.5
  477. */
  478. protected function displayLanguageFilesInError()
  479. {
  480. $html = '';
  481. $errorfiles = JFactory::getLanguage()->getErrorFiles();
  482. if (!count($errorfiles))
  483. {
  484. $html .= '<p>' . JText::_('JNONE') . '</p>';
  485. return $html;
  486. }
  487. $html .= '<ul>';
  488. foreach ($errorfiles as $file => $error)
  489. {
  490. $html .= '<li>' . $this->formatLink($file) . str_replace($file, '', $error) . '</li>';
  491. }
  492. $html .= '</ul>';
  493. return $html;
  494. }
  495. /**
  496. * Display loaded language files.
  497. *
  498. * @return string
  499. *
  500. * @since 2.5
  501. */
  502. protected function displayLanguageFilesLoaded()
  503. {
  504. $html = '';
  505. $html .= '<ul>';
  506. foreach (JFactory::getLanguage()->getPaths() as $extension => $files)
  507. {
  508. foreach ($files as $file => $status)
  509. {
  510. $html .= '<li>';
  511. $html .= ($status)
  512. ? JText::_('PLG_DEBUG_LANG_LOADED')
  513. : JText::_('PLG_DEBUG_LANG_NOT_LOADED');
  514. $html .= ' : ';
  515. $html .= $this->formatLink($file);
  516. $html .= '</li>';
  517. }
  518. }
  519. $html .= '</ul>';
  520. return $html;
  521. }
  522. /**
  523. * Display untranslated language strings.
  524. *
  525. * @return string
  526. *
  527. * @since 2.5
  528. */
  529. protected function displayUntranslatedStrings()
  530. {
  531. $stripFirst = $this->params->get('strip-first');
  532. $stripPref = $this->params->get('strip-prefix');
  533. $stripSuff = $this->params->get('strip-suffix');
  534. $orphans = JFactory::getLanguage()->getOrphans();
  535. $html = '';
  536. if ( ! count($orphans))
  537. {
  538. $html .= '<p>' . JText::_('JNONE') . '</p>';
  539. return $html;
  540. }
  541. ksort($orphans, SORT_STRING);
  542. $guesses = array();
  543. foreach ($orphans as $key => $occurance)
  544. {
  545. if (is_array($occurance) && isset($occurance[0]))
  546. {
  547. $info = $occurance[0];
  548. $file = ($info['file']) ? $info['file'] : '';
  549. if (!isset($guesses[$file]))
  550. {
  551. $guesses[$file] = array();
  552. }
  553. // Prepare the key
  554. if (($pos = strpos($info['string'], '=')) > 0)
  555. {
  556. $parts = explode('=', $info['string']);
  557. $key = $parts[0];
  558. $guess = $parts[1];
  559. }
  560. else
  561. {
  562. $guess = str_replace('_', ' ', $info['string']);
  563. if ($stripFirst)
  564. {
  565. $parts = explode(' ', $guess);
  566. if (count($parts) > 1)
  567. {
  568. array_shift($parts);
  569. $guess = implode(' ', $parts);
  570. }
  571. }
  572. $guess = trim($guess);
  573. if ($stripPref)
  574. {
  575. $guess = trim(preg_replace(chr(1) . '^' . $stripPref . chr(1) . 'i', '', $guess));
  576. }
  577. if ($stripSuff)
  578. {
  579. $guess = trim(preg_replace(chr(1) . $stripSuff . '$' . chr(1) . 'i', '', $guess));
  580. }
  581. }
  582. $key = trim(strtoupper($key));
  583. $key = preg_replace('#\s+#', '_', $key);
  584. $key = preg_replace('#\W#', '', $key);
  585. // Prepare the text
  586. $guesses[$file][] = $key . '="' . $guess . '"';
  587. }
  588. }
  589. foreach ($guesses as $file => $keys)
  590. {
  591. $html .= "\n\n# " . ($file ? $this->formatLink($file) : JText::_('PLG_DEBUG_UNKNOWN_FILE')) . "\n\n";
  592. $html .= implode("\n", $keys);
  593. }
  594. return '<pre>' . $html . '</pre>';
  595. }
  596. /**
  597. * Simple highlight for SQL queries.
  598. *
  599. * @param string $query The query to highlight
  600. *
  601. * @return string
  602. *
  603. * @since 2.5
  604. */
  605. protected function highlightQuery($query)
  606. {
  607. $newlineKeywords = '#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';
  608. $query = htmlspecialchars($query, ENT_QUOTES);
  609. $query = preg_replace($newlineKeywords, '<br />&#160;&#160;\\0', $query);
  610. $regex = array(
  611. // Tables are identified by the prefix
  612. '/(=)/'
  613. => '<b class="dbgOperator">$1</b>',
  614. // All uppercase words have a special meaning
  615. '/(?<!\w|>)([A-Z_]{2,})(?!\w)/x'
  616. => '<span class="dbgCommand">$1</span>',
  617. // Tables are identified by the prefix
  618. '/(' . JFactory::getDbo()->getPrefix() . '[a-z_0-9]+)/'
  619. => '<span class="dbgTable">$1</span>'
  620. );
  621. $query = preg_replace(array_keys($regex), array_values($regex), $query);
  622. $query = str_replace('*', '<b style="color: red;">*</b>', $query);
  623. return $query;
  624. }
  625. /**
  626. * Render the backtrace.
  627. *
  628. * Stolen from JError to prevent it's removal.
  629. *
  630. * @param integer $error The error
  631. *
  632. * @return string Contents of the backtrace
  633. *
  634. * @since 2.5
  635. */
  636. protected function renderBacktrace($error)
  637. {
  638. $backtrace = $error->getTrace();
  639. $html = '';
  640. if (is_array($backtrace))
  641. {
  642. $j = 1;
  643. $html .= '<table cellpadding="0" cellspacing="0">';
  644. $html .= '<tr>';
  645. $html .= '<td colspan="3"><strong>Call stack</strong></td>';
  646. $html .= '</tr>';
  647. $html .= '<tr>';
  648. $html .= '<th>#</th>';
  649. $html .= '<th>Function</th>';
  650. $html .= '<th>Location</th>';
  651. $html .= '</tr>';
  652. for ($i = count($backtrace) - 1; $i >= 0; $i--)
  653. {
  654. $link = '&#160;';
  655. if (isset($backtrace[$i]['file']))
  656. {
  657. $link = $this->formatLink($backtrace[$i]['file'], $backtrace[$i]['line']);
  658. }
  659. $html .= '<tr>';
  660. $html .= '<td>' . $j . '</td>';
  661. if (isset($backtrace[$i]['class']))
  662. {
  663. $html .= '<td>' . $backtrace[$i]['class'] . $backtrace[$i]['type'] . $backtrace[$i]['function'] . '()</td>';
  664. }
  665. else
  666. {
  667. $html .= '<td>' . $backtrace[$i]['function'] . '()</td>';
  668. }
  669. $html .= '<td>' . $link . '</td>';
  670. $html .= '</tr>';
  671. $j++;
  672. }
  673. $html .= '</table>';
  674. }
  675. return $html;
  676. }
  677. /**
  678. * Replaces the Joomla! root with "JROOT" to improve readability.
  679. * Formats a link with a special value xdebug.file_link_format
  680. * from the php.ini file.
  681. *
  682. * @param string $file The full path to the file.
  683. * @param string $line The line number.
  684. *
  685. * @return string
  686. *
  687. * @since 2.5
  688. */
  689. protected function formatLink($file, $line = '')
  690. {
  691. $link = str_replace(JPATH_ROOT, 'JROOT', $file);
  692. $link .= ($line) ? ':' . $line : '';
  693. if ($this->linkFormat)
  694. {
  695. $href = $this->linkFormat;
  696. $href = str_replace('%f', $file, $href);
  697. $href = str_replace('%l', $line, $href);
  698. $html = '<a href="' . $href . '">' . $link . '</a>';
  699. }
  700. else
  701. {
  702. $html = $link;
  703. }
  704. return $html;
  705. }
  706. /**
  707. * Store log messages so they can be displayed later.
  708. * This function is passed log entries by JLogLoggerCallback.
  709. *
  710. * @param JLogEntry $entry A log entry.
  711. *
  712. * @since 3.1
  713. */
  714. public function logger(JLogEntry $entry)
  715. {
  716. $this->logEntries[] = $entry;
  717. }
  718. /**
  719. * Display log messages
  720. *
  721. * @return string
  722. *
  723. * @since 3.1
  724. */
  725. protected function displayLogs()
  726. {
  727. $priorities = array(
  728. JLog::EMERGENCY => 'EMERGENCY',
  729. JLog::ALERT => 'ALERT',
  730. JLog::CRITICAL => 'CRITICAL',
  731. JLog::ERROR => 'ERROR',
  732. JLog::WARNING => 'WARNING',
  733. JLog::NOTICE => 'NOTICE',
  734. JLog::INFO => 'INFO',
  735. JLog::DEBUG => 'DEBUG');
  736. $out = array();
  737. foreach ($this->logEntries as $entry)
  738. {
  739. $out[] = '<h5>' . $priorities[$entry->priority] . ' - ' . $entry->category . ' </h5><code>' . $entry->message . '</code>';
  740. }
  741. return implode('<br /><br />', $out);
  742. }
  743. }