Index: branches/5.2.x/core/kernel/utility/debugger.php =================================================================== --- branches/5.2.x/core/kernel/utility/debugger.php +++ branches/5.2.x/core/kernel/utility/debugger.php @@ -209,20 +209,11 @@ private $Application = null; /** - * Set to true if fatal error occurred + * Stores last fatal error hash or 0, when no fatal error happened * - * @var bool - * @access private + * @var integer */ - private $IsFatalError = false; - - /** - * Tells if last error (if any) caught by shutdown function was processed - * - * @var bool - * @access private - */ - private $_lastErrorProcessed = false; + private $_fatalErrorHash = 0; /** * Counts warnings on the page @@ -320,7 +311,7 @@ * @var bool * @access private */ - private $reportDone = false; + private $_inReportPrinting = false; /** * Transparent spacer image used in case of none spacer image defined via SPACER_URL constant. @@ -1430,28 +1421,35 @@ /** * Generates report * - * @param bool $returnResult - * @param bool $clean_output_buffer + * @param boolean $return_result Returns or output report contents. + * @param boolean $clean_output_buffer Clean output buffers before displaying anything. + * @param boolean $is_shutdown_func Called from shutdown function. * * @return string - * @access public */ - public function printReport($returnResult = false, $clean_output_buffer = true) + public function printReport($return_result = false, $clean_output_buffer = true, $is_shutdown_func = false) { - if ( $this->reportDone ) { + if ( $this->_inReportPrinting ) { // don't print same report twice (in case if shutdown function used + compression + fatal error) return ''; } + $this->_inReportPrinting = true; $last_error = error_get_last(); - if ( !is_null($last_error) && !$this->_lastErrorProcessed ) { - $this->_lastErrorProcessed = true; - $this->saveError($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']); + if ( !is_null($last_error) && $is_shutdown_func ) { + $this->saveError( + $last_error['type'], + $last_error['message'], + $last_error['file'], + $last_error['line'], + null, + $is_shutdown_func + ); } $this->profileFinish('script_runtime'); - $this->breakOutofBuffering(!$returnResult); + $this->_breakOutOfBuffering(!$return_result); $debugger_start = memory_get_usage(); @@ -1561,7 +1559,6 @@ if ( $skip_reporting ) { // let debugger write report and then don't output anything - $this->reportDone = true; return ''; } @@ -1571,7 +1568,7 @@ $debugger_params = Array ( 'RowSeparator' => $this->rowSeparator, 'ErrorsCount' => (int)$this->getProfilerTotal('error_handling'), - 'IsFatalError' => $this->IsFatalError, + 'IsFatalError' => $this->_fatalErrorHappened(), 'SQLCount' => (int)$this->getProfilerTotal('sql'), 'SQLTime' => isset($this->ProfilerTotals['sql']) ? sprintf('%.5f', $this->ProfilerTotals['sql']) : 0, 'ScriptTime' => sprintf('%.5f', $this->ProfilerData['script_runtime']['ends'] - $this->ProfilerData['script_runtime']['begins']), @@ -1599,7 +1596,9 @@ IsFatalError || (!$is_install && DBG_RAISE_ON_WARNINGS && $this->WarningCount) ) { + if ( $this->_fatalErrorHappened() + || (!$is_install && DBG_RAISE_ON_WARNINGS && $this->WarningCount) + ) { echo '$Debugger.Toggle();'; } if ( DBG_TOOLBAR_BUTTONS ) { @@ -1609,26 +1608,26 @@ window.focus(); getShortReport($this->getMemoryUsed($debugger_start)); - $this->reportDone = true; return $ret; } else { if ( !DebuggerUtil::constOn('DBG_HIDE_FULL_REPORT') ) { - $this->breakOutofBuffering(); + $this->_breakOutOfBuffering(); } elseif ( $clean_output_buffer ) { ob_clean(); } - echo $this->getShortReport($this->getMemoryUsed($debugger_start)); - $this->reportDone = true; + echo $this->getShortReport($this->getMemoryUsed($debugger_start)); } return ''; @@ -1706,19 +1705,49 @@ } /** - * User-defined error handler + * Detects if there was a fatal error at some point * - * @throws Exception - * @param int $errno - * @param string $errstr - * @param string $errfile - * @param int $errline - * @param array $errcontext - * @return bool - * @access public + * @return boolean */ - public function saveError($errno, $errstr, $errfile = null, $errline = null, $errcontext = Array ()) + private function _fatalErrorHappened() { + return $this->_fatalErrorHash !== 0; + } + + /** + * Creates error hash + * + * @param string $errfile File, where error happened. + * @param integer $errline Line in file, where error happened. + * + * @return integer + */ + private function _getErrorHash($errfile, $errline) + { + return crc32($errfile . ':' . $errline); + } + + /** + * User-defined error handler + * + * @param integer $errno Error code. + * @param string $errstr Error message. + * @param string $errfile Error file. + * @param integer $errline Error line. + * @param array $errcontext Error context. + * @param boolean $is_shutdown_func Called from shutdown function. + * + * @return boolean + * @throws Exception When unknown error code given. + */ + public function saveError( + $errno, + $errstr, + $errfile = null, + $errline = null, + array $errcontext = null, + $is_shutdown_func = false + ) { $this->ProfilerData['error_handling']['begins'] = memory_get_usage(); $errorType = $this->getErrorNameByCode($errno); @@ -1729,7 +1758,7 @@ return false; } elseif ( substr($errorType, 0, 5) == 'Fatal' ) { - $this->IsFatalError = true; + $this->_fatalErrorHash = $this->_getErrorHash($errfile, $errline); $this->appendTrace(4); } @@ -1747,9 +1776,15 @@ $this->WarningCount++; } - if ( $this->IsFatalError ) { - // append debugger report to data in buffer & clean buffer afterwards - die( $this->breakOutofBuffering(false) . $this->printReport(true) ); + if ( $this->_fatalErrorHappened() + && $this->_getErrorHash($errfile, $errline) === $this->_fatalErrorHash + ) { + // Append debugger report to data in buffer & clean buffer afterwards. + echo $this->_breakOutOfBuffering(false) . $this->printReport(true); + + if ( !$is_shutdown_func ) { + exit; + } } return true; @@ -1794,10 +1829,10 @@ public function saveException($exception) { $this->appendException($exception); - $this->IsFatalError = true; + $this->_fatalErrorHash = $this->_getErrorHash($exception->getFile(), $exception->getLine()); - // append debugger report to data in buffer & clean buffer afterwards - die( $this->breakOutofBuffering(false) . $this->printReport(true) ); + // Append debugger report to data in buffer & clean buffer afterwards. + echo $this->_breakOutOfBuffering(false) . $this->printReport(true); } /** @@ -1835,7 +1870,7 @@ * @return string * @access private */ - private function breakOutofBuffering($flush = true) + private function _breakOutOfBuffering($flush = true) { $buffer_content = Array (); while ( ob_get_level() ) { @@ -1983,6 +2018,6 @@ } if ( DebuggerUtil::constOn('DBG_USE_SHUTDOWN_FUNC') ) { - register_shutdown_function(Array (&$debugger, 'printReport')); + register_shutdown_function(array(&$debugger, 'printReport'), false, true, true); } - } \ No newline at end of file + }