1
0
mirror of https://github.com/e107inc/e107.git synced 2025-01-17 20:58:30 +01:00
php-e107/e107_handlers/db_debug_class.php
2023-01-03 08:46:19 -08:00

1281 lines
31 KiB
PHP

<?php
/*
+ ----------------------------------------------------------------------------+
| e107 website system
|
| Copyright (C) 2008-2009 e107 Inc (e107.org)
| http://e107.org
|
|
| Released under the terms and conditions of the
| GNU General Public License (http://gnu.org).
|
| $Source: /cvs_backup/e107_0.8/e107_handlers/db_debug_class.php,v $
| $Revision$
| $Date$
| $Author$
+----------------------------------------------------------------------------+
*/
if(!defined('e107_INIT'))
{
exit;
}
/**
*
*/
class e107_db_debug
{
private $active = false; // true when debug is active.
var $aSQLdetails = array(); // DB query analysis (in pieces for further analysis)
var $aDBbyTable = array();
var $aOBMarks = array(0 => ''); // Track output buffer level at each time mark
var $aMarkNotes = array(); // Other notes can be added and output...
var $aTimeMarks = array(); // Overall time markers
var $curTimeMark = 'Start';
var $nTimeMarks = 0; // Provide an array index for time marks. Stablizes 'current' function
var $aGoodQueries = array();
var $aBadQueries = array();
var $scbbcodes = array();
var $scbcount;
var $deprecated_funcs = array();
var $aLog = array(); // Generalized debug log (only seen during debug)
var $aIncList = array(); // Included files
function __construct()
{
}
/**
* Set the active status of the debug logging.
* When set to false, called methods within the class will by bypassed for better performance.
* @param $var
*/
public function active($var)
{
$this->active = (bool) $var;
}
/**
* Return a list of all registered time markers.
* @return array
*/
public function getTimeMarkers()
{
return $this->aTimeMarks;
}
/**
* Return a list of currently logged items
* @return array
*/
public function getLog()
{
return $this->aLog;
}
/**
* @return void
*/
function e107_db_debug()
{
global $eTimingStart;
$this->aTimeMarks[0] = array(
'Index' => 0,
'What' => 'Start',
'%Time' => 0,
'%DB Time' => 0,
'%DB Count' => 0,
'Time' => ($eTimingStart),
'DB Time' => 0,
'DB Count' => 0,
'Memory' => 0
);
register_shutdown_function('e107_debug_shutdown');
}
//
// Add your new Show function here so it will display in debug output!
//
/**
* @return void
*/
function Show_All()
{
$this->ShowIf('Debug Log', $this->Show_Log());
$this->ShowIf('Traffic Counters', e107::getSingleton('e107_traffic')->Display());
$this->ShowIf('Time Analysis', $this->Show_Performance());
$this->ShowIf('SQL Analysis', $this->Show_SQL_Details());
$this->ShowIf('Shortcodes / BBCode', $this->Show_SC_BB());
$this->ShowIf('Paths', $this->Show_PATH());
$this->ShowIf('Deprecated Methods/Functions', $this->Show_DEPRECATED());
if(E107_DBG_INCLUDES)
{
$this->aIncList = get_included_files();
}
$this->ShowIf('Included Files: ' . count($this->aIncList), $this->Show_Includes());
}
/**
* @param $title
* @param $str
* @return void
*/
function ShowIf($title, $str)
{
if(!empty($str))
{
//e107::getRender()->setStyle('debug');
echo "<h4>" . $title . "</h4>";
echo $str;
//e107::getRender()->tablerender($title, $str);
}
}
/**
* @param $sMarker
* @return void
*/
function Mark_Time($sMarker)
{
$this->logTime($sMarker);
}
/**
* Replacement for $sql->db_Mark_Time()
* @param string $sMarker - a descriptive marker for the log
* @return null
*/
public function logTime($sMarker)
{
if(!$this->active)
{
return null;
}
$timeNow = microtime();
$nMarks = ++$this->nTimeMarks;
// file_put_contents(e_LOG."debugClass.log",$nMarks."\t". $sMarker."\n", FILE_APPEND);
if(!strlen($sMarker))
{
$sMarker = "Mark not set";
}
$srch = array('[', ']');
$repl = array("<small>", "</small>");
$this->aTimeMarks[$nMarks] = array(
'Index' => ($this->nTimeMarks),
'What' => str_replace($srch, $repl, $sMarker),
'%Time' => 0,
'%DB Time' => 0,
'%DB Count' => 0,
'Time' => $timeNow,
'DB Time' => 0,
'DB Count' => 0,
'Memory' => ((function_exists("memory_get_usage")) ? memory_get_usage() : 0)
);
$this->aOBMarks[$nMarks] = ob_get_level() . '(' . ob_get_length() . ')';
$this->curTimeMark = $sMarker;
// Add any desired notes to $aMarkNotes[$nMarks]... e.g.
//global $eTimingStart;
//$this->aMarkNotes[$nMarks] .= "verify start: ".$eTimingStart."<br />";
}
/**
* @param $query
* @param $rli
* @param $origQryRes
* @param $aTrace
* @param $mytime
* @param $curtable
* @return null
*/
function Mark_Query($query, $rli, $origQryRes, $aTrace, $mytime, $curtable)
{
if(!$this->active)
{
return null;
}
// global $sql;
$sql = e107::getDb($rli);
// Explain the query, if possible...
list($qtype, $args) = explode(" ", ltrim($query), 2);
unset($args);
$nFields = 0;
$bExplained = false;
$ExplainText = '';
// Note the subtle bracket in the second comparison! Also, strcasecmp() returns zero on match
if(!strcasecmp($qtype, 'SELECT') || !strcasecmp($qtype, '(SELECT'))
{ // It's a SELECT statement - explain it
// $rli should always be set by caller
// $sQryRes = (is_null($rli) ? mysql_query("EXPLAIN {$query}") : mysql_query("EXPLAIN {$query}", $rli));
$sQryRes = $sql->gen("EXPLAIN {$query}");
if($sQryRes) // There's something to explain
{
//$nFields = mysql_num_fields($sQryRes);
$nFields = $sql->columnCount(); // mysql_num_fields($sQryRes);
$bExplained = true;
}
}
else
{ // Don't run 'EXPLAIN' on other queries
$sQryRes = $origQryRes; // Return from original query could be TRUE or a link resource if success
}
// Record Basic query info
$sCallingFile = varset($aTrace[2]['file']);
$sCallingLine = varset($aTrace[2]['line']);
$t = &$this->aSQLdetails[$sql->db_QueryCount()];
$t['marker'] = $this->curTimeMark;
$t['caller'] = "$sCallingFile($sCallingLine)";
$t['query'] = $query;
$t['ok'] = ($sQryRes !== false);
$t['error'] = $sQryRes ? '' : $sql->getLastErrorText(); // mysql_error();
$t['nFields'] = $nFields;
$t['time'] = $mytime;
if($bExplained)
{
$bRowHeaders = false;
// while ($row = @mysql_fetch_assoc($sQryRes))
while($row = $sql->fetch())
{
if(!$bRowHeaders)
{
$bRowHeaders = true;
$t['explain'] = "<tr><td><b>" . implode("</b></td><td><b>", array_keys($row)) . "</b></td></tr>\n";
}
$t['explain'] .= "<tr><td>" . implode("&nbsp;</td><td>", array_values($row)) . "&nbsp;</td></tr>\n";
}
}
else
{
$t['explain'] = $ExplainText;
}
$this->aTimeMarks[$this->nTimeMarks]['DB Time'] += $mytime;
$this->aTimeMarks[$this->nTimeMarks]['DB Count']++;
if(array_key_exists($curtable, $this->aDBbyTable))
{
$this->aDBbyTable[$curtable]['DB Time'] += $mytime;
$this->aDBbyTable[$curtable]['DB Count']++;
}
else
{
$this->aDBbyTable[$curtable]['Table'] = $curtable;
$this->aDBbyTable[$curtable]['%DB Time'] = 0; // placeholder
$this->aDBbyTable[$curtable]['%DB Count'] = 0; // placeholder
$this->aDBbyTable[$curtable]['DB Time'] = $mytime;
$this->aDBbyTable[$curtable]['DB Count'] = 1;
}
return null;
}
/**
* @param $force
* @return false|string
*/
function Show_SQL_Details($force = false)
{
global $sql;
//
// Show stats from aSQLdetails array
//
if(!E107_DBG_SQLQUERIES && !E107_DBG_SQLDETAILS && ($force === false))
{
return false;
}
$text = '';
$nQueries = $sql->db_QueryCount();
if(!$nQueries)
{
return $text;
}
//
// ALWAYS summarize query errors
//
$badCount = 0;
$okCount = 0;
foreach($this->aSQLdetails as $cQuery)
{
if($cQuery['ok'] == 1)
{
$okCount++;
}
else
{
$badCount++;
}
}
if($badCount)
{
$text .= "\n<table class='table table-striped table-bordered'>\n";
$text .= "<tr><th colspan='2'><b>$badCount Query Errors!</b></td></tr>\n";
$text .= "<tr><th><b>Index</b></td><th><b>Query / Error</b></td></tr>\n";
foreach($this->aSQLdetails as $idx => $cQuery)
{
if(!$cQuery['ok'])
{
$text .= "<tr><td rowspan='2' style='text-align:right'>{$idx}&nbsp;</td>
<td>" . $cQuery['query'] . "</td></tr>\n<tr><td>" . $cQuery['error'] . "</td></tr>\n";
}
}
$text .= "\n</table><br />\n";
}
//
// Optionally list good queries
//
if($okCount && E107_DBG_SQLDETAILS)
{
$text .= "\n<table class='table table-striped table-bordered'>\n";
$text .= "<tr><th colspan='3'><b>" . $this->countLabel($okCount) . " Good Queries</b></td></tr>\n";
$text .= "<tr><th><b>Index</b></td><th><b>Qtime</b></td><th><b>Query</b></td></tr>\n
<tr><th>&nbsp;</td><th><b>(msec)</b></td><th>&nbsp;</td></tr>\n
";
$count = 0;
foreach($this->aSQLdetails as $idx => $cQuery)
{
if($count > 500)
{
$text .= "<tr class='danger'><td colspan='6'><b>Too many queries. Ending... </b></td></tr>"; // NO LAN - debug only.
break;
}
if($cQuery['ok'])
{
$text .= "<tr><td style='text-align:right'>{$idx}&nbsp;</td>
<td style='text-align:right'>" . number_format($cQuery['time'] * 1000.0, 4) . "&nbsp;</td>
<td>" . $cQuery['query'] . '<br />[' . $cQuery['marker'] . " - " . $cQuery['caller'] . "]</td></tr>\n";
$count++;
}
}
$text .= "\n</table><br />\n";
}
//
// Optionally list query details
//
if(E107_DBG_SQLDETAILS)
{
$count = 0;
foreach($this->aSQLdetails as $idx => $cQuery)
{
$text .= "\n<table class='table table-striped table-bordered' style='width: 100%;'>\n";
$text .= "<tr><td colspan='" . $cQuery['nFields'] . "'><b>" . $idx . ") Query:</b> [" . $cQuery['marker'] . " - " . $cQuery['caller'] . "]<br />" . $cQuery['query'] . "</td></tr>\n";
if(isset($cQuery['explain']))
{
$text .= $cQuery['explain'];
}
if(strlen($cQuery['error']))
{
$text .= "<tr><td ><b>Error in query:</b></td></tr>\n<tr><td>" . $cQuery['error'] . "</td></tr>\n";
}
$text .= "<tr><td colspan='" . $cQuery['nFields'] . "'><b>Query time:</b> " . number_format($cQuery['time'] * 1000.0, 4) . ' (ms)</td></tr>';
$text .= '</table><br />' . "\n";
if($count > 500)
{
$text .= "<div class='alert alert-danger text-center'>Too many queries. Ending...</div>"; // NO LAN - debug only.
break;
}
$count++;
}
}
return $text;
}
/**
* @param $amount
* @return string
*/
function countLabel($amount)
{
$inc = '';
if($amount < 30)
{
$inc = 'label-success';
}
elseif($amount < 50)
{
$inc = 'label-warning';
}
elseif($amount > 49)
{
$inc = 'label-danger label-important';
}
return "<span class='label " . $inc . "'>" . $amount . "</span>";
}
/**
* @param $log
* @return void
*/
function save($log)
{
e107::getMessage()->addDebug("Saving a log");
$titles = array_keys($this->aTimeMarks[0]);
$text = implode("\t\t\t", $titles) . "\n\n";
foreach($this->aTimeMarks as $item)
{
$item['What'] = str_pad($item['What'], 50, " ", STR_PAD_RIGHT);
$text .= implode("\t\t\t", $item) . "\n";
}
file_put_contents($log, $text, FILE_APPEND);
}
/**
* @param $label
* @param $value
* @param $thresholdHigh
* @return mixed|string
*/
private function highlight($label, $value = 0, $thresholdHigh = 0)
{
if($value > $thresholdHigh)
{
return "<span class='label label-danger' style='font-size:0.9em'>" . $label . "</span>";
}
if($value == 0)
{
return "<span class='label label-success'>" . $label . "</span>";
}
return $label;
}
/**
* @return string
*/
function Show_Performance()
{
//
// Stats by Time Marker
//
global $db_time;
global $sql;
global $eTimingStart, $eTimingStop;
$this->Mark_Time('Stop');
if(!E107_DBG_TIMEDETAILS)
{
return '';
}
$totTime = e107::getSingleton('e107_traffic')->TimeDelta($eTimingStart, $eTimingStop);
$text = "\n<table class='table table-striped table-condensed'>\n";
$bRowHeaders = false;
reset($this->aTimeMarks);
$aSum = $this->aTimeMarks[0]; // create a template from the 'real' array
$aSum['Index'] = '';
$aSum['What'] = 'Total';
$aSum['Time'] = 0;
$aSum['DB Time'] = 0;
$aSum['DB Count'] = 0;
$aSum['Memory'] = 0;
// Calculate Memory Usage per entry.
$prevMem = 0;
foreach($this->aTimeMarks as $k => $v)
{
$prevKey = $k - 1;
if(!empty($prevKey))
{
$this->aTimeMarks[$prevKey]['Memory Used'] = (intval($v['Memory']) - $prevMem);
}
$prevMem = intval($v['Memory']);
}
$obj = new ArrayObject($this->aTimeMarks);
$it = $obj->getIterator();
$head = '';
// while(list($tKey, $tMarker) = each($this->aTimeMarks))
foreach ($it as $tKey=>$tMarker)
{
if(!$bRowHeaders)
{
// First time: emit headers
$bRowHeaders = true;
$head = "<tr><th style='text-align:right'><b>" . implode("</b>&nbsp;</td><th style='text-align:right'><b>", array_keys($tMarker)) . "</b>&nbsp;</td><th style='text-align:right'><b>OB Lev&nbsp;</b></td></tr>\n";
$aUnits = $tMarker;
foreach($aUnits as $key => $val)
{
switch($key)
{
case 'DB Time':
case 'Time':
$aUnits[$key] = '(msec)';
break;
default:
$aUnits[$key] = '';
break;
}
}
$aUnits['OB Lev'] = 'lev(buf bytes)';
$aUnits['Memory'] = '(kb)';
$aUnits['Memory Used'] = '(kb)';
$head .= "<tr><th style='text-align:right'><small>" . implode("</small>&nbsp;</td><th style='text-align:right'><small>", $aUnits) . "</small>&nbsp;</td></tr>\n";
$text .= $head;
}
// $tMem = ($tMarker['Memory'] - $aSum['Memory']);
$tMem = ($tMarker['Memory']);
// if($tMem < 0) // Quick Fix for negative numbers.
// {
// $tMem = 0.0000000001;
// }
$tMarker['Memory'] = ($tMem ? number_format($tMem / 1024.0, 1) : '?'); // display if known
$tUsage = $tMarker['Memory Used'];
$tMarker['Memory Used'] = number_format($tUsage / 1024.0, 1);
$tMarker['Memory Used'] = $this->highlight($tMarker['Memory Used'], $tUsage, 400000);
/*
if($tUsage > 400000) // Highlight high memory usage.
{
$tMarker['Memory Used'] = "<span class='label label-danger'>".$tMarker['Memory Used']."</span>";
}*/
$aSum['Memory'] = $tMem;
if($tMarker['What'] === 'Stop')
{
$tMarker['Time'] = '&nbsp;';
$tMarker['%Time'] = '&nbsp;';
$tMarker['%DB Count'] = '&nbsp;';
$tMarker['%DB Time'] = '&nbsp;';
$tMarker['DB Time'] = '&nbsp;';
$tMarker['OB Lev'] = $this->aOBMarks[$tKey];
$tMarker['DB Count'] = '&nbsp;';
}
else
{
// Convert from start time to delta time, i.e. from now to next entry
// $nextMarker = current($this->aTimeMarks);
$it->next();
$nextMarker = $it->current();
$it->seek($tKey - 1); // go back one position.
$aNextT = $nextMarker['Time'];
$aThisT = $tMarker['Time'];
$thisDelta = e107::getSingleton('e107_traffic')->TimeDelta($aThisT, $aNextT);
$aSum['Time'] += $thisDelta;
$aSum['DB Time'] += $tMarker['DB Time'];
$aSum['DB Count'] += $tMarker['DB Count'];
$tMarker['Time'] = number_format($thisDelta * 1000.0, 1);
$tMarker['Time'] = $this->highlight($tMarker['Time'], $thisDelta, .2);
$tMarker['%Time'] = $totTime ? number_format(100.0 * ($thisDelta / $totTime), 0) : 0;
$tMarker['%Time'] = $this->highlight($tMarker['%Time'], $tMarker['%Time'], 20);
$tMarker['%DB Count'] = number_format(100.0 * $tMarker['DB Count'] / $sql->db_QueryCount(), 0);
$tMarker['%DB Time'] = $db_time ? number_format(100.0 * $tMarker['DB Time'] / $db_time, 0) : 0;
// $tMarker['DB Time'] = number_format($tMarker['DB Time'] * 1000.0, 1);
$dbTime = number_format($tMarker['DB Time'] * 1000.0, 1);
$tMarker['DB Time'] = $this->highlight($dbTime,$dbTime, 10);
$tMarker['OB Lev'] = $this->aOBMarks[$tKey];
}
$text .= "<tr><td >" . implode("&nbsp;</td><td style='text-align:right'>", array_values($tMarker)) . "&nbsp;</td></tr>\n";
if(isset($this->aMarkNotes[$tKey]))
{
$text .= "<tr><td >&nbsp;</td><td colspan='4'>";
$text .= $this->aMarkNotes[$tKey] . "</td></tr>\n";
}
if($tMarker['What'] === 'Stop')
{
break;
}
}
$text .= $head;
$aSum['%Time'] = $totTime ? number_format(100.0 * ($aSum['Time'] / $totTime), 0) : 0;
$aSum['%DB Time'] = $db_time ? number_format(100.0 * ($aSum['DB Time'] / $db_time), 0) : 0;
$aSum['%DB Count'] = ($sql->db_QueryCount()) ? number_format(100.0 * ($aSum['DB Count'] / ($sql->db_QueryCount())), 0) : 0;
$aSum['Time'] = number_format($aSum['Time'] * 1000.0, 1);
$aSum['DB Time'] = number_format($aSum['DB Time'] * 1000.0, 1);
$text .= "<tr>
<th>&nbsp;</td>
<th style='text-align:right'><b>Total</b></td>
<th style='text-align:right'><b>" . $aSum['%Time'] . "</b></td>
<th style='text-align:right'><b>" . $aSum['%DB Time'] . "</b></td>
<th style='text-align:right'><b>" . $aSum['%DB Count'] . "</b></td>
<th style='text-align:right' title='Time (msec)'><b>" . $aSum['Time'] . "</b></td>
<th style='text-align:right' title='DB Time (msec)'><b>" . $aSum['DB Time'] . "</b></td>
<th style='text-align:right'><b>" . $aSum['DB Count'] . "</b></td>
<th style='text-align:right' title='Memory (Kb)'><b>" . number_format($aSum['Memory'] / 1024, 1) . "</b></td>
<th style='text-align:right' title='Memory (Kb)'><b>" . number_format($aSum['Memory'] / 1024, 1) . "</b></td>
<th style='text-align:right'><b>" . $tMarker['OB Lev'] . "</b></td>
</tr>
";
// $text .= "<tr><th><b>".implode("</b>&nbsp;</td><th style='text-align:right'><b>", $aSum)."</b>&nbsp;</td><th>&nbsp;</td></tr>\n";
$text .= "\n</table><br />\n";
//
// Stats by Table
//
$text .= "\n<table class='table table-striped table-condensed'>
<colgroup>
<col style='width:auto' />
<col style='width:9%' />
<col style='width:9%' />
<col style='width:9%' />
<col style='width:9%' />
</colgroup>\n";
$bRowHeaders = false;
$aSum = $this->aDBbyTable['core']; // create a template from the 'real' array
$aSum['Table'] = 'Total';
$aSum['%DB Time'] = 0;
$aSum['%DB Count'] = 0;
$aSum['DB Time'] = 0;
$aSum['DB Count'] = 0;
foreach($this->aDBbyTable as $curTable)
{
if(!$bRowHeaders)
{
$bRowHeaders = true;
$text .= "<tr><th><b>" . implode("</b></td><th style='text-align:right'><b>", array_keys($curTable)) . "</b></td></tr>\n";
$aUnits = $curTable;
foreach($aUnits as $key => $val)
{
switch($key)
{
case 'DB Time':
$aUnits[$key] = '(msec)';
break;
default:
$aUnits[$key] = '';
break;
}
}
$text .= "<tr><th style='text-align:right'><b>" . implode("</b>&nbsp;</td><th style='text-align:right'><b>", $aUnits) . "</b>&nbsp;</td></tr>\n";
}
$aSum['DB Time'] += $curTable['DB Time'];
$aSum['DB Count'] += $curTable['DB Count'];
$curTable['%DB Count'] = number_format(100.0 * $curTable['DB Count'] / $sql->db_QueryCount(), 0);
$curTable['%DB Time'] = number_format(100.0 * $curTable['DB Time'] / $db_time, 0);
$timeLabel = number_format($curTable['DB Time'] * 1000.0, 1);
$curTable['DB Time'] = $this->highlight($timeLabel, ($curTable['DB Time'] * 1000), 500); // 500 msec
$text .= "<tr><td>" . implode("&nbsp;</td><td style='text-align:right'>", array_values($curTable)) . "&nbsp;</td></tr>\n";
}
$aSum['%DB Time'] = $db_time ? number_format(100.0 * ($aSum['DB Time'] / $db_time), 0) : 0;
$aSum['%DB Count'] = ($sql->db_QueryCount()) ? number_format(100.0 * ($aSum['DB Count'] / ($sql->db_QueryCount())), 0) : 0;
$aSum['DB Time'] = number_format($aSum['DB Time'] * 1000.0, 1);
$text .= "<tr><th><b>" . implode("&nbsp;</td><th style='text-align:right'><b>", array_values($aSum)) . "&nbsp;</b></td></tr>\n";
$text .= "\n</table><br />\n";
return $text;
}
/**
* @param $message
* @param $file
* @param $line
* @return void|null
*/
function logDeprecated($message=null, $file=null, $line=null)
{
if(!empty($message) || !empty($file))
{
$this->deprecated_funcs[] = array(
'func' => $message,
'file' => $file,
'line' => $line
);
return null;
}
$back_trace = debug_backtrace();
// print_r($back_trace);
$this->deprecated_funcs[] = array(
'message' => varset($message),
'func' => (isset($back_trace[1]['type']) && ($back_trace[1]['type'] === '::' || $back_trace[1]['type'] === '->') ? $back_trace[1]['class'] . $back_trace[1]['type'] . $back_trace[1]['function'] : $back_trace[1]['function']),
'file' => $back_trace[1]['file'],
'line' => $back_trace[1]['line']
);
}
/**
* @param $type
* @param $code
* @param $parm
* @param $details
* @return false|null
*/
function logCode($type, $code, $parm, $details)
{
if(!E107_DBG_BBSC || !$this->active)
{
return false;
}
$this->scbbcodes[$this->scbcount]['type'] = $type;
$this->scbbcodes[$this->scbcount]['code'] = $code;
$this->scbbcodes[$this->scbcount]['parm'] = is_array($parm) ? var_export($parm, true) : (string) $parm;
$this->scbbcodes[$this->scbcount]['details'] = $details;
$this->scbcount++;
return null;
}
/**
* @param $force
* @return false|string
*/
function Show_SC_BB($force = false)
{
if(!E107_DBG_BBSC && ($force === false))
{
return false;
}
$text = "<table class='table table-striped table-condensed' style='width: 100%'>
<thead>
<tr>
<th style='width: 10%;'>Type</th>
<th style='width: 30%;'>Code</th>
<th style='width: 20%;'>Parm</th>
<th style='width: 40%;'>Details</th>
</tr>
</thead>
<tbody>\n";
$description = array(1 => 'Bbcode', 2 => 'Shortcode', 3 => 'Wrapper', 4 => 'Shortcode Override', -2 => 'Shortcode Failure');
$style = array(1 => 'label-info', 2 => 'label-primary', 3 => 'label-warning', 'label-danger', -2 => 'label-danger');
foreach($this->scbbcodes as $codes)
{
$type = $codes['type'];
$text .= "<tr>
<td style='width: 10%;'><span class='label " . $style[$type] . "'>" . ($description[$type]) . "</span></td>
<td style='width: auto;'>" . (isset($codes['code']) ? $codes['code'] : "&nbsp;") . "</td>
<td style='width: auto;'>" . ($codes['parm'] ? $codes['parm'] : "&nbsp;") . "</td>
<td style='width: 40%;'>" . ($codes['details'] ? $codes['details'] : "&nbsp;") . "</td>
</tr>\n";
}
$text .= "</tbody></table>";
return $text;
}
/**
* @param $value
* @return bool
*/
private function includeVar($value)
{
$prefix = array('ADMIN', 'E_', 'e_', 'E107', 'SITE', 'USER', 'CORE');
foreach($prefix as $c)
{
if(strpos($value, $c) === 0)
{
return true;
}
}
return false;
}
/**
* @param $force
* @return false|string
*/
function Show_PATH($force = false)
{
if(!E107_DBG_PATH && ($force === false))
{
return false;
}
$e107 = e107::getInstance();
$sql = e107::getDb();
$text = "<table class='table table-striped table-condensed debug-footer' style='width:100%'>
<colgroup>
<col style='width:20%' />
<col style='width:auto' />
</colgroup>
<thead>
<tr>
<th class='debug-footer-caption left' colspan='2'><b>Paths &amp; Variables</b></th>
</tr>
</thead>
<tbody>\n";
$inc = array(
'BOOTSTRAP', 'HEADERF', 'FOOTERF', 'FILE_UPLOADS', 'FLOODPROTECT', 'FLOODTIMEOUT', 'FONTAWESOME', 'CHARSET',
'GUESTS_ONLINE', 'MEMBERS_ONLINE', 'PAGE_NAME', 'STANDARDS_MODE', 'TIMEOFFSET',
'TOTAL_ONLINE', 'THEME', 'THEME_ABS', 'THEME_LAYOUT', 'THEME_LEGACY', 'THEME_VERSION', 'THEME_STYLE', 'META_OG', 'META_DESCRIPTION', 'MPREFIX', 'VIEWPORT', 'BODYTAG', 'CSSORDER'
);
$userCon = get_defined_constants(true);
ksort($userCon['user']);
$c = 0;
foreach($userCon['user'] as $k => $v)
{
if(E107_DBG_ALLERRORS || in_array($k, $inc) || $this->includeVar($k))
{
$text .= "
<tr>
<td>" . $k . "</td>
<td>" . (is_string($v) ? htmlspecialchars($v) : $v). "</td>
</tr>";
$c++;
}
}
$sess = e107::getSession();
$text .= "
<tr>
<td>SQL Language</td>
<td>" . $sql->mySQLlanguage . "</td>
</tr>
";
if($_SERVER['E_DEV'] == 'true')
{
$text .= "
<tr>
<th colspan='2'><h2>e107 Object</h2></td>
</tr>";
foreach($e107 as $key=>$val)
{
$text .= "
<tr>
<td>".$key."</td>
<td><pre>" . htmlspecialchars(print_r($val, true)) . "</pre></td>
</tr>";
}
}
$text .= "
<tr>
<th colspan='2'><h2>Registry</h2></td>
</tr>";
$regis = e107::getRegistry('_all_');
ksort($regis);
$c = 0;
foreach($regis as $key=>$val)
{
$id = "view-registry-".$c;
$text .= "<tr>
<td>".$key."</td>
<td><a href='#".$id."' class='btn btn-sm btn-default e-expandit'>View</a><div id='".$id."' class='e-hideme'>" . print_a($val,true). "</div></td>
</tr>";
$c++;
}
$text .= "
<tr>
<th colspan='2'><h2>Session</h2></td>
</tr>
<tr>
<td>Session lifetime</td>
<td>" . $sess->getOption('lifetime') . " seconds</td>
</tr>
<tr>
<td>Session domain</td>
<td>" . $sess->getOption('domain') . "</td>
</tr>
<tr>
<td>Session save method</td>
<td>" . $sess->getSaveMethod() . "</td>
</tr>
<tr>
<td>Registry</td>
<td>" . $sess->getSaveMethod() . "</td>
</tr>
<tr>
<td colspan='2'><pre>" . htmlspecialchars(print_r($_SESSION, true)) . "</pre></td>
</tr>
</tbody>
</table>";
return $text;
}
/**
* @param $force
* @return false|string
*/
function Show_DEPRECATED($force = false)
{
if(!E107_DBG_DEPRECATED && ($force === false))
{
return false;
}
$text = "
<table class='table table-striped table-condensed' style='width: 100%'>
<thead>
<tr>
<th style='width: 40%;'>Info</th>
<th style='width: 30%;'>File</th>
<th>Line</th>
</tr>
</thead>
<tbody>\n";
if(empty($this->deprecated_funcs))
{
$text .= "<tr>
<td colspan='3'><span class='label label-success'>None Found</span></td>
</tr>";
}
else
{
// $unique = array_unique($this->deprecated_funcs);
foreach($this->deprecated_funcs as $funcs)
{
$text .= "<tr>
<td>{$funcs['func']}</td>
<td>".(is_array($funcs['file']) ? print_a($funcs['file'],true) : $funcs['file'])."</td>
<td>{$funcs['line']}</td>
</tr>\n";
}
}
$text .= "</tbody></table>";
return $text;
}
/**
* var_dump to debug log
*
* @param mixed $message
*/
function dump($message, $TraceLev = 1)
{
ob_start();
var_dump($message);
$content = ob_get_clean();
$bt = debug_backtrace();
$this->aLog[] = array(
'Message' => $content,
'Function' => (isset($bt[$TraceLev]['type']) && ($bt[$TraceLev]['type'] == '::' || $bt[$TraceLev]['type'] == '->') ? $bt[$TraceLev]['class'] . $bt[$TraceLev]['type'] . $bt[$TraceLev]['function'] . '()' : $bt[$TraceLev]['function']) . '()',
'File' => varset($bt[$TraceLev]['file']),
'Line' => varset($bt[$TraceLev]['line'])
);
// $this->aLog[] = array ('Message' => $content, 'Function' => '', 'File' => '', 'Line' => '' );
}
/**
* @desc Simple debug-level 'console' log
* Record a "nice" debug message with
* $db_debug->log("message");
* @param string|array $message
* @param int $TraceLev
* @return bool true on success , false on error
*/
public function log($message, $TraceLev = 1)
{
if(!$this->active)
{
return null;
}
if(!is_string($message))
{
$message = "<pre>" . var_export($message, true) . "</pre>";
}
if(!deftrue('E107_DBG_BASIC') && !deftrue('E107_DBG_ALLERRORS') && !deftrue('E107_DBG_SQLDETAILS') && !deftrue('E107_DBG_NOTICES'))
{
return false;
}
if($TraceLev)
{
$bt = debug_backtrace();
$this->aLog[] = array(
'Message' => $message,
'Function' => (isset($bt[$TraceLev]['type']) && ($bt[$TraceLev]['type'] == '::' || $bt[$TraceLev]['type'] == '->') ? $bt[$TraceLev]['class'] . $bt[$TraceLev]['type'] . $bt[$TraceLev]['function'] . '()' : $bt[$TraceLev]['function']) . '()',
'File' => varset($bt[$TraceLev]['file']),
'Line' => varset($bt[$TraceLev]['line'])
);
}
else
{
$this->aLog[] = array(
'Message' => $message,
'Function' => '',
'File' => '',
'Line' => ''
);
}
return true;
}
/**
* @return bool|string
*/
function Show_Log()
{
if(empty($this->aLog))
{
return false;
}
//
// Dump the debug log
//
$text = "\n<table class='table table-striped'>\n";
$bRowHeaders = false;
foreach($this->aLog as $curLog)
{
if(!$bRowHeaders)
{
$bRowHeaders = true;
$text .= "<tr><th style='text-align:left'><b>" . implode("</b></td><th style='text-align:left'><b>", array_keys($curLog)) . "</b></td></tr>\n";
}
$text .= "<tr ><td>" . implode("&nbsp;</td><td>", array_values($curLog)) . "&nbsp;</td></tr>\n";
}
$text .= "</table><br />\n";
return $text;
}
/**
* @param $force
* @return false|string
*/
function Show_Includes($force = false)
{
if(!E107_DBG_INCLUDES && ($force === false))
{
return false;
}
$text = "<table class='table table-striped'>\n";
$text .= "<tr><td>" .
implode("&nbsp;</td></tr>\n<tr><td>", $this->aIncList) .
"&nbsp;</td></tr>\n";
$text .= "</table>\n";
return $text;
}
}
//
// Helper functions (not part of the class)
//
/**
* @return void
*/
function e107_debug_shutdown()
{
if(e_AJAX_REQUEST) // extra output will break json ajax returns ie. comments
{
return;
}
global $error_handler;
if(!empty($GLOBALS['E107_CLEAN_EXIT']))
{
return;
}
if(empty($GLOBALS['E107_IN_FOOTER']))
{
$ADMIN_DIRECTORY = e107::getFolder('admin');
if(deftrue('ADMIN_AREA'))
{
$filewanted = realpath(__DIR__) . '/../' . $ADMIN_DIRECTORY . 'footer.php';
require_once($filewanted);
}
elseif(deftrue('USER_AREA'))
{
$filewanted = realpath(__DIR__) . '/../' . FOOTERF;
require_once($filewanted);
}
}
//
// Error while in the footer, or during startup, or during above processing
//
if(!empty($GLOBALS['E107_CLEAN_EXIT']))
{
return;
}
while(ob_get_level() > 0)
{
ob_end_flush();
}
if(isset($error_handler))
{
if($error_handler->return_errors())
{
echo "<br /><div 'e107_debug php_err'><h3>PHP Errors:</h3><br />" . $error_handler->return_errors() . "</div>\n";
echo "</body></html>";
}
}
else
{
echo "<b>e107 Shutdown while no error_handler available!</b>";
echo "</body></html>";
}
}