Index: trunk/core/kernel/utility/debugger.php =================================================================== diff -u -N --- trunk/core/kernel/utility/debugger.php (revision 8860) +++ trunk/core/kernel/utility/debugger.php (revision 0) @@ -1,1303 +0,0 @@ -$dbg_options array instead'); - } - - // check IP before enabling debug mode - $ip_match = $this->ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : ''); - - if (!$ip_match) { - define('DEBUG_MODE', 0); - return ; - } - - // debug is allowed for user, continue initialization - $this->InitDebugger(); - $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 - $this->appendRequest(); - } - - /** - * Checks, that user IP address is within allowed range - * - * @param string $ip_list semi-column (by default) separated ip address list - * @param string $separator ip address separator (default ";") - * - * @return bool - */ - function ipMatch($ip_list, $separator = ';') - { - $ip_match = false; - $ip_addresses = $ip_list ? explode($separator, $ip_list) : Array (); - foreach ($ip_addresses as $ip_address) { - if ($this->netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) { - $ip_match = true; - break; - } - } - - return $ip_match; - } - - /** - * Set's default values to constants debugger uses - * - */ - function InitDebugger() - { - global $dbg_options; - - unset($_REQUEST['debug_host'], $_REQUEST['debug_fastfile'], $dbg_options['DBG_IP']); // this var messed up whole detection stuff :( - - // Detect fact, that this session beeing debugged by Zend Studio - foreach ($_REQUEST as $rq_name => $rq_value) { - if (substr($rq_name, 0, 6) == 'debug_') { - $this->safeDefine('DBG_ZEND_PRESENT', 1); - break; - } - } - - $this->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_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:', // replace DOC_ROOT in filenames (in errors) using this path - ); - - // only for IE, in case if no windows php script editor defined - if (!defined('DBG_EDITOR')) { -// $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\UltraEdit\uedit32.exe %F/%L'; - $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe %F'; - } - - if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] && constOn('DBG_SKIP_AJAX')) { - $this->safeDefine('DBG_SKIP_REPORTING', 1); - } - - // user defined options override debugger defaults - $dbg_constMap = $this->array_merge_recursive2($dbg_constMap, $dbg_options); - - foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) { - $this->safeDefine($dbg_constName, $dbg_constValue); - } - } - - function constOn($const_name) - { - return defined($const_name) && constant($const_name); - } - - function safeDefine($const_name, $const_value) { - if (!defined($const_name)) { - define($const_name, $const_value); - } - } - - function array_merge_recursive2($paArray1, $paArray2) - { - if (!is_array($paArray1) or !is_array($paArray2)) { - return $paArray2; - } - - foreach ($paArray2 AS $sKey2 => $sValue2) { - $paArray1[$sKey2] = isset($paArray1[$sKey2]) ? array_merge_recursive2($paArray1[$sKey2], $sValue2) : $sValue2; - } - - return $paArray1; - } - - function netMatch($network, $ip) { - - $network = trim($network); - $ip = trim($ip); - - if ($network == $ip) { - // comparing 2 ip addresses directly - return true; - } - - $d = strpos($network, '-'); - if ($d === false) { - // sigle subnet specified - $ip_arr = explode('/', $network); - - if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) { - $ip_arr[0] .= '.0'; // Alternate form 194.1.4/24 - } - - $network_long = ip2long($ip_arr[0]); - $x = ip2long($ip_arr[1]); - - $mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1])); - $ip_long = ip2long($ip); - - return ($ip_long & $mask) == ($network_long & $mask); - } - else { - // ip address range specified - $from = ip2long(trim(substr($network, 0, $d))); - $to = ip2long(trim(substr($network, $d + 1))); - - $ip = ip2long($ip); - return ($ip >= $from && $ip <= $to); - } - } - - function InitReport() - { - 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 = '@'.(is_object($application->Factory) ? $application->GetSID() : 0).'@'; - - // 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 = defined('WRITEABLE') ? WRITEABLE.'/cache' : FULL_PATH.'/kernel/cache'; - } - - function mapLongError($msg) - { - $key = $this->generateID(); - $this->longErrors[$key] = $msg; - return $key; - } - - /** - * Appends all passed variable values (wihout variable names) to debug output - * - */ - function dumpVars() - { - $dump_mode = 'var_dump'; - $dumpVars = func_get_args(); - - if ($dumpVars[count($dumpVars) - 1] === 'STRICT') { - $dump_mode = 'strict_var_dump'; - array_pop($dumpVars); - } - - foreach ($dumpVars as $varValue) { - $this->Data[] = Array('value' => $varValue, 'debug_type' => $dump_mode); - } - - } - - 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( $this->print_r($Data['value'], true) ); - break; - - case 'strict_var_dump': - return $this->highlightString( var_export($Data['value'], true) ); - break; - - case 'trace': - ini_set('memory_limit', '500M'); - $trace =& $Data['trace']; - - $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'; - } - - if ($has_args) { - // if parameter value is longer then 200 symbols, then leave only first 50 - $args = $this->highlightString($this->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(); - $total_width = ($this->getWindowWidth() - 10); - $div_width['before'] = round(($total_before / $total) * $total_width); - $div_width['current'] = round(($runtime / $total) * $total_width); - $div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width); - - $ret = 'Name: '.$Data['description'].'
'; - - $additional = isset($Data['additional']) ? $Data['additional'] : Array (); - if (isset($Data['file'])) { - array_unshift($additional, Array('name' => 'File', 'value' => $this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line']))); - } - array_unshift($additional, Array('name' => 'Runtime', 'value' => $runtime.'s')); - - foreach ($additional as $mixed_param) { - $ret .= '['.$mixed_param['name'].': '.$mixed_param['value'].'] '; - } - - /*if (isset($Data['file'])) { - $ret .= '[Runtime: '.$runtime.'s] [File: '.$this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line']).']
'; - } - else { - $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 - 8; - } - - /** - * 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) - { - $skip_classes = Array( - defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication', - 'kFactory', - 'kUnitConfigReader', - 'TemplateParser', - ); - - foreach ($skip_classes as $class_name) { - if (strtolower(get_class($object)) == strtolower($class_name)) { - return true; - } - } - - return false; - } - - /** - * 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 $tab_count offset in tabs - * @return string - */ - function print_r(&$array, $return_output = false, $tab_count = -1) - { - static $first_line = true; - - // not an array at all - if (!is_array($array)) { - switch (gettype($array)) { - case 'NULL': - return 'NULL'."\n"; - break; - - case 'object': - return $this->processObject($array, $tab_count); - break; - - default: - // number or string - if (strlen($array) > 200) { - $array = substr($array, 0, 50).' ...'; - } - return $array."\n"; - break; - } - } - - $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); - - foreach ($array_keys as $key) { - switch (gettype($array[$key])) { - case 'array': - $output .= $tabsign.'['.$key.'] = '.$this->print_r($array[$key], true, $tab_count); - break; - - case 'boolean': - $output .= $tabsign.'['.$key.'] = '.($array[$key] ? 'true' : 'false')."\n"; - break; - - case 'integer': - case 'double': - case 'string': - if (strlen($array[$key]) > 200) { - $array[$key] = substr($array[$key], 0, 50).' ...'; - } - $output .= $tabsign.'['.$key.'] = '.$array[$key]."\n"; - break; - - case 'NULL': - $output .= $tabsign.'['.$key."] = NULL\n"; - break; - - case 'object': - $output .= $tabsign.'['.$key."] = "; - $output .= "Object (".get_class($array[$key]).") = \n".str_repeat(' ', $tab_count + 1)."(\n"; - $output .= $this->processObject($array[$key], $tab_count + 2); - $output .= str_repeat(' ', $tab_count + 1).")\n"; - break; - - default: - $output .= $tabsign.'['.$key.'] unknown = '.gettype($array[$key])."\n"; - break; - } - } - - $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; - } - - function processObject(&$object, $tab_count) - { - $object_class = get_class($object); - if (!in_array($object_class, $this->RecursionStack)) { - if ($this->IsBigObject($object)) { - return 'SKIPPED (class: '.$object_class.")\n"; - } - - $attribute_names = get_class_vars($object_class); - if (!$attribute_names) { - return "NO_ATTRIBUTES\n"; - } - else { - $output = ''; - array_push($this->RecursionStack, $object_class); - - $tabsign = $tab_count ? str_repeat(' ', $tab_count) : ''; - foreach ($attribute_names as $attribute_name => $attribute_value) { - if (is_object($object->$attribute_name)) { - // it is object - $output .= $tabsign.'['.$attribute_name.'] = '.$this->processObject($object->$attribute_name, $tab_count + 1); - } - else { - $output .= $tabsign.'['.$attribute_name.'] = '.$this->print_r($object->$attribute_name, true, $tab_count); - } - } - array_pop($this->RecursionStack); - return $output; - } - } - else { - // object [in recursion stack] - return '*** RECURSION *** (class: '.$object_class.")\n"; - } - } - - /** - * 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 (!$this->constOn('DBG_USE_HIGHLIGHT')) { - return $string; - } - - $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); - } - - /** - * 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) { - $title = str_replace('/', '\\', $this->getLocalFile($file)); - } - - if ($this->isGecko()) { - return ''.$title.''; - } - else { - return ''.$title.''; - } - - } - - /** - * Converts filepath on server to filepath in mapped DocumentRoot on developer pc - * - * @param string $remoteFile - * @return string - */ - function getLocalFile($remoteFile) - { - return preg_replace('/^'.preg_quote(DOC_ROOT, '/').'/', DBG_LOCAL_BASE_PATH, $remoteFile, 1); - } - - /** - * Appends call trace till this method call - * - */ - 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'); - } - - /** - * Appends HTML code whithout transformations - * - * @param string $html - */ - 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).')'); - if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 'yes') { - $this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI'].' (QS Length:'.strlen($_SERVER['QUERY_STRING']).')'); - } - $this->appendHTML('DomViewer:  '); - - ob_start(); - ?> - - - - - $value) { - if(!is_array($value) && trim($value) == '') { - $value = 'no value'; - } - else { - $value = htmlspecialchars($this->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(); - } - - /** - * Appends php session content to debugger output - * - */ - 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 = null) - { - if (!isset($timeStamp)) { - $timeStamp = $this->getMoment(); - } - $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data)); - if (isset($description)) { - $this->ProfilerData[$key]['description'] = $description; - } - - 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_results[$i]['file']; - $this->ProfilerData[$key]['line'] = $trace_results[$i]['line']; - unset($trace_results); - } - - $this->Data[] = Array('profile_key' => $key, 'debug_type' => 'profiler'); - } - - function profileFinish($key, $description = null, $timeStamp = null) - { - if (!isset($timeStamp)) { - $timeStamp = $this->getMoment(); - } - $this->ProfilerData[$key]['ends'] = $timeStamp; - - if (isset($description)) { - $this->ProfilerData[$key]['description'] = $description; - } - - if (substr($key, 0, 4) == 'sql_') { - $func_arguments = func_get_args(); - $rows_affected = $func_arguments[3]; - - if ($rows_affected > 0) { - $additional = Array ( - Array ('name' => 'Affected Rows', 'value' => $rows_affected), - ); - - if (isset($func_arguments[4])) { - $additional[] = Array ('name' => 'Result', 'value' => $func_arguments[4]); - } - $this->ProfilerData[$key]['additional'] =& $additional; - } - } - } - - 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($error_code) - { - $error_map = Array( - 'Fatal Error' => Array(E_USER_ERROR), - 'Warning' => Array(E_WARNING, E_USER_WARNING), - 'Notice' => Array(E_NOTICE, E_USER_NOTICE), - ); - - if (defined('E_STRICT')) { - $error_map['PHP5 Strict'] = Array(E_STRICT); - } - - if (defined('E_RECOVERABLE_ERROR')) { - $error_map['Fatal Error (recoverable)'] = Array(E_RECOVERABLE_ERROR); - } - - foreach ($error_map as $error_name => $error_codes) { - if (in_array($error_code, $error_codes)) { - return $error_name; - } - } - - return ''; - } - - /** - * Returns profile total key (check against unexisting key too) - * - * @param string $key - * @return int - */ - function getProfilerTotal($key) - { - if (isset($this->ProfilerTotalCount[$key])) { - return (int)$this->ProfilerTotalCount[$key]; - } - return 0; - } - - function ProfilePoint($title, $level=1) - { - $trace_results = debug_backtrace(); - $level = min($level,count($trace_results)-1); - - do { - $point = $trace_results[$level]; - $location = $point['file'].':'.$point['line']; - $level++; - $has_more = isset($trace_results[$level]); - } while ($has_more && $point['function'] == $trace_results[$level]['function'] ); - - if ($location == ':') { - echo ''; - } - - if (!isset($this->ProfilePoints[$title])) { - $this->ProfilePoints[$title] = array(); - } - if (!isset($this->ProfilePoints[$title][$location])) { - $this->ProfilePoints[$title][$location] = 0; - } - $this->ProfilePoints[$title][$location]++; - } - - /** - * Generates report - * - */ - function printReport($returnResult = false, $clean_output_buffer = true) - { - if ($this->reportDone) { - // 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(); - - if (defined('SPACER_URL')) { - $this->dummyImage = SPACER_URL; - } - - $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_TOOLBAR_BUTTONS', 1); - - $this->appendSession(); // show php session if any - - // ensure, that 1st line of debug output always is this one: - $top_line = '
[Reload Frame] [Hide Debugger][Current Time: '.date('H:i:s').'] [File Size: #DBG_FILESIZE#]
'; - - $this->appendHTML($top_line); - $this->moveToBegin(1); - - if (count($this->ProfilePoints)>0) { - foreach($this->ProfilePoints as $point => $locations) { - arsort($this->ProfilePoints[$point]); - } - - $this->appendHTML($this->highlightString($this->print_r($this->ProfilePoints, true))); - /*foreach ($this->ProfilePoints as $point => $locations) { - foreach ($locations as $location => $occurences) { - - - } - }*/ - } - - if ($this->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 ($this->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 ($this->constOn('DBG_PROFILE_MEMORY')) { - // detailed memory usage reporting by objects was enabled -> show totals - $this->appendHTML('Memory used by Objects: '.round($this->ProfilerTotals['objects'] / 1024, 2).'Kb'); - } - - if ($this->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 ($this->constOn('DBG_PROFILE_INCLUDES')) { - $this->appendHTML('Included files statistics:'.( $this->constOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':'')); - $totals = Array( 'mem' => 0, 'time' => 0); - $totals_configs = Array( 'mem' => 0, 'time' => 0); - if (is_array($this->IncludesData['mem'])) { - if ( $this->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'])); - } - }*/ - - $is_ajax = isset($_GET['ajax']) && $_GET['ajax'] == 'yes'; - $skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT'); - - if (($is_ajax && !constOn('DBG_SKIP_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); - } - - if ($skip_reporting) { - // let debugger write report and then don't output anything - $this->reportDone = true; - return ''; - } - - $dbg_path = str_replace(FULL_PATH, '', $this->tempFolder); - ob_start(); - // the - - - - - - ProfilerTotals['error_handling'])) { - $memory_used = $debugger_start; - $this->ProfilerTotalCount['error_handling'] = 0; - } - else { - $memory_used = $debugger_start - $this->ProfilerTotals['error_handling']; - } - - if ($returnResult) { - $ret = ob_get_contents(); - if ($clean_output_buffer) { - ob_end_clean(); - } - $ret .= $this->getShortReport($memory_used); - - $this->reportDone = true; - return $ret; - } - else { - if (!$this->constOn('DBG_HIDE_FULL_REPORT')) { - $this->breakOutofBuffering(); - } - elseif ($clean_output_buffer) { - ob_clean(); - } - echo $this->getShortReport($memory_used); - - $this->reportDone = true; - } - } - - /** - * Format's memory usage report by debugger - * - * @return string - * @access private - */ - function getShortReport($memory_used) - { - if ($this->constOn('DBG_TOOLBAR_BUTTONS')) { - // we have sql & error count in toolbar, don't duplicate here - $info = Array( - 'Script Runtime' => 'PROFILE:script_runtime', - 'SQL\'s Runtime' => 'PROFILE_T:sql', - ); - } - else { - // toolbar not visible, then show sql & error count too - $info = Array ( - 'Script Runtime' => 'PROFILE:script_runtime', - 'SQL\'s Runtime' => 'PROFILE_T:sql', - '-' => 'SEP:-', - 'Notice / Warning' => 'PROFILE_TC:error_handling', - 'SQLs Count' => 'PROFILE_TC:sql', - ); - } - - $ret = 'Application:'.$this->formatSize($memory_used).' ('.$memory_used.')'; - foreach ($info as $title => $value_key) { - list ($record_type, $record_data) = explode(':', $value_key, 2); - switch ($record_type) { - case 'PROFILE': // profiler totals value - $Data =& $this->ProfilerData[$record_data]; - $profile_time = ($Data['ends'] - $Data['begins']); // in seconds - $ret .= ''.$title.':'.sprintf('%.5f', $profile_time).' s'; - break; - - case 'PROFILE_TC': // profile totals record count - $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 'PROFILE_T': // profile total - $record_cell = ''; - $ret .= ''.$record_cell.$title.':'.$record_cell.''.sprintf('%.5f', $this->ProfilerTotals[$record_data]).' s'; - break; - - case 'SEP': - $ret .= ''; - break; - } - } - - return '
'.$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 = '') - { - $this->ProfilerData['error_handling']['begins'] = memory_get_usage(); - - $errorType = $this->getErrorNameByCode($errno); - if (!$errorType) { - trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR); - return false; - } - - if ($this->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]); - } - - 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); - } - - $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error'); - $this->ProfilerData['error_handling']['ends'] = memory_get_usage(); - $this->profilerAddTotal('error_handling', 'error_handling'); - if (substr($errorType, 0, 5) == 'Fatal') { - $this->IsFatalError = true; - // 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()) { - $buffer_content[] = ob_get_clean(); - } - $ret = implode('', array_reverse($buffer_content)); - if ($flush) { - echo $ret; - flush(); - } - return $ret; - } - - 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); - } - - function AttachToApplication() { - if (!$this->constOn('DBG_HANDLE_ERRORS')) return true; - - if (class_exists('kApplication')) { - restore_error_handler(); - $application =& kApplication::Instance(); - $application->Debugger =& $this; - $application->errorHandlers[] = Array(&$this, 'saveError'); - } - else { - set_error_handler(Array(&$this, 'saveError')); - } - } - } - - if (!function_exists('memory_get_usage')) { - function memory_get_usage(){ return -1; } - } - - if (!Debugger::constOn('DBG_ZEND_PRESENT')) { - $debugger = new Debugger(); - } - - if (Debugger::constOn('DBG_USE_SHUTDOWN_FUNC')) { - register_shutdown_function( Array(&$debugger, 'printReport') ); - } - } -?> \ No newline at end of file