Index: trunk/core/kernel/utility/debugger.php
===================================================================
diff -u -N -r5104 -r6093
--- trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 5104)
+++ trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 6093)
@@ -79,6 +79,7 @@
$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start);
$this->profileStart('script_runtime', 'Script runtime', $start);
+ error_reporting(E_ALL);
ini_set('display_errors', $this->constOn('DBG_ZEND_PRESENT') ? 0 : 1); // show errors on screen in case if not in Zend Studio debugging
$this->scrollbarWidth = $this->isGecko() ? 22 : 25; // vertical scrollbar width differs in Firefox and other browsers
@@ -112,7 +113,7 @@
'DBG_IGNORE_STRICT_ERRORS' => 1, // ignore PHP5 errors about private/public view modified missing in class declarations
'DBG_DOMVIEWER' => '/temp/domviewer.html', // path to DOMViewer on website
'DOC_ROOT' => str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
- 'DBG_LOCAL_BASE_PATH' => 'w:' // replace DOC_ROOT in filenames (in errors) using this path
+ 'DBG_LOCAL_BASE_PATH' => 'w:', // replace DOC_ROOT in filenames (in errors) using this path
);
// only for IE, in case if no windows php script editor defined
@@ -144,7 +145,7 @@
$application =& kApplication::Instance();
// string used to separate debugger records while in file (used in debugger dump filename too)
- $this->rowSeparator = '@'.$application->GetSID().'@';
+ $this->rowSeparator = '@'.(is_object($application->Factory) ? $application->GetSID() : 0).'@';
// include debugger files from this url
$reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/';
@@ -190,7 +191,7 @@
break;
case 'var_dump':
- return $this->highlightString( print_r($Data['value'], true) );
+ return $this->highlightString( $this->print_r($Data['value'], true) );
break;
case 'trace':
@@ -216,10 +217,9 @@
$ret .= 'no file information available';
}
- // ensure parameter value is not longer then 200 symbols
if ($has_args) {
- $this->processTraceArguments($traceRec['args']);
- $args = $this->highlightString(print_r($traceRec['args'], true));
+ // if parameter value is longer then 200 symbols, then leave only first 50
+ $args = $this->highlightString($this->print_r($traceRec['args'], true, 50, 200));
$ret .= '
'.$args.'
';
}
$i++;
@@ -244,7 +244,14 @@
$div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width);
$ret = 'Name : '.$Data['description'].' ';
+
+ if (isset($Data['file'])) {
+ $ret .= '[Runtime : '.$runtime.'s] [File : '.$Data['file'].'] ';
+ }
+ else {
$ret .= 'Runtime : '.$runtime.'s ';
+ }
+
$ret .= '';
$ret .= '';
$ret .= '';
@@ -278,6 +285,7 @@
$skip_classes = Array(
defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication',
'kFactory',
+ 'kUnitConfigReader',
'TemplateParser',
);
@@ -290,41 +298,124 @@
return false;
}
- function processTraceArguments(&$traceArgs)
+ /**
+ * Advanced version of print_r (for debugger only). Don't print objects recursively
+ *
+ * @param Array $array
+ * @param bool $return_output return output or print it out
+ * @param int $cut_first cut first N symbols, don't cut anything if -1 specified
+ * @package int $cut_min_length cut only of this length of string or greather
+ * @return string
+ */
+ function print_r(&$array, $return_output = false, $cut_first = -1, $cut_min_length = -1)
{
- if (!$traceArgs) return '';
+ static $first_line = true, $tab_count = -1;
+
+ if (is_null($array)) {
+ return 'NULL';
+ }elseif (!is_array($array)) {
+ if ($cut_min_length != -1 && strlen($array) > $cut_min_length) {
+ $array = substr($array, 0, $cut_first).' ...';
+ }
+ return $array;
+ }
+
+ $output = '';
+
+ $tab_count++;
+ $output .= "Array\n".str_repeat(' ', $tab_count)."(\n";
+
+ $tab_count++;
+ $tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
+
+ $array_keys = array_keys($array);
- $array_keys = array_keys($traceArgs);
- foreach ($array_keys as $argID) {
- $argValue =& $traceArgs[$argID];
+ foreach ($array_keys as $key) {
+ switch (gettype($array[$key])) {
+ case 'array':
+ $output .= $tabsign.'['.$key.'] = '.$this->print_r($array[$key], true, 50, 200);
+ break;
- if (is_array($argValue) || is_object($argValue)) {
- if (is_object($argValue) && !in_array(get_class($argValue), $this->RecursionStack)) {
- array_push($this->RecursionStack, get_class($argValue));
+ case 'boolean':
+ $output .= $tabsign.'['.$key.'] = '.($array[$key] ? 'true' : 'false')."\n";
+ break;
- if ($this->IsBigObject($argValue)) {
- $argValue = null;
- continue;
+ case 'integer':
+ case 'double':
+ case 'string':
+ if ($cut_min_length != -1 && strlen($array[$key]) > $cut_min_length) {
+ $array[$key] = substr($array[$key], 0, $cut_first).' ...';
}
-
- // object & not in stack - ok
- settype($argValue, 'array');
- $this->processTraceArguments($argValue);
- array_pop($this->RecursionStack);
- }
- elseif (is_object($argValue) && in_array(get_class($argValue), $this->RecursionStack)) {
- // object & in stack - recursion
- $traceArgs[$argID] = '**** RECURSION ***';
- }
- else {
- // normal array here
- $this->processTraceArguments($argValue);
- }
+ $output .= $tabsign.'['.$key.'] = '.$array[$key]."\n";
+ break;
+
+ case 'NULL':
+ $output .= $tabsign.'['.$key."] = NULL\n";
+ break;
+
+ case 'object':
+ $attribute_names = get_class_vars( get_class($array[$key]) );
+ if (!$attribute_names) {
+ $output .= $tabsign.'['.$key."] = NO_ATTRIBUTES\n";
+ }
+ else {
+ if ($this->IsBigObject($array[$key])) {
+ $output .= $tabsign.'['.$key.'] = SKIPPED (class: '.get_class($array[$key]).")\n";
+ break;
+ }
+
+ // $attribute_value - default value for this attribute, not used here
+ foreach ($attribute_names as $attribute_name => $attribute_value) {
+ if (is_object($array[$key]->$attribute_name)) {
+ // it is object
+ $object_class = get_class($array[$key]->$attribute_name);
+ if (!in_array($object_class, $this->RecursionStack)) {
+ // object [not in recursion stack]
+ if ($this->IsBigObject($array[$key]->$attribute_name)) {
+ $output .= $tabsign.'['.$attribute_name.'] = SKIPPED (class: '.$object_class.")\n";
+ continue;
+ }
+
+ array_push($this->RecursionStack, $object_class);
+ $output .= $this->print_r($array[$key]->$attribute_name, true, 50, 200);
+ array_pop($this->RecursionStack);
+ }
+ else {
+ // object [in recursion stack]
+ $output .= $tabsign.'['.$attribute_name.'] = *** RECURSION *** (class: '.$object_class.")\n";
+ }
+ }
+ else {
+ $output .= $tabsign.'['.$attribute_name.'] = '.$this->print_r($array[$key]->$attribute_name, true, 50, 200)."\n";
+ }
+ }
+ }
+ break;
+
+ default:
+ $output .= $tabsign.'['.$key.'] unknown = '.gettype($array[$key])."\n";
+ break;
}
- else {
- $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
- }
}
+
+ $tab_count--;
+ $output .= str_repeat(' ', $tab_count).")\n";
+
+ if ($first_line) {
+ $first_line = false;
+ $output .= "\n";
+ }
+
+ $tab_count--;
+
+ if ($return_output) {
+ return $output;
+ }
+ else {
+ echo $output;
+ }
+
+ return true;
}
/**
@@ -388,7 +479,7 @@
function getFileLink($file, $lineno = 1, $title = '')
{
if (!$title) {
- $title = $file;
+ $title = str_replace('/', '\\', $this->getLocalFile($file));
}
if ($this->isGecko()) {
@@ -408,7 +499,7 @@
*/
function getLocalFile($remoteFile)
{
- return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);
+ return preg_replace('/^'.preg_quote(DOC_ROOT, '/').'/', DBG_LOCAL_BASE_PATH, $remoteFile, 1);
}
/**
@@ -419,6 +510,7 @@
{
$trace = debug_backtrace();
array_shift($trace);
+
$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
}
@@ -501,7 +593,7 @@
$this->appendHTML('ScriptName: '.$this->getFileLink($script, 1, basename($script)).' ('.dirname($script).' )');
if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 'yes') {
- $this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI']);
+ $this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI'].' (QS Length:'.strlen($_SERVER['QUERY_STRING']).')');
}
$this->appendHTML('DomViewer : Show ');
@@ -517,7 +609,7 @@
$value = 'no value ';
}
else {
- $value = htmlspecialchars(print_r($value, true));
+ $value = htmlspecialchars($this->print_r($value, true));
}
$in_cookie = isset($_COOKIE[$key]);
@@ -554,7 +646,23 @@
$this->ProfilerData[$key]['description'] = $description;
}
- $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
+ if (substr($key, 0, 4) == 'sql_') {
+ // append place from what was called
+ $trace_results = debug_backtrace();
+ $trace_count = count($trace_results);
+ $i = 0;
+ while ($i < $trace_count) {
+ $trace_file = basename($trace_results[$i]['file']);
+ if ($trace_file != 'db_connection.php' && $trace_file != 'adodb.inc.php') {
+ break;
+ }
+ $i++;
+ }
+ $this->ProfilerData[$key]['file'] = $trace_file.':'.$trace_results[$i]['line'];
+ unset($trace_results);
+ }
+
+ $this->Data[] = Array('profile_key' => $key, 'debug_type' => 'profiler');
}
function profileFinish($key, $description = null, $timeStamp = null)
@@ -639,13 +747,13 @@
*/
function printReport($returnResult = false, $clean_output_buffer = true)
{
- $this->profileFinish('script_runtime');
-
- $this->breakOutofBuffering();
if ($this->reportDone) {
- // don't print same report twice
+ // don't print same report twice (in case if shutdown function used + compression + fatal error)
return '';
}
+
+ $this->profileFinish('script_runtime');
+ $this->breakOutofBuffering();
$debugger_start = memory_get_usage();
@@ -656,12 +764,15 @@
$this->InitReport(); // set parameters required by AJAX
// defined here, because user can define this contant while script is running, not event before debugger is started
- $this->safeDefine('DBG_RAISE_ON_WARNINGS', 0);
-
+ $this->safeDefine('DBG_RAISE_ON_WARNINGS', 0);
+ $this->safeDefine('DBG_TOOLBAR_BUTTONS', 1);
+
$this->appendSession(); // show php session if any
// ensure, that 1st line of debug output always is this one:
- $this->appendHTML('[Reload Frame ] [Hide Debugger ] [Current Time: '.date('H:i:s').' ]');
+ $top_line = '';
+
+ $this->appendHTML($top_line);
$this->moveToBegin(1);
if ($this->constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) {
@@ -711,27 +822,35 @@
$this->appendHTML('Grand Total: '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
}
}*/
-
- $debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt';
- if (file_exists($debug_file)) unlink($debug_file);
-
- $i = 0;
- $fp = fopen($debug_file, 'a');
- $lineCount = count($this->Data);
- while ($i < $lineCount) {
- fwrite($fp, $this->prepareHTML($i).$this->rowSeparator);
- $i++;
+
+ $is_ajax = isset($_GET['ajax']) && $_GET['ajax'] == 'yes';
+ $skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT');
+
+ if ($is_ajax || !$skip_reporting) {
+ $debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt';
+ if (file_exists($debug_file)) unlink($debug_file);
+
+ $i = 0;
+ $fp = fopen($debug_file, 'a');
+ $lineCount = count($this->Data);
+ while ($i < $lineCount) {
+ fwrite($fp, $this->prepareHTML($i).$this->rowSeparator);
+ $i++;
+ }
+ fclose($fp);
}
- fclose($fp);
- // let debugger write report and then don't output anything
- if ($this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT')) return '';
+ if ($skip_reporting) {
+ // let debugger write report and then don't output anything
+ $this->reportDone = true;
+ return '';
+ }
ob_start();
?>
-
+
@@ -751,6 +870,9 @@
if ($this->IsFatalError || DBG_RAISE_ON_WARNINGS) {
echo '$Debugger.Toggle();';
}
+ if (DBG_TOOLBAR_BUTTONS) {
+ echo '$Debugger.AddToolbar("$Debugger");';
+ }
?>
window.focus();
@@ -766,7 +888,7 @@
if ($returnResult) {
$ret = ob_get_contents();
if ($clean_output_buffer) {
- ob_clean();
+ ob_end_clean();
}
$ret .= $this->getShortReport($memory_used);
@@ -812,19 +934,22 @@
break;
case 'PROFILE_TC': // profile totals record count
- $ret .= ''.$title.': '.$this->ProfilerTotalCount[$record_data].' ';
+ $record_cell = '';
+ if ($record_data == 'error_handling' && $this->ProfilerTotalCount[$record_data] > 0) {
+ $record_cell = ' ';
+ }
+ $ret .= ' '.$record_cell.$title.':'.$record_cell.''.$this->ProfilerTotalCount[$record_data].' ';
break;
case 'SEP':
$ret .= ' ';
break;
}
}
-
- return ' ';
+
+ return ' ';
}
-
/**
* User-defined error handler
*
@@ -866,26 +991,24 @@
$this->ProfilerData['error_handling']['ends'] = memory_get_usage();
$this->profilerAddTotal('error_handling', 'error_handling');
if (substr($errorType, 0, 5) == 'Fatal') {
- $this->breakOutofBuffering(false);
$this->IsFatalError = true;
- if (ob_get_level()) ob_flush();
- if (!$this->constOn('DBG_USE_SHUTDOWN_FUNC')) {
- $this->printReport();
- }
- exit;
+ // append debugger report to data in buffer & clean buffer afterwards
+ die( $this->breakOutofBuffering(false) . $this->printReport(true) );
}
}
function breakOutofBuffering($flush = true)
{
+ $buffer_content = Array();
while (ob_get_level()) {
- if ($flush) {
- ob_end_flush();
- }
- else {
- ob_end_clean();
- }
+ $buffer_content[] = ob_get_clean();
}
+ $ret = implode('', array_reverse($buffer_content));
+ if ($flush) {
+ echo $ret;
+ flush();
+ }
+ return $ret;
}
function saveToFile($msg)