Index: branches/5.2.x/core/kernel/utility/debugger.php =================================================================== diff -u -N -r14092 -r14095 --- branches/5.2.x/core/kernel/utility/debugger.php (.../debugger.php) (revision 14092) +++ branches/5.2.x/core/kernel/utility/debugger.php (.../debugger.php) (revision 14095) @@ -1,6 +1,6 @@ = 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; + } + + /** + * 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 + */ + public static function ipMatch($ip_list, $separator = ';') + { + if ( !isset($_SERVER['REMOTE_ADDR']) ) { + // PHP CLI used -> never match + return false; + } + + $ip_match = false; + $ip_addresses = $ip_list ? explode($separator, $ip_list) : Array (); + foreach ($ip_addresses as $ip_address) { + if (self::netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) { + $ip_match = true; + break; + } + } + + return $ip_match; + } + + public static function netMatch($network, $ip) { + + $network = trim($network); + $ip = trim($ip); + + if ($network == $ip) { + // comparing two ip addresses directly + return true; + } + + $d = strpos($network, '-'); + if ($d !== false) { + // 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); + } + elseif (strpos($network, '/') !== 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); + } + + return false; + } + } + class Debugger { /** @@ -124,16 +249,17 @@ */ var $_isAjax = false; - function Debugger() + public function __construct() { global $start, $dbg_options; + // check if user haven't defined DEBUG_MODE contant directly if (defined('DEBUG_MODE') && DEBUG_MODE) { die('error: contant DEBUG_MODE defined directly, please use $dbg_options array instead'); } // check IP before enabling debug mode - $ip_match = $this->ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : ''); + $ip_match = DebuggerUtil::ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : ''); if (!$ip_match) { define('DEBUG_MODE', 0); @@ -147,39 +273,13 @@ $this->LastMoment = $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 + ini_set('display_errors', DebuggerUtil::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 = ';') - { - if ( !isset($_SERVER['REMOTE_ADDR']) ) { - return false; - } - - $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 * */ @@ -192,20 +292,20 @@ // Detect fact, that this session beeing debugged by Zend Studio foreach ($_COOKIE as $cookie_name => $cookie_value) { if (substr($cookie_name, 0, 6) == 'debug_') { - $this->safeDefine('DBG_ZEND_PRESENT', 1); + DebuggerUtil::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 + DebuggerUtil::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_IGNORE_STRICT_ERRORS' => 0, // 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 @@ -226,7 +326,7 @@ } // user defined options override debugger defaults - $dbg_constMap = $this->array_merge_recursive2($dbg_constMap, $dbg_options); + $dbg_constMap = array_merge($dbg_constMap, $dbg_options); if ($this->_isAjax && array_key_exists('DBG_SKIP_AJAX', $dbg_constMap) && $dbg_constMap['DBG_SKIP_AJAX']) { $dbg_constMap['DBG_SKIP_REPORTING'] = 1; @@ -248,73 +348,10 @@ } foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) { - $this->safeDefine($dbg_constName, $dbg_constValue); + DebuggerUtil::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 two ip addresses directly - return true; - } - - $d = strpos($network, '-'); - if ($d !== false) { - // 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); - } - elseif (strpos($network, '/') !== 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); - } - - return false; - } - function InitReport() { if (!class_exists('kApplication')) return false; @@ -338,6 +375,7 @@ { $key = $this->generateID(); $this->longErrors[$key] = $msg; + return $key; } @@ -363,19 +401,29 @@ function prepareHTML($dataIndex) { + static $errors_displayed = 0; + $Data =& $this->Data[$dataIndex]; if ($Data['debug_type'] == 'html') { return $Data['html']; } switch ($Data['debug_type']) { case 'error': + $errors_displayed++; $fileLink = $this->getFileLink($Data['file'], $Data['line']); - $ret = ''.$this->getErrorNameByCode($Data['no']).': '.$Data['str']; + $ret = '' . $this->getErrorNameByCode($Data['no']) . ' (#' . $errors_displayed . '): ' . $Data['str']; $ret .= ' in '.$fileLink.' on line '.$Data['line'].''; return $ret; break; + case 'exception': + $fileLink = $this->getFileLink($Data['file'], $Data['line']); + $ret = ''.$Data['exception_class'].': '.$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; @@ -742,15 +790,32 @@ /** * Appends call trace till this method call * + * @param int $levels_to_shift */ - function appendTrace() + function appendTrace($levels_to_shift = 1) { + $levels_shifted = 0; $trace = debug_backtrace(); - array_shift($trace); + while ($levels_shifted < $levels_to_shift) { + array_shift($trace); + $levels_shifted++; + } + $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace'); } + /** + * Appends call trace till this method call + * + * @param Exception $exception + */ + private function appendExceptionTrace(&$exception) + { + $trace = $exception->getTrace(); + $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace'); + } + function appendMemoryUsage($msg, $used = null) { if (!isset($used)) { @@ -1105,8 +1170,8 @@ $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); + DebuggerUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 0); + DebuggerUtil::safeDefine('DBG_TOOLBAR_BUTTONS', 1); $this->appendSession(); // show php session if any @@ -1130,7 +1195,7 @@ }*/ } - if ($this->constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) { + if (DebuggerUtil::constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) { // sql query profiling was enabled -> show totals if (array_key_exists('cachable_queries', $this->ProfilerTotalCount)) { $append = ' Cachable queries: ' . $this->ProfilerTotalCount['cachable_queries']; @@ -1142,30 +1207,30 @@ $this->appendHTML('SQL Total time: '.$this->ProfilerTotals['sql'].' Number of queries: '.$this->ProfilerTotalCount['sql'] . $append); } - if ($this->constOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes'])) { + if (DebuggerUtil::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')) { + if (DebuggerUtil::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')) { + if (DebuggerUtil::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)':'')); + if (DebuggerUtil::constOn('DBG_PROFILE_INCLUDES')) { + $this->appendHTML('Included files statistics:'.( DebuggerUtil::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') ) { + if ( DebuggerUtil::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) { @@ -1185,9 +1250,9 @@ } } - $skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT'); + $skip_reporting = DebuggerUtil::constOn('DBG_SKIP_REPORTING') || DebuggerUtil::constOn('DBG_ZEND_PRESENT'); - if (($this->_isAjax && !$this->constOn('DBG_SKIP_AJAX')) || !$skip_reporting) { + if (($this->_isAjax && !DebuggerUtil::constOn('DBG_SKIP_AJAX')) || !$skip_reporting) { $debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt'; if (file_exists($debug_file)) unlink($debug_file); @@ -1228,7 +1293,9 @@ $Debugger.DebugURL = 'baseURL.'/debugger_responce.php?sid='.$this->rowSeparator.'&path='.urlencode($dbg_path); ?>'; $Debugger.EventURL = 'Factory) ? $application->HREF('dummy', '', Array ('pass' => 'm', '__NO_REWRITE__' => 1)) : ''; ?>'; IsFatalError || (DBG_RAISE_ON_WARNINGS && $this->WarningCount)) { + $is_install = defined('IS_INSTALL') && IS_INSTALL; + + if ($this->IsFatalError || (!$is_install && DBG_RAISE_ON_WARNINGS && $this->WarningCount)) { echo '$Debugger.Toggle();'; } if (DBG_TOOLBAR_BUTTONS) { @@ -1257,7 +1324,7 @@ return $ret; } else { - if (!$this->constOn('DBG_HIDE_FULL_REPORT')) { + if (!DebuggerUtil::constOn('DBG_HIDE_FULL_REPORT')) { $this->breakOutofBuffering(); } elseif ($clean_output_buffer) { @@ -1277,7 +1344,7 @@ */ function getShortReport($memory_used) { - if ($this->constOn('DBG_TOOLBAR_BUTTONS')) { + if (DebuggerUtil::constOn('DBG_TOOLBAR_BUTTONS')) { // we have sql & error count in toolbar, don't duplicate here $info = Array( 'Script Runtime' => 'PROFILE:script_runtime', @@ -1295,7 +1362,7 @@ ); } - $ret = '