$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 $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;
function Debugger()
{
$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->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 .= '
'.$args.'
';
}
$i++;
}
return $ret;
break;
case 'profiler':
$profileKey = $Data['profile_key'];
$Data =& $this->ProfilerData[$profileKey];
$runtime = ($Data['ends'] - $Data['begins']); // in seconds
return 'Name: '.$Data['description'].'
Runtime: '.$runtime.'s';
break;
default:
return 'incorrect debug data';
break;
}
}
function isApplication(&$object)
{
$app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication';
return 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( get_class($argValue) == 'kfactory' || $this->isApplication($argValue) || 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 (.*)\?>/s', '$2', $string);
}
else
{
return $string;
}
}
function getFileLink($file, $lineno = 1, $title = '')
{
if(!$title) $title = $file;
$is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
if($is_mozilla)
{
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();
?>
Src | Name | Value |
$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 ''.$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)
{
$timeStamp = $this->getMoment();
$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
$this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
}
function profileFinish($key)
{
$this->ProfilerData[$key]['ends'] = $this->getMoment();
}
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'];
}
$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)
{
if($this->reportDone) return '';
if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return;
$this->profileFinish('script_runtime');
if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return;
dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0);
dbg_safeDefine('DBG_WINDOW_WIDTH', 700);
$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);
if( !ob_get_length() ) ob_start();
?>
'.$this->prepareHTML($i).' | ';
$i++;
}
?>
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') )
{
ob_end_flush();
}
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 '';
}
/**
* 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;
$long_id_pos=strrpos($errstr,'#');
if($long_id_pos!==false)
{
// replace short message with long one (due triger_error limitations on message size)
$long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
$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')
{
echo '';
if( !dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) $this->printReport();
exit;
}
}
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;
}
}
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') );
}
?>