$rq_value) { if( substr($rq_name,0,6)=='debug_' ) { dbg_safeDefine('DBG_ZEND_PRESENT', 1); break; } } dbg_safeDefine('DBG_ZEND_PRESENT',0); // 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', 'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack 'DBG_LOCAL_BASE_PATH'=>'w:'); 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')) { $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); }*/ class Debugger { /** * Debugger data for building report * * @var Array */ var $Data = Array(); var $ProfilerData = Array(); var $ProfilerTotals = Array(); var $ProfilerTotalCount = Array(); var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results var $TraceNextError=false; var $Options = 0; var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2, 'output_buffer' => 4, 'highlight_output' => 8); var $scrollbarWidth = 0; var $longErrors = Array(); /** * Amount of memory used by debugger itself * * @var Array * @access private */ var $memoryUsage = Array(); var $IncludesData = Array(); var $IncludeLevel = 0; var $reportDone = false; var $dummyImage = ''; function Debugger() { $this->dummyImage = PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').'/'.'kernel/admin_templates/img/spacer.gif'; $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4'); $this->profileStart('script_runtime', 'Script runtime'); ini_set('display_errors', dbg_ConstOn('DBG_ZEND_PRESENT') ? 0 : 1); $this->memoryUsage['error_handling'] = 0; // memory amount used by error handler $this->scrollbarWidth = $this->isGecko() ? 22 : 25; dbg_safeDefine('DBG_WINDOW_WIDTH', 700); $this->appendRequest(); } function initOptions() { } function mapLongError($msg) { $key=$this->generateID(); $this->longErrors[$key]=$msg; return $key; } function setOption($name,$value) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
'); if($value) { $this->Options|=$this->OptionsMap[$name]; } else { $this->Options=$this->Options&~$this->OptionsMap[$name]; } } function getOption($name) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
'); return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name]; } /** * Set's flag, that next error that occurs will * be prepended by backtrace results * */ function traceNext() { $this->TraceNextError = true; } function dumpVars() { $dumpVars = func_get_args(); foreach($dumpVars as $varValue) { $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump'); } } function prepareHTML($dataIndex) { $Data =& $this->Data[$dataIndex]; if($Data['debug_type'] == 'html') return $Data['html']; switch($Data['debug_type']) { case 'error': $fileLink = $this->getFileLink($Data['file'],$Data['line']); $ret = ''.$this->getErrorNameByCode($Data['no']).': '.$Data['str']; $ret .= ' in '.$fileLink.' on line '.$Data['line'].''; return $ret; break; case 'var_dump': return $this->highlightString( print_r($Data['value'], true) ); break; case 'trace': ini_set('memory_limit','500M'); $trace =& $Data['trace']; //return 'sorry'; //return $this->highlightString(print_r($trace,true)); $i = 0; $traceCount = count($trace); $ret = ''; while($i < $traceCount) { $traceRec =& $trace[$i]; $argsID = 'trace_args_'.$dataIndex.'_'.$i; $has_args = isset($traceRec['args']); if(isset($traceRec['file'])) { $func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function']; $args_link = $has_args ? 'Function' : 'Function'; $ret .= $args_link.': '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name); $ret .= ' in '.basename($traceRec['file']).' on line '.$traceRec['line'].'
'; } else { $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)); $ret .= ''; } $i++; } return $ret; break; case 'profiler': $profileKey = $Data['profile_key']; $Data =& $this->ProfilerData[$profileKey]; $runtime = ($Data['ends'] - $Data['begins']); // in seconds $totals_key = getArrayValue($Data, 'totalsKey'); if ($totals_key) { $total_before = $Data['totalsBefore']; $total = $this->ProfilerTotals[$totals_key]; $div_width = Array(); $div_width['before'] = ($total_before / $total) * $this->getWindowWidth(); $div_width['current'] = ($runtime / $total) * $this->getWindowWidth(); $div_width['left'] = (($total - $total_before - $runtime) / $total) * $this->getWindowWidth(); $ret = 'Name: '.$Data['description'].'
'; $ret .= 'Runtime: '.$runtime.'s'; $ret .= '
'; $ret .= '
'; $ret .= '
'; return $ret; } else { return 'Name: '.$Data['description'].'
Runtime: '.$runtime.'s'; } break; default: return 'incorrect debug data'; break; } } function getWindowWidth() { return DBG_WINDOW_WIDTH - $this->scrollbarWidth; } function isApplication(&$object) { $app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication'; return strtolower(get_class($object)) == $app_class; } function processTraceArguments(&$traceArgs) { 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) ) { array_push($this->RecursionStack, get_class($argValue)); if( strtolower(get_class($argValue)) == 'kfactory' || $this->isApplication($argValue) || strtolower(get_class($argValue)) == 'templateparser' ) { $argValue = null; continue; } // 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); } } else { $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]); } } } function cutStringForHTML($string) { if( strlen($string) > 200 ) $string = substr($string,0,50).' ...'; return $string; } /** * Format SQL Query using predefined formatting * and highlighting techniques * * @param string $sql * @return string */ 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); return $this->highlightString($sql); } function highlightString($string) { if( dbg_ConstOn('DBG_USE_HIGHLIGHT') ) { $string = str_replace( Array('\\', '/') , Array('_no_match_string_', '_n_m_s_'), $string); $string = highlight_string('', true); $string = str_replace( Array('_no_match_string_', '_n_m_s_'), Array('\\', '/'), $string); return preg_replace('/<\?(.*)php(.*)\?>/Us', '\\2', $string); } else { return $string; } } function isGecko() { return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false; } function getFileLink($file, $lineno = 1, $title = '') { if (!$title) $title = $file; if ($this->isGecko()) { return ''.$title.''; } else { return ''.$title.''; } } function getLocalFile($remoteFile) { return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile); } function appendTrace() { $trace = debug_backtrace(); array_shift($trace); $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace'); } function appendMemoryUsage($msg, $used=null) { if (!isset($used)) $used = round(memory_get_usage()/1024); $this->appendHTML('Memory usage '.$msg.' '.$used.'Kb'); } function appendHTML($html) { $this->Data[] = Array('html' => $html,'debug_type' => 'html'); } /** * Change debugger info that was already generated before. * Returns true if html was set. * * @param int $index * @param string $html * @param string $type = {'append','prepend','replace'} * @return bool */ function setHTMLByIndex($index,$html,$type='append') { if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' ) { return false; } switch ($type) { case 'append': $this->Data[$index]['html'] .= '
'.$html; break; case 'prepend': $this->Data[$index]['html'] = $this->Data[$index]['html'].'
'.$html; break; case 'replace': $this->Data[$index]['html'] = $html; break; } return true; } /** * Move $debugLineCount lines of input from debug output * end to beginning. * * @param int $debugLineCount */ function moveToBegin($debugLineCount) { $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount); $this->Data = array_merge($lines,$this->Data); } function moveAfterRow($new_row, $debugLineCount) { $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount); $rows_before = array_splice($this->Data,0,$new_row,$lines); $this->Data = array_merge($rows_before,$this->Data); } function appendRequest() { if (isset($_SERVER['SCRIPT_FILENAME'])) { $script = $_SERVER['SCRIPT_FILENAME']; } else { $script = $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']; } $this->appendHTML('ScriptName: '.$this->getFileLink($script,1,basename($script)).' ('.dirname($script).')'); $this->appendHTML('DomViewer:  '); ob_start(); ?> $value) { if( !is_array($value) && trim($value) == '' ) { $value = 'no value'; } else { $value = htmlspecialchars(print_r($value, true)); } $in_cookie = isset($_COOKIE[$key]); $src = isset($_GET[$key]) && !$in_cookie ? 'GE' : (isset($_POST[$key]) && !$in_cookie ? 'PO' : ($in_cookie ? 'CO' : '?') ); echo ''; } ?>
SrcNameValue
'.$src.''.$key.''.$value.'
appendHTML( ob_get_contents() ); ob_end_clean(); } function appendSession() { if( isset($_SESSION)&&$_SESSION ) { $this->appendHTML('PHP Session: ['.ini_get('session.name').']'); $this->dumpVars($_SESSION); $this->moveToBegin(2); } } function profileStart($key, $description = null) { $timeStamp = $this->getMoment(); $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data)); if (isset($description)) { $this->ProfilerData[$key]['description'] = $description; } $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler'); } function profileFinish($key, $description = null) { $this->ProfilerData[$key]['ends'] = $this->getMoment(); if (isset($description)) { $this->ProfilerData[$key]['description'] = $description; } } function profilerAddTotal($total_key, $key=null, $value=null) { if (!isset($this->ProfilerTotals[$total_key])) { $this->ProfilerTotals[$total_key] = 0; $this->ProfilerTotalCount[$total_key] = 0; } if (!isset($value)) { $value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins']; } if (isset($key)) { $this->ProfilerData[$key]['totalsKey'] = $total_key; $this->ProfilerData[$key]['totalsBefore'] = $this->ProfilerTotals[$total_key]; } $this->ProfilerTotals[$total_key] += $value; $this->ProfilerTotalCount[$total_key]++; } function getMoment() { list($usec, $sec) = explode(' ', microtime()); return ((float)$usec + (float)$sec); } function generateID() { list($usec, $sec) = explode(" ",microtime()); $id_part_1 = substr($usec, 4, 4); $id_part_2 = mt_rand(1,9); $id_part_3 = substr($sec, 6, 4); $digit_one = substr($id_part_1, 0, 1); if ($digit_one == 0) { $digit_one = mt_rand(1,9); $id_part_1 = ereg_replace("^0","",$id_part_1); $id_part_1=$digit_one.$id_part_1; } return $id_part_1.$id_part_2.$id_part_3; } function getErrorNameByCode($errorCode) { switch($errorCode) { case E_USER_ERROR: return 'Fatal Error'; break; case E_WARNING: case E_USER_WARNING: return 'Warning'; break; case E_NOTICE: case E_USER_NOTICE: return 'Notice'; break; case E_STRICT: return 'PHP5 Strict'; break; default: return ''; break; } } /** * Generates report * */ function printReport($returnResult = false, $clean_output_buffer = true) { $this->breakOutofBuffering(); if($this->reportDone) return ''; if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return; $this->profileFinish('script_runtime'); if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return; if (defined('SPACER_URL')) { $this->dummyImage = SPACER_URL; } dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0); $this->memoryUsage['debugger_start']=memory_get_usage(); // show php session if any $this->appendSession(); // ensure, that 1st line of debug output always is this one: $this->appendHTML('Hide Debugger'); $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_PROFILE_MEMORY') ) { $this->appendHTML('Memory used by Objects: '.round($this->ProfilerTotals['objects']/1024, 2).'Kb'); } 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)'); } } 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); if ( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ) { array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']); } foreach ($this->IncludesData['file'] as $key => $file_name) { $this->appendHTML( str_repeat(' -> ', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key])); if ($this->IncludesData['level'][$key] == 0) { $totals['mem'] += $this->IncludesData['mem'][$key]; $totals['time'] += $this->IncludesData['time'][$key]; } else if ($this->IncludesData['level'][$key] == -1) { $totals_configs['mem'] += $this->IncludesData['mem'][$key]; $totals_configs['time'] += $this->IncludesData['time'][$key]; } } $this->appendHTML('Sub-Total classes: '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time'])); $this->appendHTML('Sub-Total configs: '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time'])); $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); ob_start(); ?> 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(); $this->reportDone = true; return $ret; } else { if( !dbg_ConstOn('DBG_HIDE_FULL_REPORT') ) { $this->breakOutofBuffering(); } else { if($clean_output_buffer) ob_clean(); } if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport(); $this->reportDone = true; } } /** * Format's memory usage report by debugger * * @return string * @access private */ function getMemoryUsageReport() { if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return ''; $info = Array('printReport'=>'print_report', 'saveError'=>'error_handling', 'Total'=>'total', 'Application'=>'application'); $ret=Array(); foreach($info as $title => $value_key) { $ret[]=''.$title.':'.$this->formatSize($this->memoryUsage[$value_key]).''; } return ''.implode('',$ret).'
'; } /** * User-defined error handler * * @param int $errno * @param string $errstr * @param string $errfile * @param int $errline * @param array $errcontext */ function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '') { $memory_used=Array(); $memory_used['begin']=memory_get_usage(); $errorType = $this->getErrorNameByCode($errno); if(!$errorType) { trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR); return false; } 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) $long_id = $rets[2]; $errstr = $this->longErrors[$long_id]; unset($this->longErrors[$long_id]); } /*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line [PRE-PARSED block, $line 13]: Undefined variable: IdField*/ /* if( strpos($errfile,'runtime-created') !== false ) { $errfile = ' PRE-PARSED block '.$this->CurrentPreParsedBlock.' '; }*/ if( strpos($errfile,'eval()\'d code') !== false ) { $errstr = '[EVAL, line '.$errline.']: '.$errstr; $tmpStr = $errfile; $pos = strpos($tmpStr,'('); $errfile = substr($tmpStr,0,$pos); $pos++; $errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos); } // if($this->TraceNextError || $errno == E_USER_ERROR) if($this->TraceNextError) { $this->appendTrace(); $this->TraceNextError=false; } $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') { $this->breakOutofBuffering(false); echo ''; ob_flush(); if( !dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) $this->printReport(); exit; } } function breakOutofBuffering($flush=true) { while (ob_get_level()) { if ($flush) { ob_end_flush(); } else { ob_end_clean(); } } //ob_end_flush(); } function saveToFile($msg) { $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a'); fwrite($fp,$msg."\n"); fclose($fp); } /** * Formats file/memory size in nice way * * @param int $bytes * @return string * @access public */ function formatSize($bytes) { if ($bytes >= 1099511627776) { $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2); $suffix = "TB"; } elseif ($bytes >= 1073741824) { $return = round($bytes / 1024 / 1024 / 1024, 2); $suffix = "GB"; } elseif ($bytes >= 1048576) { $return = round($bytes / 1024 / 1024, 2); $suffix = "MB"; } elseif ($bytes >= 1024) { $return = round($bytes / 1024, 2); $suffix = "KB"; } else { $return = $bytes; $suffix = "Byte"; } $return .= ' '.$suffix; return $return; } function printConstants($constants) { if (!is_array($constants)) { $constants = explode(',', $constants); } $contant_tpl = '%s%s'; $ret = ''; foreach ($constants as $constant_name) { $ret .= sprintf($contant_tpl, $constant_name, constant($constant_name)); } $ret .= '
'; $this->appendHTML($ret); } } if( !function_exists('memory_get_usage') ) { function memory_get_usage(){ return -1; } } if( !dbg_ConstOn('DBG_ZEND_PRESENT') ) { $debugger = new Debugger(); } if( dbg_ConstOn('DBG_HANDLE_ERRORS') ) { if( class_exists('kApplication') ) { $application =& kApplication::Instance(); $application->Debugger =& $debugger; $application->errorHandlers[] = Array(&$debugger, 'saveError'); } else { set_error_handler( Array(&$debugger, 'saveError') ); } } if( dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) register_shutdown_function( Array(&$debugger, 'printReport') ); } ?>