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 .= ''; } $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:  '); @@ -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 = '
[Reload Frame] [Hide Debugger][Current Time: '.date('H:i:s').'] [File Size: #DBG_FILESIZE#]
'; + + $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(); ?> - +