Source for file debug.php
Documentation is available at debug.php
* @subpackage System.Debug
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
* @subpackage System.Debug
* True if debug lang is on.
private $debugLang =
false;
* Holds log entries handled by the plugin.
private $logEntries =
array();
* Holds SHOW PROFILES of queries
private $sqlShowProfiles =
array();
* Holds all SHOW PROFILE FOR QUERY n, indexed by n-1
private $sqlShowProfileEach =
array();
* Holds all EXPLAIN EXTENDED for all queries
private $explains =
array();
* @param object &$subject The object to observe
* @param array $config An array that holds the plugin configuration
// Log the deprecated API.
if ($this->params->get('log-deprecated'))
JLog::addLogger(array('text_file' =>
'deprecated.php'), JLog::ALL, array('deprecated'));
// Only if debugging or language debug is enabled
if (JDEBUG ||
$this->debugLang)
if ($this->params->get('logs', 1))
foreach ($this->params->get('log_priorities', array()) as $p)
// Split into an array at any character other than alphabet, numbers, _, ., or -
$mode =
$this->params->get('log_category_mode', 0);
JLog::addLogger(array('logger' =>
'callback', 'callback' =>
array($this, 'logger')), $priority, $categories, $mode);
// Prepare disconnect-handler for SQL profiling:
$db->addDisconnectHandler(array($this, 'mysqlDisconnectHandler'));
* Add the CSS for debug. We can't do this in the constructor because
// Only if debugging or language debug is enabled
if ((JDEBUG ||
$this->debugLang) &&
$this->isAuthorisedDisplayDebug())
JHtml::_('stylesheet', 'cms/debug.css', array(), true);
// Only if debugging is enabled for SQL queries popovers
if (JDEBUG &&
$this->isAuthorisedDisplayDebug())
JHtml::_('bootstrap.tooltip');
JHtml::_('bootstrap.popover', '.hasPopover', array('placement' =>
'top'));
// Do not render if debugging or language debug is not enabled
if (!JDEBUG &&
!$this->debugLang)
// User has to be authorised to see the debug information
if (!$this->isAuthorisedDisplayDebug())
// Only render for HTML output
// No debug for Safari and Chrome redirection
&&
substr($contents, 0, 50) ==
'<html><head><meta http-equiv="refresh" content="0;'
// Some "mousewheel protecting" JS
$html[] =
"<script>function toggleContainer(name)
var e = document.getElementById(name);// MooTools might not be available ;)
e.style.display = (e.style.display == 'none') ? 'block' : 'none';
$html[] =
'<div id="system-debug" class="profiler">';
$html[] =
'<h1>' .
JText::_('PLG_DEBUG_TITLE') .
'</h1>';
$html[] =
$this->display('errors');
$html[] =
$this->display('session');
if ($this->params->get('profile', 1))
$html[] =
$this->display('profile_information');
if ($this->params->get('memory', 1))
$html[] =
$this->display('memory_usage');
if ($this->params->get('queries', 1))
$html[] =
$this->display('queries');
if ($this->params->get('logs', 1) &&
!empty($this->logEntries))
if ($this->params->get('language_errorfiles', 1))
$html[] =
$this->display('language_files_in_error', $languageErrors);
if ($this->params->get('language_files', 1))
$html[] =
$this->display('language_files_loaded');
if ($this->params->get('language_strings'))
$html[] =
$this->display('untranslated_strings');
* Method to check if the current user is allowed to see the debug information or not.
* @return boolean True is access is allowed
private function isAuthorisedDisplayDebug()
// If the user is not allowed to view the output then end here
$filterGroups = (array)
$this->params->get('filter_groups', null);
if (!empty($filterGroups))
if (!array_intersect($filterGroups, $userGroups))
* General display method.
* @param string $item The item to display
* @param array $errors Errors occured during execution
protected function display($item, array $errors =
array())
return __METHOD__ .
' -- Unknown method: ' .
$fncName .
'<br />';
$js =
"toggleContainer('dbg_container_" .
$item .
"');";
$class =
'dbg-header' .
$status;
$html[] =
'<div class="' .
$class .
'" onclick="' .
$js .
'"><a href="javascript:void(0);"><h3>' .
$title .
'</h3></a></div>';
$style =
' style="display: none;"';
$html[] =
'<div ' .
$style .
' class="dbg-container" id="dbg_container_' .
$item .
'">';
$html[] =
$this->$fncName();
* Display session information.
* @param string $key A session key
* @param mixed $session The session array, initially null
* @param integer $id The id is used for JS toggling the div
protected function displaySession($key =
'', $session =
null, $id =
0)
$html[] =
$key .
' ⇒' .
$session .
PHP_EOL;
foreach ($session as $sKey =>
$entries)
$js =
"toggleContainer('dbg_container_session" .
$id .
'_' .
$sKey .
"');";
$html[] =
'<div class="dbg-header" onclick="' .
$js .
'"><a href="javascript:void(0);"><h3>' .
$sKey .
'</h3></a></div>';
$style =
' style="display: none;"';
$html[] =
'<div ' .
$style .
' class="dbg-container" id="dbg_container_session' .
$id .
'_' .
$sKey .
'">';
$html[] =
$sKey .
' ⇒ ' .
$entries .
'<br />';
$col =
(E_WARNING ==
$error->get('level')) ?
'red' :
'orange';
$html[] =
'<b style="color: ' .
$col .
'">' .
$error->getMessage() .
'</b><br />';
$info =
$error->get('info');
$html[] =
'<pre>' .
print_r($info, true) .
'</pre><br />';
* Display profile information.
$totalTime +=
$mark->time;
$totalMem +=
$mark->memory;
JText::_('PLG_DEBUG_TIME') .
': <span class="label label-time">%.1f ms</span> / <span class="label">%.1f ms</span>'
.
' ' .
JText::_('PLG_DEBUG_MEMORY') .
': <span class="label label-memory">%0.3f MB</span> / <span class="label">%0.2f MB</span>'
$marks[] = (object)
array(
'memory' =>
$mark->memory,
$avgTime =
$totalTime /
count($marks);
$avgMem =
$totalMem /
count($marks);
foreach ($marks as $mark)
if ($mark->time >
$avgTime *
1.5)
$barClass =
'bar-danger';
$labelClass =
'label-important';
elseif ($mark->time <
$avgTime /
1.5)
$barClass =
'bar-success';
$labelClass =
'label-success';
$barClass =
'bar-warning';
$labelClass =
'label-warning';
if ($mark->memory >
$avgMem *
1.5)
$barClassMem =
'bar-danger';
$labelClassMem =
'label-important';
elseif ($mark->memory <
$avgMem /
1.5)
$barClassMem =
'bar-success';
$labelClassMem =
'label-success';
$barClassMem =
'bar-warning';
$labelClassMem =
'label-warning';
$bars[] = (object)
array(
'width' =>
round($mark->time /
($totalTime /
100), 4),
$barsMem[] = (object)
array(
'width' =>
round($mark->memory /
($totalMem /
100), 4),
$htmlMarks[] =
'<div>' .
str_replace('label-time', $labelClass, str_replace('label-memory', $labelClassMem, $mark->html)) .
'</div>';
$html[] =
'<h4>' .
JText::_('PLG_DEBUG_TIME') .
'</h4>';
$html[] =
'<h4>' .
JText::_('PLG_DEBUG_MEMORY') .
'</h4>';
$html[] =
'<div class="dbg-profile-list">' .
implode('', $htmlMarks) .
'</div>';
$timings =
$db->getTimings();
foreach ($timings as $k =>
$v)
$totalQueryTime +=
$v -
$lastStart;
$totalQueryTime =
$totalQueryTime *
1000;
if ($totalQueryTime >
($totalTime *
0.25))
$labelClass =
'label-important';
elseif ($totalQueryTime <
($totalTime *
0.15))
$labelClass =
'label-success';
$labelClass =
'label-warning';
'PLG_DEBUG_QUERIES_TIME',
sprintf('<span class="label ' .
$labelClass .
'">%.1f ms</span>', $totalQueryTime)
return '<span class="label">' .
JHtml::_('number.bytes', $bytes) .
'</span>'
.
' (<span class="label">' .
number_format($bytes) .
' ' .
JText::_('PLG_DEBUG_BYTES') .
'</span>)';
* Display logged queries.
$timings =
$db->getTimings();
$callStacks =
$db->getCallStacks();
$selectQueryTypeTicker =
array();
$otherQueryTypeTicker =
array();
$startTime =
$timings[0];
$endTime =
$timings[count($timings) -
1];
$totalBargraphTime =
$endTime -
$startTime;
if ($totalBargraphTime >
0)
foreach ($log as $id =>
$query)
if (isset
($timings[$id *
2 +
1]))
// Compute the query time: $timing[$k] = array( queryTime, timeBetweenQueries ):
$timing[$id] =
array(($timings[$id *
2 +
1] -
$timings[$id *
2]) *
1000, $id >
0 ?
($timings[$id *
2] -
$timings[$id *
2 -
1]) *
1000 :
0);
$maxtime =
max($maxtime, $timing[$id]['0']);
foreach ($log as $id =>
$query)
if (!isset
($duplicates[$did]))
$duplicates[$did] =
array();
$duplicates[$did][] =
$id;
if ($timings && isset
($timings[$id *
2 +
1]))
// Compute the query time:
$queryTime =
($timings[$id *
2 +
1] -
$timings[$id *
2]) *
1000;
$totalQueryTime +=
$queryTime;
// Run an EXPLAIN EXTENDED query on the SQL query if possible:
$hasWarningsInProfile =
false;
if (isset
($this->explains[$id]))
$explain =
$this->tableToHtml($this->explains[$id], $hasWarnings);
// Run a SHOW PROFILE query:
if (in_array($db->name, array('mysqli', 'mysql')))
if (isset
($this->sqlShowProfileEach[$id]))
$profileTable =
$this->sqlShowProfileEach[$id];
$profile =
$this->tableToHtml($profileTable, $hasWarningsInProfile);
$ratio =
0.5; // how heavy should the string length count: 0 - 1
$timeScore =
$queryTime /
(strlen($query) *
$ratio) *
200;
// Determine color of bargraph depending on query speed and presence of warnings in EXPLAIN:
$barClass =
'bar-danger';
$labelClass =
'label-important';
elseif ($hasWarnings ||
$timeScore >
5)
$barClass =
'bar-warning';
$labelClass =
'label-warning';
$barClass =
'bar-success';
$labelClass =
'label-success';
// Computes bargraph as follows: Position begin and end of the bar relatively to whole execution time:
$prevBar =
($id && isset
($bars[$id -
1])) ?
$bars[$id -
1] :
0;
$barPre =
round($timing[$id][1] /
($totalBargraphTime *
10), 4);
$barWidth =
round($timing[$id][0] /
($totalBargraphTime *
10), 4);
if ($barWidth <
$minWidth)
$barPre -=
($minWidth -
$barWidth);
$bars[$id] = (object)
array(
'tip' =>
sprintf('%.2f ms', $queryTime)
$info[$id] = (object)
array(
'hasWarnings' =>
$hasWarnings
// Remove single queries from $duplicates
foreach ($duplicates as $did =>
$dups)
unset
($duplicates[$did]);
$total_duplicates +=
count($dups);
if ($bars[0]->width <
$minWidth && isset
($bars[1]))
$bars[1]->pre -=
($minWidth -
$bars[0]->width);
$minWidth +=
$bars[1]->pre;
$bars[0]->width =
$minWidth;
foreach ($log as $id =>
$query)
// Start Query Type Ticker Additions
$fromStart =
stripos($query, 'from');
$whereStart =
stripos($query, 'where', $fromStart);
if ($whereStart ===
false)
$whereStart =
stripos($query, 'order by', $fromStart);
if ($whereStart ===
false)
$whereStart =
strlen($query) -
1;
$fromString =
substr($query, 0, $whereStart);
$fromString =
trim($fromString);
// Initialize the select/other query type counts the first time:
if (!isset
($selectQueryTypeTicker[$fromString]))
$selectQueryTypeTicker[$fromString] =
0;
if (!isset
($otherQueryTypeTicker[$fromString]))
$otherQueryTypeTicker[$fromString] =
0;
if (stripos($query, 'select') ===
0)
$selectQueryTypeTicker[$fromString] =
$selectQueryTypeTicker[$fromString] +
1;
unset
($otherQueryTypeTicker[$fromString]);
$otherQueryTypeTicker[$fromString] =
$otherQueryTypeTicker[$fromString] +
1;
unset
($selectQueryTypeTicker[$fromString]);
if ($timings && isset
($timings[$id *
2 +
1]))
// Compute the query time:
$queryTime =
($timings[$id *
2 +
1] -
$timings[$id *
2]) *
1000;
// Formats the output for the query time with EXPLAIN query results as tooltip:
$htmlTiming =
'<div style="margin: 0px 0 5px;"><span class="dbg-query-time">' .
JText::sprintf('PLG_DEBUG_QUERY_TIME', sprintf('<span class="label ' .
$info[$id]->class .
'">%.2f ms</span>', $timing[$id]['0']));
$htmlTiming .=
' ' .
JText::sprintf('PLG_DEBUG_QUERY_AFTER_LAST', sprintf('<span class="label">%.2f ms</span>', $timing[$id]['1']));
$htmlTiming .=
'</span>';
if (isset
($callStacks[$id][0]['memory']))
$memoryUsed =
$callStacks[$id][0]['memory'][1] -
$callStacks[$id][0]['memory'][0];
$memoryBeforeQuery =
$callStacks[$id][0]['memory'][0];
// Determine color of query memory usage:
if ($memoryUsed >
0.1 *
$memoryUsageNow)
$labelClass =
'label-important';
elseif ($memoryUsed >
0.05 *
$memoryUsageNow)
$labelClass =
'label-warning';
$labelClass =
'label-success';
$htmlTiming .=
' ' .
'<span class="dbg-query-memory">' .
JText::sprintf('PLG_DEBUG_MEMORY_USED_FOR_QUERY',
sprintf('<span class="label ' .
$labelClass .
'">%.3f MB</span>', $memoryUsed /
1048576),
sprintf('<span class="label">%.3f MB</span>', $memoryBeforeQuery /
1048576)
if ($callStacks[$id][0]['memory'][2] !==
null)
// Determine color of number or results:
$resultsReturned =
$callStacks[$id][0]['memory'][2];
if ($resultsReturned >
3000)
$labelClass =
'label-important';
elseif ($resultsReturned >
1000)
$labelClass =
'label-warning';
elseif ($resultsReturned ==
0)
$labelClass =
'label-success';
$htmlResultsReturned =
'<span class="label ' .
$labelClass .
'">' . (int)
$resultsReturned .
'</span>';
$htmlTiming .=
' ' .
'<span class="dbg-query-rowsnumber">' .
JText::sprintf('PLG_DEBUG_ROWS_RETURNED_BY_QUERY', $htmlResultsReturned) .
'</span>';
$htmlBar =
$this->renderBars($bars, 'query', $id);
$title =
JText::_('PLG_DEBUG_PROFILE');
if (!$info[$id]->profile)
$title =
'<span class="dbg-noprofile">' .
$title .
'</span>';
$htmlProfile =
($info[$id]->profile ?
$info[$id]->profile :
JText::_('PLG_DEBUG_NO_PROFILE'));
if (isset
($callStacks[$id]))
$htmlCallStackElements =
array();
foreach ($callStacks[$id] as $functionCall)
if (isset
($functionCall['file']) && isset
($functionCall['line']) &&
(strpos($functionCall['file'], '/libraries/joomla/database/') ===
false))
$htmlCallStackElements[] =
'<span class="dbg-log-called-from">' .
$this->formatLink($htmlFile, $htmlLine) .
'</span>';
$htmlCallStack =
'<div class="dbg-query-table"><div>' .
implode('</div><div>', $htmlCallStackElements) .
'</div></div>';
$htmlCallStack .=
'<div>[<a href="http://xdebug.org/docs/all_settings#file_link_format" target="_blank">' .
JText::_('PLG_DEBUG_LINK_FORMAT') .
'</a>]</div>';
'bootstrap.startAccordion', 'dbg_query_' .
$id, array(
'active' =>
($info[$id]->hasWarnings ?
('dbg_query_explain_' .
$id) :
'')
$htmlAccordions .=
JHtml::_('bootstrap.addSlide', 'dbg_query_' .
$id, JText::_('PLG_DEBUG_EXPLAIN'), 'dbg_query_explain_' .
$id)
.
JHtml::_('bootstrap.endSlide');
$htmlAccordions .=
JHtml::_('bootstrap.addSlide', 'dbg_query_' .
$id, $title, 'dbg_query_profile_' .
$id)
.
JHtml::_('bootstrap.endSlide');
$htmlAccordions .=
JHtml::_('bootstrap.addSlide', 'dbg_query_' .
$id, JText::_('PLG_DEBUG_CALL_STACK'), 'dbg_query_callstack_' .
$id)
.
JHtml::_('bootstrap.endSlide');
$htmlAccordions .=
JHtml::_('bootstrap.endAccordion');
if (isset
($duplicates[$did]))
foreach ($duplicates[$did] as $dup)
$dups[] =
'<a href="#dbg-query-' .
($dup +
1) .
'">#' .
($dup +
1) .
'</a>';
$htmlQuery =
'<div class="alert alert-error">' .
JText::_('PLG_DEBUG_QUERY_DUPLICATES') .
': ' .
implode(' ', $dups) .
'</div>'
.
'<pre class="alert hasTooltip" title="' .
JHtml::tooltipText('PLG_DEBUG_QUERY_DUPLICATES_FOUND') .
'">' .
$text .
'</pre>';
$htmlQuery =
'<pre>' .
$text .
'</pre>';
$list[] =
'<a name="dbg-query-' .
($id +
1) .
'"></a>'
$list[] =
'<pre>' .
$text .
'</pre>';
$totalTime +=
$mark->time;
if ($totalQueryTime >
($totalTime *
0.25))
$labelClass =
'label-important';
elseif ($totalQueryTime <
($totalTime *
0.15))
$labelClass =
'label-success';
$labelClass =
'label-warning';
$html[] =
'<h4>' .
JText::sprintf('PLG_DEBUG_QUERIES_LOGGED', $db->getCount())
.
sprintf(' <span class="label ' .
$labelClass .
'">%.1f ms</span>', ($totalQueryTime)) .
'</h4><br />';
$html[] =
'<div class="alert alert-error">'
.
'<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_TOTAL_NUMBER', $total_duplicates) .
'</h4>';
foreach ($duplicates as $dups)
$links[] =
'<a href="#dbg-query-' .
($dup +
1) .
'">#' .
($dup +
1) .
'</a>';
$html[] =
'<div>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_NUMBER', count($links)) .
': ' .
implode(' ', $links) .
'</div>';
$html[] =
'<ol><li>' .
implode('<hr /></li><li>', $list) .
'<hr /></li></ol>';
// Get the totals for the query types:
$totalSelectQueryTypes =
count($selectQueryTypeTicker);
$totalOtherQueryTypes =
count($otherQueryTypeTicker);
$totalQueryTypes =
$totalSelectQueryTypes +
$totalOtherQueryTypes;
$html[] =
'<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes) .
'</h4>';
if ($totalSelectQueryTypes)
$html[] =
'<h5>' .
JText::_('PLG_DEBUG_SELECT_QUERIES') .
'</h5>';
arsort($selectQueryTypeTicker);
foreach ($selectQueryTypeTicker as $query =>
$occurrences)
$html[] =
'<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
if ($totalOtherQueryTypes)
$html[] =
'<h5>' .
JText::_('PLG_DEBUG_OTHER_QUERIES') .
'</h5>';
arsort($otherQueryTypeTicker);
foreach ($otherQueryTypeTicker as $query =>
$occurrences)
$html[] =
'<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
* @param array &$bars Array of bar data
* @param string $class Optional class for items
* @param integer $id Id if the bar to highlight
protected function renderBars(&$bars, $class =
'', $id =
null)
foreach ($bars as $i =>
$bar)
if (isset
($bar->pre) &&
$bar->pre)
$html[] =
'<div class="dbg-bar-spacer" style="width:' .
$bar->pre .
'%;"></div>';
$barClass =
trim('bar dbg-bar ' .
(isset
($bar->class) ?
$bar->class :
''));
if ($id !==
null &&
$i ==
$id)
$barClass .=
' dbg-bar-active';
if (isset
($bar->tip) &&
$bar->tip)
$barClass .=
' hasTooltip';
$tip =
JHtml::tooltipText($bar->tip, '', 0);
$html[] =
'<a class="bar dbg-bar ' .
$barClass .
'" title="' .
$tip .
'" style="width: ' .
$bar->width .
'%;" href="#dbg-' .
$class .
'-' .
($i +
1) .
'"></a>';
return '<div class="progress dbg-bars dbg-bars-' .
$class .
'">' .
implode('', $html) .
'</div>';
* @param boolean $hasWarnings Changes value to true if warnings are displayed, otherwise untouched
$html[] =
'<table class="table table-striped dbg-query-table"><tr>';
if (isset
($tr['Duration']))
$durations[] =
$tr['Duration'];
rsort($durations, SORT_NUMERIC);
foreach ($tr as $k =>
$td)
// Display null's as 'NULL':
// Treat special columns:
if ($td >=
0.001 &&
($td ==
$durations[0] ||
(isset
($durations[1]) &&
$td ==
$durations[1])))
// Duration column with duration value of more than 1 ms and within 2 top duration in SQL engine: Highlight warning:
$html[] =
'<td class="dbg-warning">';
// Display duration in ms with the unit instead of seconds:
$html[] =
sprintf('%.1f ms', $td *
1000);
// An error in the EXPLAIN query occured, display it instead of the result (means original query had syntax error most probably):
// Displays query parts which don't use a key with warning:
$html[] =
'<td><strong>' .
'<span class="dbg-warning hasTooltip" title="' .
JHtml::tooltipText('PLG_DEBUG_WARNING_NO_INDEX_DESC') .
'">' .
JText::_('PLG_DEBUG_WARNING_NO_INDEX') .
'</span>' .
'</strong>';
// Replace spaces with nbsp for less tall tables displayed:
// Displays warnings for "Using filesort":
$htmlTdWithWarnings =
str_replace('Using filesort', '<span class="dbg-warning hasTooltip" title="' .
JHtml::tooltipText('PLG_DEBUG_WARNING_USING_FILESORT_DESC') .
'">' .
JText::_('PLG_DEBUG_WARNING_USING_FILESORT') .
'</span>', $htmlTd);
if ($htmlTdWithWarnings !==
$htmlTd)
$html[] =
'<td>' .
$htmlTdWithWarnings;
* Disconnect-handler for database to collect profiling and explain information
* @param JDatabaseDriver &$db Database object
// Check if profiling is enabled:
$db->setQuery("SHOW VARIABLES LIKE 'have_profiling'");
$hasProfiling =
$db->loadResult();
// Run a SHOW PROFILE query:
$db->setQuery('SHOW PROFILES');
$this->sqlShowProfiles =
$db->loadAssocList();
if ($this->sqlShowProfiles)
foreach ($this->sqlShowProfiles as $qn)
// Run SHOW PROFILE FOR QUERY for each query where a profile is available (max 100):
$db->setQuery('SHOW PROFILE FOR QUERY ' . (int)
($qn['Query_ID']));
$this->sqlShowProfileEach[(int)
($qn['Query_ID'] -
1)] =
$db->loadAssocList();
$this->sqlShowProfileEach[0] =
array(array('Error' =>
'MySql have_profiling = off'));
$this->sqlShowProfileEach[0] =
array(array('Error' =>
$e->getMessage()));
if (in_array($db->name, array('mysqli', 'mysql', 'postgresql')))
foreach ($log as $k =>
$query)
if ((stripos($query, 'select') ===
0) ||
($dbVersion56 &&
((stripos($query, 'delete') ===
0) ||
(stripos($query, 'update') ===
0))))
$db->setQuery('EXPLAIN ' .
($dbVersion56 ?
'EXTENDED ' :
'') .
$query);
$this->explains[$k] =
$db->loadAssocList();
$this->explains[$k] =
array(array('Error' =>
$e->getMessage()));
* Displays errors in language files.
return '<p>' .
JText::_('JNONE') .
'</p>';
foreach ($errorfiles as $file =>
$error)
* Display loaded language files.
foreach ($files as $file =>
$status)
?
JText::_('PLG_DEBUG_LANG_LOADED')
:
JText::_('PLG_DEBUG_LANG_NOT_LOADED');
* Display untranslated language strings.
$stripFirst =
$this->params->get('strip-first');
$stripPref =
$this->params->get('strip-prefix');
$stripSuff =
$this->params->get('strip-suffix');
return '<p>' .
JText::_('JNONE') .
'</p>';
ksort($orphans, SORT_STRING);
foreach ($orphans as $key =>
$occurance)
if (is_array($occurance) && isset
($occurance[0]))
$file =
($info['file']) ?
$info['file'] :
'';
if (!isset
($guesses[$file]))
$guesses[$file] =
array();
if (($pos =
strpos($info['string'], '=')) >
0)
$parts =
explode('=', $info['string']);
$guesses[$file][] =
$key .
'="' .
$guess .
'"';
foreach ($guesses as $file =>
$keys)
$html[] =
"\n\n# " .
($file ?
$this->formatLink($file) :
JText::_('PLG_DEBUG_UNKNOWN_FILE')) .
"\n\n";
return '<pre>' .
implode('', $html) .
'</pre>';
* Simple highlight for SQL queries.
* @param string $query The query to highlight
$newlineKeywords =
'#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';
$query =
preg_replace($newlineKeywords, '<br />  \\0', $query);
// Tables are identified by the prefix
=>
'<b class="dbg-operator">$1</b>',
// All uppercase words have a special meaning
'/(?<!\w|>)([A-Z_]{2,})(?!\w)/x'
=>
'<span class="dbg-command">$1</span>',
// Tables are identified by the prefix
=>
'<span class="dbg-table">$1</span>'
$query =
str_replace('*', '<b style="color: red;">*</b>', $query);
* Stolen from JError to prevent it's removal.
* @param Exception $error The error
* @return string Contents of the backtrace
$backtrace =
$error->getTrace();
$html[] =
'<table cellpadding="0" cellspacing="0">';
$html[] =
'<td colspan="3"><strong>Call stack</strong></td>';
$html[] =
'<th>Function</th>';
$html[] =
'<th>Location</th>';
for ($i =
count($backtrace) -
1; $i >=
0; $i--
)
if (isset
($backtrace[$i]['file']))
$link =
$this->formatLink($backtrace[$i]['file'], $backtrace[$i]['line']);
$html[] =
'<td>' .
$j .
'</td>';
if (isset
($backtrace[$i]['class']))
$html[] =
'<td>' .
$backtrace[$i]['class'] .
$backtrace[$i]['type'] .
$backtrace[$i]['function'] .
'()</td>';
$html[] =
'<td>' .
$backtrace[$i]['function'] .
'()</td>';
$html[] =
'<td>' .
$link .
'</td>';
* Replaces the Joomla! root with "JROOT" to improve readability.
* Formats a link with a special value xdebug.file_link_format
* @param string $file The full path to the file.
* @param string $line The line number.
$link .=
($line) ?
':' .
$line :
'';
$html =
'<a href="' .
$href .
'">' .
$link .
'</a>';
* Store log messages so they can be displayed later.
* This function is passed log entries by JLogLoggerCallback.
* @param JLogEntry $entry A log entry.
public function logger(JLogEntry $entry)
$this->logEntries[] =
$entry;
JLog::EMERGENCY =>
'EMERGENCY',
JLog::CRITICAL =>
'CRITICAL',
JLog::WARNING =>
'WARNING',
JLog::NOTICE =>
'NOTICE',
foreach ($this->logEntries as $entry)
$out[] =
'<h5>' .
$priorities[$entry->priority] .
' - ' .
$entry->category .
' </h5><code>' .
$entry->message .
'</code>';
return implode('<br /><br />', $out);
Documentation generated on Tue, 19 Nov 2013 14:58:03 +0100 by phpDocumentor 1.4.3