Index: trunk/core/kernel/utility/debugger.php =================================================================== diff -u -N -r4821 -r4823 --- trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 4821) +++ trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 4823) @@ -21,32 +21,32 @@ } } - dbg_safeDefine('DBG_ZEND_PRESENT', 0); + dbg_safeDefine('DBG_ZEND_PRESENT', 0); // set this constant value to 0 (zero) to debug debugger using Zend Studio // set default values for debugger constants $dbg_constMap = Array( - 'DBG_OPTIONS' => 0, - 'DBG_USE_HIGHLIGHT' => 1, - 'DBG_USE_SHUTDOWN_FUNC' => DBG_ZEND_PRESENT ? 0 : 1, - 'DBG_HANDLE_ERRORS' => DBG_ZEND_PRESENT ? 0 : 1, - 'DBG_IGNORE_STRICT_ERRORS' => 1, - 'DBG_DOMVIEWER' => '/temp/domviewer.html', + /*'DBG_OPTIONS' => 0,*/ + 'DBG_USE_HIGHLIGHT' => 1, // highlight output same as php code using "highlight_string" function + 'DBG_WINDOW_WIDTH' => 700, // set width of debugger window (in pixels) for better viewing large amount of debug data + 'DBG_USE_SHUTDOWN_FUNC' => DBG_ZEND_PRESENT ? 0 : 1, // use shutdown function to include debugger code into output + 'DBG_HANDLE_ERRORS' => DBG_ZEND_PRESENT ? 0 : 1, // handle all allowed by php (see php manual) errors instead of default handler + '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:' + 'DBG_LOCAL_BASE_PATH' => 'w:' // replace DOC_ROOT in filenames (in errors) using this path ); foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) { dbg_safeDefine($dbg_constName, $dbg_constValue); } // only for IE, in case if no windows php script editor defined - /*if(!defined('WINDOWS_EDITOR')) - { + /*if (!defined('DBG_EDITOR')) { $dbg_editor = 0; $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L'); - $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F'); - define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']); - unset($dbg_editors,$dbg_editor); + $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe', 'params' => '%F'); + define('DBG_EDITOR', $dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']); + unset($dbg_editors, $dbg_editor); }*/ class Debugger { @@ -95,10 +95,16 @@ var $reportDone = false; - var $dummyImage = ''; + /** + * Transparent spacer image used in case of none spacer image defined via SPACER_URL contant. + * Used while drawing progress bars (memory usage, time usage, etc.) + * + * @var string + */ + var $dummyImage = 'http://www.adamauto.lv/chevrolet/images/spacer.gif'; /** - * Folder for holding AJAX temporary file + * Temporary files created by debugger will be stored here * * @var string */ @@ -120,17 +126,14 @@ function Debugger() { - $this->dummyImage = PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').'/'.'kernel/admin_templates/img/spacer.gif'; - $this->tempFolder = FULL_PATH.'/kernel/cache'; - global $start; $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start); $this->profileStart('script_runtime', 'Script runtime', $start); - ini_set('display_errors', dbg_ConstOn('DBG_ZEND_PRESENT') ? 0 : 1); - $this->memoryUsage['error_handling'] = 0; // memory amount used by error handler + + ini_set('display_errors', dbg_ConstOn('DBG_ZEND_PRESENT') ? 0 : 1); // show errors on screen in case if not in Zend Studio debugging + $this->memoryUsage['error_handling'] = 0; // memory amount used by error handler - $this->scrollbarWidth = $this->isGecko() ? 22 : 25; - dbg_safeDefine('DBG_WINDOW_WIDTH', 700); + $this->scrollbarWidth = $this->isGecko() ? 22 : 25; // vertical scrollbar width differs in Firefox and other browsers $this->appendRequest(); } @@ -139,11 +142,17 @@ if (!class_exists('kApplication')) return false; $application =& kApplication::Instance(); + + // string used to separate debugger records while in file (used in debugger dump filename too) $this->rowSeparator = '@'.$application->GetSID().'@'; + // include debugger files from this url $reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/'; $kernel_path = preg_replace($reg_exp, '', KERNEL_PATH, 1); $this->baseURL = PROTOCOL.SERVER_NAME.rtrim(BASE_PATH, '/').$kernel_path.'/utility/debugger'; + + // save debug output in this folder + $this->tempFolder = FULL_PATH.'/kernel/cache'; } function mapLongError($msg) @@ -285,25 +294,42 @@ return DBG_WINDOW_WIDTH - $this->scrollbarWidth - 8; } - function isApplication(&$object) + /** + * Tells debugger to skip objects that are heavy in plan of memory usage while printing debug_backtrace results + * + * @param Object $object + * @return bool + */ + function IsBigObject(&$object) { - $app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication'; - return strtolower(get_class($object)) == $app_class; + $skip_classes = Array( + defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication', + 'kFactory', + 'TemplateParser', + ); + + foreach ($skip_classes as $class_name) { + if (strtolower(get_class($object)) == $class_name) { + return true; + } + } + + return false; } function processTraceArguments(&$traceArgs) { - if(!$traceArgs) return ''; + if (!$traceArgs) return ''; $array_keys = array_keys($traceArgs); foreach ($array_keys as $argID) { $argValue =& $traceArgs[$argID]; if (is_array($argValue) || is_object($argValue)) { - if (is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack)) { + if (is_object($argValue) && !in_array(get_class($argValue), $this->RecursionStack)) { array_push($this->RecursionStack, get_class($argValue)); - if (strtolower(get_class($argValue)) == 'kfactory' || $this->isApplication($argValue) || strtolower(get_class($argValue)) == 'templateparser') { + if ($this->IsBigObject($argValue)) { $argValue = null; continue; } @@ -313,7 +339,7 @@ $this->processTraceArguments($argValue); array_pop($this->RecursionStack); } - elseif (is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack)) { + elseif (is_object($argValue) && in_array(get_class($argValue), $this->RecursionStack)) { // object & in stack - recursion $traceArgs[$argID] = '**** RECURSION ***'; } @@ -328,6 +354,12 @@ } } + /** + * Returns only first 200 chars of string, this allow to save amount of data sent to browser + * + * @param string $string + * @return string + */ function cutStringForHTML($string) { if (strlen($string) > 200) { @@ -345,8 +377,8 @@ */ function formatSQL($sql) { - $sql = preg_replace('/(\n|\t| )+/is',' ',$sql); - $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql); + $sql = preg_replace('/(\n|\t| )+/is', ' ', $sql); + $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ", $sql); return $this->highlightString($sql); } @@ -362,11 +394,24 @@ return preg_replace('/<\?(.*)php(.*)\?>/Us', '\\2', $string); } + /** + * Determine by php type of browser used to show debugger + * + * @return bool + */ function isGecko() { return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false; } + /** + * Returns link for editing php file (from error) in external editor + * + * @param string $file filename with path from root folder + * @param int $lineno line number in file where error is found + * @param string $title text to show on file edit link + * @return string + */ function getFileLink($file, $lineno = 1, $title = '') { if (!$title) { @@ -377,11 +422,17 @@ return ''.$title.''; } else { - return ''.$title.''; + return ''.$title.''; } } + /** + * Converts filepath on server to filepath in mapped DocumentRoot on developer pc + * + * @param string $remoteFile + * @return string + */ function getLocalFile($remoteFile) { return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile); @@ -400,7 +451,9 @@ function appendMemoryUsage($msg, $used = null) { - if (!isset($used)) $used = round(memory_get_usage()/1024); + if (!isset($used)) { + $used = round(memory_get_usage() / 1024); + } $this->appendHTML('Memory usage '.$msg.' '.$used.'Kb'); } @@ -411,7 +464,7 @@ */ function appendHTML($html) { - $this->Data[] = Array('html' => $html,'debug_type' => 'html'); + $this->Data[] = Array('html' => $html, 'debug_type' => 'html'); } /** @@ -473,7 +526,7 @@ $script = $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']; } - $this->appendHTML('ScriptName: '.$this->getFileLink($script,1,basename($script)).' ('.dirname($script).')'); + $this->appendHTML('ScriptName: '.$this->getFileLink($script, 1, basename($script)).' ('.dirname($script).')'); $this->appendHTML('DomViewer:  '); @@ -499,13 +552,17 @@ ?> appendHTML( ob_get_contents() ); + $this->appendHTML(ob_get_contents()); ob_end_clean(); } + /** + * Appends php session content to debugger output + * + */ function appendSession() { - if(isset($_SESSION) && $_SESSION) { + if (isset($_SESSION) && $_SESSION) { $this->appendHTML('PHP Session: ['.ini_get('session.name').']'); $this->dumpVars($_SESSION); $this->moveToBegin(2); @@ -580,9 +637,24 @@ } - function getErrorNameByCode($errorCode) + function getErrorNameByCode($error_code) { - switch ($errorCode) { + $error_map = Array( + 'Fatal Error' => Array(E_USER_ERROR), + 'Warning' => Array(E_WARNING, E_USER_WARNING), + 'Notice' => Array(E_NOTICE, E_USER_NOTICE), + 'PHP5 Strict' => Array(E_STRICT), + ); + + foreach ($error_map as $error_name => $error_codes) { + if (in_array($error_code, $error_codes)) { + return $error_name; + } + } + + return ''; + + /*switch ($errorCode) { case E_USER_ERROR: return 'Fatal Error'; break; @@ -604,7 +676,7 @@ default: return ''; break; - } + }*/ } /** @@ -613,53 +685,57 @@ */ function printReport($returnResult = false, $clean_output_buffer = true) { - $this->breakOutofBuffering(); - if($this->reportDone) return ''; $this->profileFinish('script_runtime'); - if( dbg_ConstOn('DBG_SKIP_REPORTING') || dbg_ConstOn('DBG_ZEND_PRESENT')) return ''; + $this->breakOutofBuffering(); + if ($this->reportDone) { + // don't print same report twice + return ''; + } + + if (dbg_ConstOn('DBG_SKIP_REPORTING') || dbg_ConstOn('DBG_ZEND_PRESENT')) return ''; if (defined('SPACER_URL')) { $this->dummyImage = SPACER_URL; } - $this->InitReport(); + $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 dbg_safeDefine('DBG_RAISE_ON_WARNINGS', 0); $this->memoryUsage['debugger_start'] = memory_get_usage(); + + $this->appendSession(); // show php session if any - // show php session if any - $this->appendSession(); - // ensure, that 1st line of debug output always is this one: - $this->appendHTML('[Reload Frame] [Hide Debugger]'); + $this->appendHTML('[Reload Frame] [Hide Debugger] [Time: '.date('H:i:s').']'); $this->moveToBegin(1); - if(dbg_ConstOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) { - $this->appendHTML('SQL Total time: '.$this->ProfilerTotals['sql'].' Number of queries: '.$this->ProfilerTotalCount['sql']); + if (dbg_ConstOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) { + // sql query profiling was enabled -> show totals + $this->appendHTML('SQL Total time: '.$this->ProfilerTotals['sql'].' Number of queries: '.$this->ProfilerTotalCount['sql']); } if (dbg_ConstOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes'])) { + // included file profiling was enabled -> show totals $this->appendHTML('Included Files Total time: '.$this->ProfilerTotals['includes'].' Number of includes: '.$this->ProfilerTotalCount['includes']); } if (dbg_ConstOn('DBG_PROFILE_MEMORY')) { - $this->appendHTML('Memory used by Objects: '.round($this->ProfilerTotals['objects']/1024, 2).'Kb'); + // detailed memory usage reporting by objects was enabled -> show totals + $this->appendHTML('Memory used by Objects: '.round($this->ProfilerTotals['objects'] / 1024, 2).'Kb'); } - /*if( dbg_ConstOn('DBG_INCLUDED_FILES') ) - { + /*if (dbg_ConstOn('DBG_INCLUDED_FILES')) { $files = get_included_files(); $this->appendHTML('Included files:'); - foreach ($files as $file) - { - $this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)'); + foreach ($files as $file) { + $this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file) / 1024, 2).'Kb)'); } }*/ - /*if( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) - { + /*if (dbg_ConstOn('DBG_PROFILE_INCLUDES')) { $this->appendHTML('Included files statistics:'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':'')); $totals = Array( 'mem' => 0, 'time' => 0); $totals_configs = Array( 'mem' => 0, 'time' => 0); @@ -683,22 +759,18 @@ $this->appendHTML('Grand Total: '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time'])); } }*/ - - $i = 0; - $lineCount = count($this->Data); - $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); - - ob_start(); ?> @@ -715,7 +787,7 @@ var $Debugger = new Debugger(); $Debugger.IsFatalError = IsFatalError ? 'true' : 'false'; ?>; $Debugger.DOMViewerURL = ''; - $Debugger.EditorPath = ''; + $Debugger.EditorPath = ''; $Debugger.RowSeparator = 'rowSeparator; ?>'; $Debugger.DebugURL = 'baseURL.'/debugger_responce.php?sid='.$this->rowSeparator; ?>'; memoryUsage['debugger_finish'] = memory_get_usage(); + $this->memoryUsage['print_report'] = $this->memoryUsage['debugger_finish'] - $this->memoryUsage['debugger_start']; + $this->memoryUsage['total'] = $this->memoryUsage['print_report'] + $this->memoryUsage['error_handling']; + $this->memoryUsage['application'] = memory_get_usage() - $this->memoryUsage['total']; + - dbg_safeDefine('DBG_SHOW_MEMORY_USAGE', 1); - if(dbg_ConstOn('DBG_SHOW_MEMORY_USAGE')) { - $this->memoryUsage['debugger_finish'] = memory_get_usage(); - $this->memoryUsage['print_report'] = $this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start']; - $this->memoryUsage['total'] = $this->memoryUsage['print_report']+$this->memoryUsage['error_handling']; - $this->memoryUsage['application'] = memory_get_usage() - $this->memoryUsage['total']; - } - if ($returnResult) { $ret = ob_get_contents(); if ($clean_output_buffer) { ob_clean(); } - if (dbg_ConstOn('DBG_SHOW_MEMORY_USAGE')) { - $ret .= $this->getMemoryUsageReport(); - } + $ret .= $this->getMemoryUsageReport(); + $this->reportDone = true; return $ret; } @@ -753,10 +821,8 @@ elseif ($clean_output_buffer) { ob_clean(); } + echo $this->getMemoryUsageReport(); - if (dbg_ConstOn('DBG_SHOW_MEMORY_USAGE')) { - echo $this->getMemoryUsageReport(); - } $this->reportDone = true; } } @@ -769,8 +835,6 @@ */ function getMemoryUsageReport() { - if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return ''; - $info = Array( 'printReport' => 'print_report', 'saveError' => 'error_handling', @@ -785,7 +849,7 @@ $Data =& $this->ProfilerData['script_runtime']; $runtime = ($Data['ends'] - $Data['begins']); // in seconds - $ret .= 'Script runtime:'.sprintf('%.5f', $runtime).''; + $ret .= 'Script runtime:'.sprintf('%.5f', $runtime).'s'; return $ret; } @@ -810,7 +874,7 @@ return false; } - if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return; + if (dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT)) return; if (preg_match('/(.*)#([\d]+)$/', $errstr, $rets) ) { // replace short message with long one (due triger_error limitations on message size) @@ -831,7 +895,7 @@ $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error'); $memory_used['end'] = memory_get_usage(); $this->memoryUsage['error_handling'] += $memory_used['end'] - $memory_used['begin']; - if (substr($errorType,0,5) == 'Fatal') { + if (substr($errorType, 0, 5) == 'Fatal') { $this->breakOutofBuffering(false); $this->IsFatalError = true; ob_flush(); @@ -857,7 +921,7 @@ function saveToFile($msg) { $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a'); - fwrite($fp,$msg."\n"); + fwrite($fp, $msg."\n"); fclose($fp); }