|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZDebug class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /*! \defgroup eZUtils Utility classes */ 00012 00013 /*! 00014 \class eZDebug ezdebug.php 00015 \ingroup eZUtils 00016 \brief Advanced debug/log system 00017 00018 The eZ debug library is used to handle debug information. It 00019 can display information on screen and/or write it to log files. 00020 00021 You can enable on-screen debug information for specific IP addresses. 00022 00023 Timing points can be placed in the code to time the different sections of code. 00024 00025 Each debug message can be turned on/off by using the showTypes() function. 00026 00027 PHP error messages can also be shown using setHandleType(). 00028 00029 \code 00030 00031 // write a temporary debug message 00032 eZDebug::writeDebug( "Test" ); 00033 00034 // write a notice 00035 eZDebug::writeNotice( "Image found" ); 00036 00037 // write a warning 00038 eZDebug::writeWarning( "Image not found, using default" ); 00039 00040 // write an error 00041 eZDebug::writeError( "Object not found, bailing.." ); 00042 00043 // add a timing points 00044 eZDebug::addTimingPoint( "Module Found" ); 00045 00046 //.... code 00047 00048 eZDebug::addTimingPoint( "Module loading" ); 00049 00050 // print the results on screen. 00051 eZDebug::printReport(); 00052 00053 \endcode 00054 */ 00055 00056 class eZDebug 00057 { 00058 const LEVEL_NOTICE = 1; 00059 const LEVEL_WARNING = 2; 00060 const LEVEL_ERROR = 3; 00061 const LEVEL_TIMING_POINT = 4; 00062 const LEVEL_DEBUG = 5; 00063 const LEVEL_STRICT = 6; 00064 00065 const SHOW_NOTICE = 1; // 1 << (EZ_LEVEL_NOTICE - 1) 00066 const SHOW_WARNING = 2; // 1 << (EZ_LEVEL_WARNING - 1) 00067 const SHOW_ERROR = 4; // 1 << (EZ_LEVEL_ERROR - 1) 00068 const SHOW_TIMING_POINT = 8; // 1 << (EZ_LEVEL_TIMING_POINT - 1) 00069 const SHOW_DEBUG = 16; // 1 << (EZ_LEVEL_DEBUG - 1) 00070 const SHOW_STRICT = 32; // 1 << (EZ_LEVEL_STRICT - 1) 00071 const SHOW_ALL = 63; // EZ_SHOW_NOTICE | EZ_SHOW_WARNING | EZ_SHOW_ERROR | EZ_SHOW_TIMING_POINT | EZ_SHOW_DEBUG | EZ_SHOW_STRICT 00072 00073 const HANDLE_NONE = 0; 00074 const HANDLE_FROM_PHP = 1; 00075 const HANDLE_TO_PHP = 2; 00076 const HANDLE_EXCEPTION = 3; 00077 00078 const OUTPUT_MESSAGE_SCREEN = 1; 00079 const OUTPUT_MESSAGE_STORE = 2; 00080 00081 const MAX_LOGFILE_SIZE = 204800; // 200*1024 00082 const MAX_LOGROTATE_FILES = 3; 00083 00084 const XDEBUG_SIGNATURE = '--XDEBUG--'; 00085 00086 /*! 00087 Creates a new debug object. 00088 */ 00089 function __construct( ) 00090 { 00091 $this->TmpTimePoints = array( self::LEVEL_NOTICE => array(), 00092 self::LEVEL_WARNING => array(), 00093 self::LEVEL_ERROR => array(), 00094 self::LEVEL_DEBUG => array(), 00095 self::LEVEL_STRICT => array() ); 00096 00097 $this->OutputFormat = array( self::LEVEL_NOTICE => array( "color" => "green", 00098 'style' => 'notice', 00099 'xhtml-identifier' => 'ezdebug-first-notice', 00100 "name" => "Notice" ), 00101 self::LEVEL_WARNING => array( "color" => "orange", 00102 'style' => 'warning', 00103 'xhtml-identifier' => 'ezdebug-first-warning', 00104 "name" => "Warning" ), 00105 self::LEVEL_ERROR => array( "color" => "red", 00106 'style' => 'error', 00107 'xhtml-identifier' => 'ezdebug-first-error', 00108 "name" => "Error" ), 00109 self::LEVEL_DEBUG => array( "color" => "brown", 00110 'style' => 'debug', 00111 'xhtml-identifier' => 'ezdebug-first-debug', 00112 "name" => "Debug" ), 00113 self::LEVEL_TIMING_POINT => array( "color" => "blue", 00114 'style' => 'timing', 00115 'xhtml-identifier' => 'ezdebug-first-timing-point', 00116 "name" => "Timing" ), 00117 self::LEVEL_STRICT => array( "color" => "purple", 00118 'style' => 'strict', 00119 'xhtml-identifier' => 'ezdebug-first-strict', 00120 'name' => 'Strict' ) ); 00121 $this->LogFiles = array( self::LEVEL_NOTICE => array( "var/log/", 00122 "notice.log" ), 00123 self::LEVEL_WARNING => array( "var/log/", 00124 "warning.log" ), 00125 self::LEVEL_ERROR => array( "var/log/", 00126 "error.log" ), 00127 self::LEVEL_DEBUG => array( "var/log/", 00128 "debug.log" ), 00129 self::LEVEL_STRICT => array( 'var/log/', 00130 'strict.log' ) ); 00131 $this->MessageTypes = array( self::LEVEL_NOTICE, 00132 self::LEVEL_WARNING, 00133 self::LEVEL_ERROR, 00134 self::LEVEL_TIMING_POINT, 00135 self::LEVEL_DEBUG, 00136 self::LEVEL_STRICT ); 00137 $this->MessageNames = array( self::LEVEL_NOTICE => 'Notice', 00138 self::LEVEL_WARNING => 'Warning', 00139 self::LEVEL_ERROR => 'Error', 00140 self::LEVEL_TIMING_POINT => 'TimingPoint', 00141 self::LEVEL_DEBUG => 'Debug', 00142 self::LEVEL_STRICT => 'Strict' ); 00143 $this->LogFileEnabled = array( self::LEVEL_NOTICE => true, 00144 self::LEVEL_WARNING => true, 00145 self::LEVEL_ERROR => true, 00146 self::LEVEL_TIMING_POINT => true, 00147 self::LEVEL_DEBUG => true, 00148 self::LEVEL_STRICT => true ); 00149 $this->AlwaysLog = array( self::LEVEL_NOTICE => false, 00150 self::LEVEL_WARNING => false, 00151 self::LEVEL_ERROR => true, // Error is on by default, due to its importance 00152 self::LEVEL_TIMING_POINT => false, 00153 self::LEVEL_DEBUG => false, 00154 self::LEVEL_STRICT => false ); 00155 $this->GlobalLogFileEnabled = true; 00156 if ( isset( $GLOBALS['eZDebugLogFileEnabled'] ) ) 00157 { 00158 $this->GlobalLogFileEnabled = $GLOBALS['eZDebugLogFileEnabled']; 00159 } 00160 $this->ShowTypes = self::SHOW_ALL; 00161 $this->HandleType = self::HANDLE_NONE; 00162 $this->OldHandler = false; 00163 $this->UseCSS = false; 00164 $this->MessageOutput = self::OUTPUT_MESSAGE_STORE; 00165 $this->ScriptStart = microtime( true ); 00166 $this->TimeAccumulatorList = array(); 00167 $this->TimeAccumulatorGroupList = array(); 00168 $this->OverrideList = array(); 00169 $this->topReportsList = array(); 00170 $this->bottomReportsList = array(); 00171 } 00172 00173 function reset() 00174 { 00175 $this->DebugStrings = array(); 00176 $this->TmpTimePoints = array( self::LEVEL_NOTICE => array(), 00177 self::LEVEL_WARNING => array(), 00178 self::LEVEL_ERROR => array(), 00179 self::LEVEL_DEBUG => array(), 00180 self::LEVEL_STRICT => array() ); 00181 $this->TimeAccumulatorList = array(); 00182 $this->TimeAccumulatorGroupList = array(); 00183 $this->topReportsList = array(); 00184 $this->bottomReportsList = array(); 00185 } 00186 00187 /*! 00188 \return the name of the message type. 00189 */ 00190 function messageName( $messageType ) 00191 { 00192 return $this->MessageNames[$messageType]; 00193 } 00194 00195 /** 00196 * Returns a shared instance of the eZDebug class. 00197 * 00198 * @return eZDebug 00199 */ 00200 static function instance( ) 00201 { 00202 if ( empty( $GLOBALS["eZDebugGlobalInstance"] ) ) 00203 { 00204 $GLOBALS["eZDebugGlobalInstance"] = new eZDebug(); 00205 } 00206 return $GLOBALS["eZDebugGlobalInstance"]; 00207 } 00208 00209 /*! 00210 \static 00211 Returns true if the message type $type can be shown. 00212 */ 00213 static function showMessage( $type ) 00214 { 00215 $debug = eZDebug::instance(); 00216 return $debug->ShowTypes & $type; 00217 } 00218 00219 /*! 00220 \return \c true if the debug level \a $level should always log to file. 00221 */ 00222 static function alwaysLogMessage( $level ) 00223 { 00224 $instance = eZDebug::instance(); 00225 // If there is a global setting for this get the value 00226 // and unset it globally 00227 if ( isset( $GLOBALS['eZDebugAlwaysLog'] ) ) 00228 { 00229 $instance->AlwaysLog = $GLOBALS['eZDebugAlwaysLog'] + $instance->AlwaysLog; 00230 unset( $GLOBALS['eZDebugAlwaysLog'] ); 00231 } 00232 00233 if ( !isset( $instance->AlwaysLog[$level] ) ) 00234 { 00235 return false; 00236 } 00237 return $instance->AlwaysLog[$level]; 00238 } 00239 00240 /*! 00241 Determines how PHP errors are handled. If $type is self::HANDLE_TO_PHP all error messages 00242 is sent to PHP using trigger_error(), if $type is self::HANDLE_FROM_PHP all error messages 00243 from PHP is fetched using a custom error handler and output as a usual eZDebug message. 00244 If $type is self::HANDLE_NONE there is no error exchange between PHP and eZDebug. 00245 */ 00246 static function setHandleType( $type ) 00247 { 00248 $instance = eZDebug::instance(); 00249 00250 if ( $type != self::HANDLE_TO_PHP and 00251 $type != self::HANDLE_FROM_PHP and 00252 $type != self::HANDLE_EXCEPTION ) 00253 $type = self::HANDLE_NONE; 00254 if ( extension_loaded( 'xdebug' ) and 00255 $type == self::HANDLE_FROM_PHP ) 00256 $type = self::HANDLE_NONE; 00257 if ( $type == $instance->HandleType ) 00258 return $instance->HandleType; 00259 00260 if ( $instance->HandleType == self::HANDLE_FROM_PHP or $instance->HandleType == self::HANDLE_EXCEPTION ) 00261 restore_error_handler(); 00262 switch ( $type ) 00263 { 00264 case self::HANDLE_FROM_PHP: 00265 { 00266 set_error_handler( array( $instance, 'recursionProtectErrorHandler' ) ); 00267 } break; 00268 00269 case self::HANDLE_TO_PHP: 00270 { 00271 restore_error_handler(); 00272 } break; 00273 00274 case self::HANDLE_EXCEPTION: 00275 { 00276 set_error_handler( array( $instance, 'exceptionErrorHandler' ) ); 00277 } break; 00278 00279 case self::HANDLE_NONE: 00280 { 00281 } 00282 } 00283 $oldHandleType = $instance->HandleType; 00284 $instance->HandleType = $type; 00285 return $oldHandleType; 00286 } 00287 00288 /*! 00289 \static 00290 Sets types to be shown to $types and returns the old show types. 00291 If $types is not supplied the current value is returned and no change is done. 00292 $types is one or more of self::SHOW_NOTICE, self::SHOW_WARNING, self::SHOW_ERROR, self::SHOW_TIMING_POINT 00293 or'ed together. 00294 */ 00295 static function showTypes( $types = false ) 00296 { 00297 $instance = eZDebug::instance(); 00298 00299 if ( $types === false ) 00300 { 00301 return $instance->ShowTypes; 00302 } 00303 $old_types = $instance->ShowTypes; 00304 $instance->ShowTypes = $types; 00305 return $old_types; 00306 } 00307 00308 public function recursionProtectErrorHandler( $errno, $errstr, $errfile, $errline ) 00309 { 00310 if ( $this->recursionFlag ) 00311 { 00312 print( "Fatal debug error: A recursion in debug error handler was detected, aborting debug message.<br/>" ); 00313 $this->recursionFlag = false; 00314 return; 00315 } 00316 00317 $this->recursionFlag = true; 00318 00319 $result = $this->errorHandler( $errno, $errstr, $errfile, $errline ); 00320 $this->recursionFlag = false; 00321 return $result; 00322 } 00323 00324 /*! 00325 Handles PHP errors, creates notice, warning and error messages for 00326 the various PHP error types. 00327 */ 00328 function errorHandler( $errno, $errstr, $errfile, $errline ) 00329 { 00330 if ( error_reporting() == 0 ) // @ error-control operator is used 00331 return; 00332 if ( !eZDebug::isDebugEnabled() ) 00333 return; 00334 $str = "$errstr in $errfile on line $errline"; 00335 if ( empty( $GLOBALS['eZDebugPHPErrorNames'] ) ) 00336 { 00337 $GLOBALS['eZDebugPHPErrorNames'] = 00338 array( E_ERROR => 'E_ERROR', 00339 E_PARSE => 'E_PARSE', 00340 E_CORE_ERROR => 'E_CORE_ERROR', 00341 E_COMPILE_ERROR => 'E_COMPILE_ERROR', 00342 E_USER_ERROR => 'E_USER_ERROR', 00343 E_WARNING => 'E_WARNING', 00344 E_CORE_WARNING => 'E_CORE_WARNING', 00345 E_COMPILE_WARNING => 'E_COMPILE_WARNING', 00346 E_USER_WARNING => 'E_USER_WARNING', 00347 E_NOTICE => 'E_NOTICE', 00348 E_USER_NOTICE => 'E_USER_NOTICE', 00349 E_STRICT => 'E_STRICT' ); 00350 // Since PHP 5.2 00351 if ( defined('E_RECOVERABLE_ERROR') ) 00352 $GLOBALS['eZDebugPHPErrorNames'][E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR'; 00353 // Since PHP 5.3 00354 if ( defined('E_DEPRECATED') ) 00355 $GLOBALS['eZDebugPHPErrorNames'][E_DEPRECATED] = 'E_DEPRECATED'; 00356 if ( defined('E_USER_DEPRECATED') ) 00357 $GLOBALS['eZDebugPHPErrorNames'][E_USER_DEPRECATED] = 'E_USER_DEPRECATED'; 00358 00359 } 00360 $errname = "Unknown error code ($errno)"; 00361 if ( isset( $GLOBALS['eZDebugPHPErrorNames'][$errno] ) ) 00362 { 00363 $errname = $GLOBALS['eZDebugPHPErrorNames'][$errno]; 00364 } 00365 switch ( $errname ) 00366 { 00367 case 'E_ERROR': 00368 case 'E_PARSE': 00369 case 'E_CORE_ERROR': 00370 case 'E_COMPILE_ERROR': 00371 case 'E_USER_ERROR': 00372 case 'E_RECOVERABLE_ERROR': 00373 { 00374 $this->writeError( $str, 'PHP: ' . $errname ); 00375 } break; 00376 00377 case 'E_WARNING': 00378 case 'E_CORE_WARNING': 00379 case 'E_COMPILE_WARNING': 00380 case 'E_USER_WARNING': 00381 case 'E_DEPRECATED': 00382 case 'E_USER_DEPRECATED': 00383 { 00384 $this->writeWarning( $str, 'PHP: ' . $errname ); 00385 } break; 00386 00387 case 'E_NOTICE': 00388 case 'E_USER_NOTICE': 00389 { 00390 $this->writeNotice( $str, 'PHP: ' . $errname ); 00391 } break; 00392 00393 case 'E_STRICT': 00394 { 00395 return $this->writeStrict( $str, 'PHP: ' . $errname ); 00396 } break; 00397 default: 00398 { 00399 $this->writeError( $str, 'PHP: ' . $errname ); 00400 } break; 00401 } 00402 } 00403 00404 /*! 00405 \static 00406 Writes a strict debug message. 00407 00408 The global variable \c 'eZDebugStrict' will be set to \c true if the notice is added. 00409 \param $label This label will be associated with the strict message, e.g. to say where the message came from. 00410 \param $backgroundClass A string defining the class to use in the HTML debug output. 00411 */ 00412 static function writeStrict( $string, $label = "", $backgroundClass = "" ) 00413 { 00414 $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_STRICT ); 00415 $enabled = eZDebug::isDebugEnabled(); 00416 if ( !$alwaysLog and !$enabled ) 00417 return; 00418 00419 $show = eZDebug::showMessage( self::SHOW_STRICT ); 00420 if ( !$alwaysLog and !$show ) 00421 return; 00422 00423 if ( is_object( $string ) || is_array( $string ) ) 00424 $string = eZDebug::dumpVariable( $string ); 00425 00426 $GLOBALS['eZDebugStrict'] = true; 00427 if ( !isset( $GLOBALS['eZDebugStrictCount'] ) ) 00428 $GLOBALS['eZDebugStrictCount'] = 0; 00429 ++$GLOBALS['eZDebugStrictCount']; 00430 00431 $debug = eZDebug::instance(); 00432 if ( $debug->HandleType == self::HANDLE_TO_PHP ) 00433 { 00434 // If we get here only because of $alwaysLog we should not trigger a PHP error 00435 if ( $enabled and $show ) 00436 { 00437 // we can't trigger E_STRICT but we can let the default error handler handle it 00438 // see http://www.php.net/manual/en/function.set-error-handler.php#69218 00439 return false; 00440 } 00441 } 00442 else 00443 { 00444 $debug->write( $string, self::LEVEL_STRICT, $label, $backgroundClass, $alwaysLog ); 00445 return true; 00446 } 00447 } 00448 00449 /*! 00450 \static 00451 Writes a debug notice. 00452 00453 The global variable \c 'eZDebugNotice' will be set to \c true if the notice is added. 00454 \param $label This label will be associated with the notice, e.g. to say where the notice came from. 00455 \param $backgroundClass A string defining the class to use in the HTML debug output. 00456 */ 00457 static function writeNotice( $string, $label = "", $backgroundClass = "" ) 00458 { 00459 $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_NOTICE ); 00460 $enabled = eZDebug::isDebugEnabled(); 00461 if ( !$alwaysLog and !$enabled ) 00462 return; 00463 00464 $show = eZDebug::showMessage( self::SHOW_NOTICE ); 00465 if ( !$alwaysLog and !$show ) 00466 return; 00467 00468 if ( is_object( $string ) || is_array( $string ) ) 00469 $string = eZDebug::dumpVariable( $string ); 00470 00471 $GLOBALS['eZDebugNotice'] = true; 00472 if ( !isset( $GLOBALS['eZDebugNoticeCount'] ) ) 00473 $GLOBALS['eZDebugNoticeCount'] = 0; 00474 ++$GLOBALS['eZDebugNoticeCount']; 00475 00476 $debug = eZDebug::instance(); 00477 if ( $debug->HandleType == self::HANDLE_TO_PHP ) 00478 { 00479 // If we get here only because of $alwaysLog we should not trigger a PHP error 00480 if ( $enabled and $show ) 00481 { 00482 if ( $label ) 00483 $string = "$label: $string"; 00484 trigger_error( $string, E_USER_NOTICE ); 00485 } 00486 } 00487 else 00488 { 00489 $debug->write( $string, self::LEVEL_NOTICE, $label, $backgroundClass, $alwaysLog ); 00490 } 00491 } 00492 00493 /*! 00494 \static 00495 Writes a debug warning. 00496 00497 The global variable \c 'eZDebugWarning' will be set to \c true if the notice is added. 00498 \param $label This label will be associated with the notice, e.g. to say where the notice came from. 00499 */ 00500 static function writeWarning( $string, $label = "", $backgroundClass = "" ) 00501 { 00502 $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_WARNING ); 00503 $enabled = eZDebug::isDebugEnabled(); 00504 if ( !$alwaysLog and !$enabled ) 00505 return; 00506 00507 $show = eZDebug::showMessage( self::SHOW_WARNING ); 00508 if ( !$alwaysLog and !$show ) 00509 return; 00510 00511 if ( is_object( $string ) || is_array( $string ) ) 00512 $string = eZDebug::dumpVariable( $string ); 00513 00514 $GLOBALS['eZDebugWarning'] = true; 00515 if ( !isset( $GLOBALS['eZDebugWarningCount'] ) ) 00516 $GLOBALS['eZDebugWarningCount'] = 0; 00517 ++$GLOBALS['eZDebugWarningCount']; 00518 00519 $debug = eZDebug::instance(); 00520 if ( $debug->HandleType == self::HANDLE_TO_PHP ) 00521 { 00522 // If we get here only because of $alwaysLog we should not trigger a PHP error 00523 if ( $enabled and $show ) 00524 { 00525 if ( $label ) 00526 $string = "$label: $string"; 00527 trigger_error( $string, E_USER_WARNING ); 00528 } 00529 } 00530 else 00531 { 00532 $debug->write( $string, self::LEVEL_WARNING, $label, $backgroundClass, $alwaysLog ); 00533 } 00534 } 00535 00536 /*! 00537 \static 00538 Writes a debug error. 00539 00540 The global variable \c 'eZDebugError' will be set to \c true if the notice is added. 00541 \param $label This label will be associated with the notice, e.g. to say where the notice came from. 00542 */ 00543 static function writeError( $string, $label = "", $backgroundClass = "" ) 00544 { 00545 $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_ERROR ); 00546 $enabled = eZDebug::isDebugEnabled(); 00547 if ( !$alwaysLog and !$enabled ) 00548 return; 00549 00550 $show = eZDebug::showMessage( self::SHOW_ERROR ); 00551 if ( !$alwaysLog and !$show ) 00552 return; 00553 00554 if ( is_object( $string ) || is_array( $string ) ) 00555 $string = eZDebug::dumpVariable( $string ); 00556 00557 $GLOBALS['eZDebugError'] = true; 00558 if ( !isset( $GLOBALS['eZDebugErrorCount'] ) ) 00559 $GLOBALS['eZDebugErrorCount'] = 0; 00560 ++$GLOBALS['eZDebugErrorCount']; 00561 00562 $debug = eZDebug::instance(); 00563 if ( $debug->HandleType == self::HANDLE_TO_PHP ) 00564 { 00565 // If we get here only because of $alwaysLog we should not trigger a PHP error 00566 if ( $enabled and $show ) 00567 { 00568 if ( $label ) 00569 $string = "$label: $string"; 00570 trigger_error( $string, E_USER_ERROR ); 00571 } 00572 } 00573 else 00574 { 00575 $debug->write( $string, self::LEVEL_ERROR, $label, $backgroundClass, $alwaysLog ); 00576 } 00577 } 00578 00579 /*! 00580 \static 00581 Writes a debug message. 00582 00583 The global variable \c 'eZDebugDebug' will be set to \c true if the notice is added. 00584 \param $label This label will be associated with the notice, e.g. to say where the notice came from. 00585 */ 00586 static function writeDebug( $string, $label = "", $backgroundClass = "" ) 00587 { 00588 $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_DEBUG ); 00589 $enabled = eZDebug::isDebugEnabled(); 00590 if ( !$alwaysLog and !$enabled ) 00591 return; 00592 00593 $show = eZDebug::showMessage( self::SHOW_DEBUG ); 00594 if ( !$alwaysLog and !$show ) 00595 return; 00596 00597 if ( is_object( $string ) || is_array( $string ) ) 00598 $string = eZDebug::dumpVariable( $string ); 00599 00600 $GLOBALS['eZDebugDebug'] = true; 00601 if ( !isset( $GLOBALS['eZDebugDebugCount'] ) ) 00602 $GLOBALS['eZDebugDebugCount'] = 0; 00603 ++$GLOBALS['eZDebugDebugCount']; 00604 00605 $debug = eZDebug::instance(); 00606 if ( $debug->HandleType == self::HANDLE_TO_PHP ) 00607 { 00608 // If we get here only because of $alwaysLog we should not trigger a PHP error 00609 if ( $enabled and $show ) 00610 { 00611 if ( $label ) 00612 $string = "$label: $string"; 00613 trigger_error( $string, E_USER_NOTICE ); 00614 } 00615 } 00616 else 00617 { 00618 $debug->write( $string, self::LEVEL_DEBUG, $label, $backgroundClass, $alwaysLog ); 00619 } 00620 } 00621 00622 /*! 00623 \static 00624 \private 00625 Dumps the variables contents using the var_dump function 00626 */ 00627 static function dumpVariable( $var ) 00628 { 00629 // If we have var_export (PHP >= 4.2.0) we use the instead 00630 // provides better output, doesn't require output buffering 00631 // and doesn't get mangled by Xdebug 00632 00633 // dl: we should always use 'var_dump' since 'var_export' is 00634 // unable to handle recursion properly. 00635 //if ( function_exists( 'var_export' ) ) 00636 // return var_export( $var, true ); 00637 00638 ob_start(); 00639 var_dump( $var ); 00640 $variableContents = ''; 00641 if ( extension_loaded( 'xdebug' ) ) 00642 $variableContents = self::XDEBUG_SIGNATURE; 00643 $variableContents .= ob_get_contents(); 00644 ob_end_clean(); 00645 return $variableContents; 00646 } 00647 00648 /*! 00649 Enables/disables the use of external CSS. If false a <style> tag is output 00650 before the debug list. Default is to use internal css. 00651 */ 00652 static function setUseExternalCSS( $use ) 00653 { 00654 eZDebug::instance()->UseCSS = $use; 00655 } 00656 00657 /*! 00658 Determines the way messages are output, the \a $output parameter 00659 is self::OUTPUT_MESSAGE_SCREEN and self::OUTPUT_MESSAGE_STORE ored together. 00660 */ 00661 function setMessageOutput( $output ) 00662 { 00663 $this->MessageOutput = $output; 00664 } 00665 00666 function setStoreLog( $store ) 00667 { 00668 $this->StoreLog = $store; 00669 } 00670 00671 /*! 00672 Adds a new timing point for the benchmark report. 00673 */ 00674 static function addTimingPoint( $description = "" ) 00675 { 00676 if ( !eZDebug::isDebugEnabled() ) 00677 return; 00678 if ( !eZDebug::showMessage( self::SHOW_TIMING_POINT ) ) 00679 return; 00680 00681 $time = microtime( true ); 00682 $debug = eZDebug::instance(); 00683 00684 $usedMemory = 0; 00685 if ( function_exists( "memory_get_usage" ) ) 00686 $usedMemory = memory_get_usage(); 00687 $tp = array( "Time" => $time, 00688 "Description" => $description, 00689 "MemoryUsage" => $usedMemory ); 00690 $debug->TimePoints[] = $tp; 00691 $desc = "Timing Point: $description"; 00692 foreach ( array( self::LEVEL_NOTICE, self::LEVEL_WARNING, self::LEVEL_ERROR, self::LEVEL_DEBUG, self::LEVEL_STRICT ) as $lvl ) 00693 { 00694 if ( isset( $debug->TmpTimePoints[$lvl] ) ) 00695 $debug->TmpTimePoints[$lvl] = array(); 00696 if ( $debug->TmpTimePoints[$lvl] === false and 00697 $debug->isLogFileEnabled( $lvl ) ) 00698 { 00699 $files = $debug->logFiles(); 00700 $file = $files[$lvl]; 00701 $debug->writeFile( $file, $desc, $lvl ); 00702 } 00703 else 00704 array_push( $debug->TmpTimePoints[$lvl], $tp ); 00705 } 00706 $debug->write( $description, self::LEVEL_TIMING_POINT ); 00707 } 00708 00709 /*! 00710 \private 00711 Writes a debug log message. 00712 */ 00713 function write( $string, $verbosityLevel = self::LEVEL_NOTICE, $label = "", $backgroundClass = "", $alwaysLog = false ) 00714 { 00715 $enabled = eZDebug::isDebugEnabled(); 00716 if ( !$alwaysLog and !$enabled ) 00717 return; 00718 switch ( $verbosityLevel ) 00719 { 00720 case self::LEVEL_NOTICE: 00721 case self::LEVEL_WARNING: 00722 case self::LEVEL_ERROR: 00723 case self::LEVEL_DEBUG: 00724 case self::LEVEL_TIMING_POINT: 00725 case self::LEVEL_STRICT: 00726 break; 00727 00728 default: 00729 $verbosityLevel = self::LEVEL_ERROR; 00730 break; 00731 } 00732 if ( $this->MessageOutput & self::OUTPUT_MESSAGE_SCREEN and $enabled ) 00733 { 00734 print( "$verbosityLevel: $string ($label)\n" ); 00735 } 00736 $files = $this->logFiles(); 00737 $fileName = false; 00738 if ( isset( $files[$verbosityLevel] ) ) 00739 $fileName = $files[$verbosityLevel]; 00740 if ( $this->MessageOutput & self::OUTPUT_MESSAGE_STORE or $alwaysLog ) 00741 { 00742 if ( ! eZDebug::isLogOnlyEnabled() and $enabled ) 00743 { 00744 $ip = eZSys::clientIP(); 00745 if ( !$ip ) 00746 $ip = eZSys::serverVariable( 'HOSTNAME', true ); 00747 $this->DebugStrings[] = array( "Level" => $verbosityLevel, 00748 "IP" => $ip, 00749 "Time" => time(), 00750 "Label" => $label, 00751 "String" => $string, 00752 "BackgroundClass" => $backgroundClass ); 00753 } 00754 00755 if ( $fileName !== false ) 00756 { 00757 $timePoints = $this->TmpTimePoints[$verbosityLevel]; 00758 if ( is_array( $timePoints ) ) 00759 { 00760 if ( $this->isLogFileEnabled( $verbosityLevel ) ) 00761 { 00762 foreach ( $timePoints as $tp ) 00763 { 00764 $desc = "Timing Point: " . $tp["Description"]; 00765 $this->writeFile( $fileName, $desc, $verbosityLevel, $alwaysLog ); 00766 } 00767 } 00768 $this->TmpTimePoints[$verbosityLevel] = false; 00769 } 00770 if ( $this->isLogFileEnabled( $verbosityLevel ) ) 00771 { 00772 $string = "$label:\n$string"; 00773 $this->writeFile( $fileName, $string, $verbosityLevel, $alwaysLog ); 00774 } 00775 } 00776 } 00777 } 00778 00779 /*! 00780 \static 00781 \return the maxium size for a log file in bytes. 00782 */ 00783 static function maxLogSize() 00784 { 00785 if ( isset( $GLOBALS['eZDebugMaxLogSize'] ) ) 00786 { 00787 return $GLOBALS['eZDebugMaxLogSize']; 00788 } 00789 return self::MAX_LOGFILE_SIZE; 00790 } 00791 00792 /*! 00793 \static 00794 Sets the maxium size for a log file to \a $size. 00795 */ 00796 static function setMaxLogSize( $size ) 00797 { 00798 $GLOBALS['eZDebugMaxLogSize'] = $size; 00799 } 00800 00801 /*! 00802 \static 00803 \return the maxium number of logrotate files to keep. 00804 */ 00805 static function maxLogrotateFiles() 00806 { 00807 if ( isset( $GLOBALS['eZDebugMaxLogrotateFiles'] ) ) 00808 { 00809 return $GLOBALS['eZDebugMaxLogrotateFiles']; 00810 } 00811 return self::MAX_LOGROTATE_FILES; 00812 } 00813 00814 /*! 00815 \static 00816 Sets the maxium number of logrotate files to keep to \a $files. 00817 */ 00818 static function setLogrotateFiles( $files ) 00819 { 00820 $GLOBALS['eZDebugMaxLogrotateFiles'] = $files; 00821 } 00822 00823 /*! 00824 \static 00825 Rotates logfiles so the current logfile is backed up, 00826 old rotate logfiles are rotated once more and those that 00827 exceed maxLogrotateFiles() will be removed. 00828 Rotated files will get the extension .1, .2 etc. 00829 */ 00830 static function rotateLog( $fileName ) 00831 { 00832 $maxLogrotateFiles = eZDebug::maxLogrotateFiles(); 00833 for ( $i = $maxLogrotateFiles; $i > 0; --$i ) 00834 { 00835 $logRotateName = $fileName . '.' . $i; 00836 if ( file_exists( $logRotateName ) ) 00837 { 00838 if ( $i == $maxLogrotateFiles ) 00839 { 00840 @unlink( $logRotateName ); 00841 // print( "@unlink( $logRotateName )<br/>" ); 00842 } 00843 else 00844 { 00845 $newLogRotateName = $fileName . '.' . ($i + 1); 00846 eZFile::rename( $logRotateName, $newLogRotateName ); 00847 // print( "@rename( $logRotateName, $newLogRotateName )<br/>" ); 00848 } 00849 } 00850 } 00851 if ( file_exists( $fileName ) ) 00852 { 00853 $newLogRotateName = $fileName . '.' . 1; 00854 eZFile::rename( $fileName, $newLogRotateName ); 00855 // print( "@rename( $fileName, $newLogRotateName )<br/>" ); 00856 return true; 00857 } 00858 return false; 00859 } 00860 00861 /*! 00862 \private 00863 Writes the log message $string to the file $fileName. 00864 */ 00865 function writeFile( &$logFileData, &$string, $verbosityLevel, $alwaysLog = false ) 00866 { 00867 $enabled = eZDebug::isDebugEnabled(); 00868 if ( !$alwaysLog and !$enabled ) 00869 return; 00870 if ( !$alwaysLog and !$this->isLogFileEnabled( $verbosityLevel ) ) 00871 return; 00872 $oldHandleType = eZDebug::setHandleType( self::HANDLE_TO_PHP ); 00873 $logDir = $logFileData[0]; 00874 $logName = $logFileData[1]; 00875 $fileName = $logDir . $logName; 00876 if ( !file_exists( $logDir ) ) 00877 { 00878 eZDir::mkdir( $logDir, false, true ); 00879 } 00880 $oldumask = @umask( 0 ); 00881 $fileExisted = file_exists( $fileName ); 00882 if ( $fileExisted and 00883 filesize( $fileName ) > eZDebug::maxLogSize() ) 00884 { 00885 if ( eZDebug::rotateLog( $fileName ) ) 00886 $fileExisted = false; 00887 } 00888 $logFile = @fopen( $fileName, "a" ); 00889 if ( $logFile ) 00890 { 00891 $time = strftime( "%b %d %Y %H:%M:%S", strtotime( "now" ) ); 00892 $ip = eZSys::clientIP(); 00893 if ( !$ip ) 00894 $ip = eZSys::serverVariable( 'HOSTNAME', true ); 00895 $notice = "[ " . $time . " ] [" . $ip . "] " . $string . "\n"; 00896 @fwrite( $logFile, $notice ); 00897 @fclose( $logFile ); 00898 if ( !$fileExisted ) 00899 { 00900 $ini = eZINI::instance(); 00901 $permissions = octdec( $ini->variable( 'FileSettings', 'LogFilePermissions' ) ); 00902 @chmod( $fileName, $permissions ); 00903 } 00904 @umask( $oldumask ); 00905 } 00906 else 00907 { 00908 @umask( $oldumask ); 00909 $logEnabled = $this->isLogFileEnabled( $verbosityLevel ); 00910 $this->setLogFileEnabled( false, $verbosityLevel ); 00911 if ( $verbosityLevel != self::LEVEL_ERROR or 00912 $logEnabled ) 00913 { 00914 eZDebug::setHandleType( $oldHandleType ); 00915 $this->writeError( "Cannot open log file '$fileName' for writing\n" . 00916 "The web server must be allowed to modify the file.\n" . 00917 "File logging for '$fileName' is disabled." , 'eZDebug::writeFile' ); 00918 } 00919 } 00920 eZDebug::setHandleType( $oldHandleType ); 00921 } 00922 00923 /*! 00924 \static 00925 Enables or disables logging to file for a given message type. 00926 If \a $types is not supplied it will do the operation for all types. 00927 */ 00928 static function setLogFileEnabled( $enabled, $types = false ) 00929 { 00930 $instance = eZDebug::instance(); 00931 if ( $types === false ) 00932 { 00933 $types = $instance->messageTypes(); 00934 } 00935 if ( !is_array( $types ) ) 00936 { 00937 $types = array( $types ); 00938 } 00939 foreach ( $types as $type ) 00940 { 00941 $instance->LogFileEnabled[$type] = $enabled; 00942 } 00943 } 00944 00945 /*! 00946 \return true if the message type \a $type has logging to file enabled. 00947 \sa isGlobalLogFileEnabled, setIsLogFileEnabled 00948 */ 00949 function isLogFileEnabled( $type ) 00950 { 00951 if ( !$this->isGlobalLogFileEnabled() ) 00952 return false; 00953 return $this->LogFileEnabled[$type]; 00954 } 00955 00956 /*! 00957 \return true if the message type \a $type has logging to file enabled. 00958 \sa isLogFileEnabled, setIsGlobalLogFileEnabled 00959 */ 00960 function isGlobalLogFileEnabled() 00961 { 00962 return $this->GlobalLogFileEnabled; 00963 } 00964 00965 /*! 00966 Sets whether the logfile \a $type is enabled or disabled to \a $enabled. 00967 \sa isLogFileEnabled 00968 */ 00969 function setIsLogFileEnabled( $type, $enabled ) 00970 { 00971 $this->LogFileEnabled[$type] = $enabled; 00972 } 00973 00974 /*! 00975 Sets whether logfiles are enabled or disabled globally. Sets the value to \a $enabled. 00976 \sa isLogFileEnabled, isGlobalLogFileEnabled 00977 */ 00978 function setIsGlobalLogFileEnabled( $enabled ) 00979 { 00980 $this->GlobalLogFileEnabled = $enabled; 00981 } 00982 00983 /*! 00984 Sets whether debug output should be logged only 00985 */ 00986 function setLogOnly( $enabled ) 00987 { 00988 $GLOBALS['eZDebugLogOnly'] = $enabled; 00989 } 00990 00991 /*! 00992 \return an array with the available message types. 00993 */ 00994 function messageTypes() 00995 { 00996 return $this->MessageTypes; 00997 } 00998 00999 /*! 01000 Returns an associative array of all the log files used by this class 01001 where each key is the debug level (self::LEVEL_NOTICE, self::LEVEL_WARNING or self::LEVEL_ERROR or self::LEVEL_DEBUG). 01002 */ 01003 function logFiles() 01004 { 01005 return $this->LogFiles; 01006 } 01007 01008 /*! 01009 \static 01010 \return true if debug should be enabled. 01011 \note Will return false until the real settings has been updated with updateSettings() 01012 */ 01013 static function isDebugEnabled() 01014 { 01015 if ( isset( $GLOBALS['eZDebugEnabled'] ) ) 01016 { 01017 return $GLOBALS['eZDebugEnabled']; 01018 } 01019 01020 return false; 01021 } 01022 01023 /*! 01024 \static 01025 \return true if there should only be logging of debug strings to file. 01026 \note Will return false until the real settings has been updated with updateSettings() 01027 */ 01028 static function isLogOnlyEnabled() 01029 { 01030 if ( isset( $GLOBALS['eZDebugLogOnly'] ) ) 01031 { 01032 return $GLOBALS['eZDebugLogOnly']; 01033 } 01034 01035 return false; 01036 } 01037 01038 /*! 01039 \static 01040 Determine if an ipaddress is in a network. E.G. 120.120.120.120 in 120.120.0.0/24. 01041 \return true or false. 01042 */ 01043 static function isIPInNet( $ipaddress, $network, $mask = 24 ) 01044 { 01045 $lnet = ip2long( $network ); 01046 $lip = ip2long( $ipaddress ); 01047 $binnet = str_pad( decbin( $lnet ), 32, '0', STR_PAD_LEFT ); 01048 $firstpart = substr( $binnet, 0, $mask ); 01049 $binip = str_pad( decbin( $lip ), 32, '0', STR_PAD_LEFT ); 01050 $firstip = substr( $binip, 0, $mask ); 01051 return( strcmp( $firstpart, $firstip ) == 0 ); 01052 } 01053 01054 /*! 01055 \static 01056 Updates the settings for debug handling with the settings array \a $settings. 01057 The array must contain the following keys. 01058 - debug-enabled - boolean which controls debug handling 01059 - debug-by-ip - boolean which controls IP controlled debugging 01060 - debug-ip-list - array of IPs which gets debug 01061 - debug-by-user - boolean which controls userID controlled debugging 01062 - debug-user-list - array of UserIDs which gets debug 01063 */ 01064 static function updateSettings( $settings ) 01065 { 01066 // Make sure errors are handled by PHP when we read, including our own debug output. 01067 $oldHandleType = eZDebug::setHandleType( self::HANDLE_TO_PHP ); 01068 01069 if ( isset( $settings['debug-log-files-enabled'] ) ) 01070 { 01071 $GLOBALS['eZDebugLogFileEnabled'] = $settings['debug-log-files-enabled']; 01072 if ( isset( $GLOBALS["eZDebugGlobalInstance"] ) ) 01073 $GLOBALS["eZDebugGlobalInstance"]->GlobalLogFileEnabled = $settings['debug-log-files-enabled']; 01074 } 01075 01076 if ( isset( $settings['debug-styles'] ) ) 01077 { 01078 $GLOBALS['eZDebugStyles'] = $settings['debug-styles']; 01079 } 01080 01081 if ( isset( $settings['always-log'] ) and 01082 is_array( $settings['always-log'] ) ) 01083 { 01084 $GLOBALS['eZDebugAlwaysLog'] = $settings['always-log']; 01085 } 01086 01087 if ( isset( $settings['log-only'] ) ) 01088 { 01089 $GLOBALS['eZDebugLogOnly'] = ( $settings['log-only'] == 'enabled' ); 01090 } 01091 01092 $GLOBALS['eZDebugAllowedByIP'] = $settings['debug-by-ip'] ? self::isAllowedByCurrentIP( $settings['debug-ip-list'] ) : true; 01093 01094 // updateSettings is meant to be called before the user session is started 01095 // so we do not take debug-by-user into account yet, but store the debug-user-list in $GLOBALS 01096 // so it can be used in the final check, done by checkDebugByUser() 01097 if ( isset( $settings['debug-by-user'] ) && $settings['debug-by-user'] ) 01098 { 01099 $GLOBALS['eZDebugUserIDList'] = $settings['debug-user-list'] ? $settings['debug-user-list'] : array(); 01100 } 01101 01102 $GLOBALS['eZDebugAllowed'] = $GLOBALS['eZDebugAllowedByIP']; 01103 $GLOBALS['eZDebugEnabled'] = $settings['debug-enabled'] && $GLOBALS['eZDebugAllowedByIP']; 01104 01105 eZDebug::setHandleType( $oldHandleType ); 01106 } 01107 01108 /*! 01109 \static 01110 Final checking for debug by user id. 01111 Checks if we should enable debug. 01112 01113 Returns false if debug-by-user is not active, was already checked before 01114 or if there is no current user. Returns true otherwise. 01115 */ 01116 static function checkDebugByUser() 01117 { 01118 if ( !isset( $GLOBALS['eZDebugUserIDList'] ) || 01119 !is_array( $GLOBALS['eZDebugUserIDList'] ) ) 01120 { 01121 return false; 01122 } 01123 else 01124 { 01125 $currentUserID = eZUser::currentUserID(); 01126 01127 if ( !$currentUserID ) 01128 { 01129 return false; 01130 } 01131 else 01132 { 01133 $GLOBALS['eZDebugAllowedByUser'] = in_array( $currentUserID, $GLOBALS['eZDebugUserIDList'] ); 01134 01135 if ( $GLOBALS['eZDebugAllowed'] ) 01136 { 01137 $GLOBALS['eZDebugAllowed'] = $GLOBALS['eZDebugAllowedByUser']; 01138 } 01139 01140 if ( $GLOBALS['eZDebugEnabled'] ) 01141 { 01142 $GLOBALS['eZDebugEnabled'] = $GLOBALS['eZDebugAllowedByUser']; 01143 } 01144 01145 unset( $GLOBALS['eZDebugUserIDList'] ); 01146 01147 return true; 01148 } 01149 } 01150 } 01151 01152 /*! 01153 \static 01154 Prints the debug report 01155 */ 01156 static function printReport( $newWindow = false, $as_html = true, $returnReport = false, 01157 $allowedDebugLevels = false, $useAccumulators = true, $useTiming = true, $useIncludedFiles = false ) 01158 { 01159 if ( !self::isDebugEnabled() ) 01160 return null; 01161 01162 $debug = self::instance(); 01163 $report = $debug->printReportInternal( $as_html, $returnReport & $newWindow, $allowedDebugLevels, $useAccumulators, $useTiming, $useIncludedFiles ); 01164 01165 if ( $newWindow == true ) 01166 { 01167 $debugFilePath = eZDir::path( array( eZSys::varDirectory(), 'cache', 'debug.html' ) ); 01168 $debugFileURL = $debugFilePath; 01169 eZURI::transformURI( $debugFileURL, true ); 01170 print( " 01171 <script type='text/javascript'> 01172 <!-- 01173 01174 (function() 01175 { 01176 var debugWindow; 01177 01178 if (navigator.appName == \"Microsoft Internet Explorer\") 01179 { 01180 //Microsoft Internet Explorer 01181 debugWindow = window.open( '$debugFileURL', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40'); 01182 debugWindow.document.close(); 01183 debugWindow.location.reload(); 01184 } 01185 else if (navigator.appName == \"Opera\") 01186 { 01187 //Opera 01188 debugWindow = window.open( '', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40'); 01189 debugWindow.location.href=\"$debugFileURL\"; 01190 debugWindow.navigate(\"$debugFileURL\"); 01191 } 01192 else 01193 { 01194 //Mozilla, Firefox, etc. 01195 debugWindow = window.open( '', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40'); 01196 debugWindow.document.location.href=\"$debugFileURL\"; 01197 }; 01198 })(); 01199 01200 // --> 01201 </script> 01202 " ); 01203 $header = "<!DOCTYPE html><html><head><title>eZ debug</title></head><body>"; 01204 $footer = "</body></html>"; 01205 $fullPage = ezpEvent::getInstance()->filter( 'response/output', $header . $report . $footer ); 01206 file_put_contents( $debugFilePath, $fullPage ); 01207 } 01208 else 01209 { 01210 if ( $returnReport ) 01211 return $report; 01212 } 01213 return null; 01214 } 01215 01216 /** 01217 * Returns the microtime as a float value. $mtime must be in microtime() format. 01218 * @deprecated Since 4.4.0, use microtime( true ) instead 01219 */ 01220 static function timeToFloat( $mtime ) 01221 { 01222 $tTime = explode( " ", $mtime ); 01223 preg_match( "#0\.([0-9]+)#", "" . $tTime[0], $t1 ); 01224 $time = $tTime[1] . "." . $t1[1]; 01225 return $time; 01226 } 01227 01228 /*! 01229 Sets the time of the start of the script ot \a $time. 01230 If \a $time is not supplied it gets the current \c microtime( true ). 01231 This is used to calculate total execution time and percentages. 01232 */ 01233 static function setScriptStart( $time = false ) 01234 { 01235 if ( $time == false ) 01236 $time = microtime( true ); 01237 $debug = eZDebug::instance(); 01238 $debug->ScriptStart = $time; 01239 } 01240 01241 /*! 01242 Sets the time of the stop of the script ot \a $time. 01243 If \a $time is not supplied it gets the current \c microtime( true ). 01244 This is used to calculate total execution time and percentages. 01245 */ 01246 static function setScriptStop( $time = false ) 01247 { 01248 if ( $time === false ) 01249 $time = microtime( true ); 01250 $debug = eZDebug::instance(); 01251 $debug->ScriptStop = $time; 01252 } 01253 01254 /*! 01255 Creates an accumulator group with key \a $key and group name \a $name. 01256 If \a $name is not supplied name is taken from \a $key. 01257 */ 01258 static function createAccumulatorGroup( $key, $name = false ) 01259 { 01260 if ( !eZDebug::isDebugEnabled() ) 01261 return; 01262 if ( $name == '' or 01263 $name === false ) 01264 $name = $key; 01265 $debug = eZDebug::instance(); 01266 if ( !array_key_exists( $key, $debug->TimeAccumulatorList ) ) 01267 $debug->TimeAccumulatorList[$key] = array( 'name' => $name, 'time' => 0, 'count' => 0, 'is_group' => true, 'in_group' => false ); 01268 if ( !array_key_exists( $key, $debug->TimeAccumulatorGroupList ) ) 01269 $debug->TimeAccumulatorGroupList[$key] = array(); 01270 } 01271 01272 /*! 01273 Creates a new accumulator entry if one does not already exist and initializes with default data. 01274 If \a $name is not supplied name is taken from \a $key. 01275 If \a $inGroup is supplied it will place the accumulator under the specified group. 01276 */ 01277 static function createAccumulator( $key, $inGroup = false, $name = false ) 01278 { 01279 if ( !eZDebug::isDebugEnabled() ) 01280 return; 01281 if ( $name == '' or 01282 $name === false ) 01283 $name = $key; 01284 $debug = eZDebug::instance(); 01285 $isGroup = false; 01286 if ( array_key_exists( $key, $debug->TimeAccumulatorList ) and 01287 array_key_exists( $key, $debug->TimeAccumulatorGroupList ) ) 01288 $isGroup = true; 01289 $debug->TimeAccumulatorList[$key] = array( 'name' => $name, 'time' => 0, 'count' => 0, 'is_group' => $isGroup, 'in_group' => $inGroup ); 01290 if ( $inGroup !== false ) 01291 { 01292 $groupKeys = array(); 01293 if ( array_key_exists( $inGroup, $debug->TimeAccumulatorGroupList ) ) 01294 $groupKeys = $debug->TimeAccumulatorGroupList[$inGroup]; 01295 $debug->TimeAccumulatorGroupList[$inGroup] = array_unique( array_merge( $groupKeys, array( $key ) ) ); 01296 if ( array_key_exists( $inGroup, $debug->TimeAccumulatorList ) ) 01297 $debug->TimeAccumulatorList[$inGroup]['is_group'] = true; 01298 } 01299 } 01300 01301 /*! 01302 Starts an time count for the accumulator \a $key. 01303 You can also specify a name which will be displayed. 01304 */ 01305 static function accumulatorStart( $key, $inGroup = false, $name = false, $recursive = false ) 01306 { 01307 if ( !eZDebug::isDebugEnabled() ) 01308 return; 01309 $startTime = microtime( true ); 01310 $debug = eZDebug::instance(); 01311 $key = $key === false ? 'Default Debug-Accumulator' : $key; 01312 if ( ! array_key_exists( $key, $debug->TimeAccumulatorList ) ) 01313 { 01314 $debug->createAccumulator( $key, $inGroup, $name ); 01315 } 01316 01317 if ( $recursive ) 01318 { 01319 if ( isset( $debug->TimeAccumulatorList[$key]['recursive_counter'] ) ) 01320 { 01321 $debug->TimeAccumulatorList[$key]['recursive_counter']++; 01322 return; 01323 } 01324 $debug->TimeAccumulatorList[$key]['recursive_counter'] = 0; 01325 } 01326 01327 $debug->TimeAccumulatorList[$key]['temp_time'] = $startTime; 01328 } 01329 01330 /*! 01331 Stops a previous time count and adds the total time to the accumulator \a $key. 01332 */ 01333 static function accumulatorStop( $key, $recursive = false ) 01334 { 01335 if ( !eZDebug::isDebugEnabled() ) 01336 return; 01337 $stopTime = microtime( true ); 01338 $debug = eZDebug::instance(); 01339 $key = $key === false ? 'Default Debug-Accumulator' : $key; 01340 if ( ! array_key_exists( $key, $debug->TimeAccumulatorList ) ) 01341 { 01342 eZDebug::writeWarning( "Accumulator '$key' does not exist, run eZDebug::accumulatorStart first", __METHOD__ ); 01343 return; 01344 } 01345 $accumulator = $debug->TimeAccumulatorList[$key]; 01346 if ( $recursive ) 01347 { 01348 if ( isset( $accumulator['recursive_counter'] ) ) 01349 { 01350 if ( $accumulator['recursive_counter'] > 0 ) 01351 { 01352 $accumulator['recursive_counter']--; 01353 return; 01354 } 01355 } 01356 } 01357 $diffTime = $stopTime - $accumulator['temp_time']; 01358 $accumulator['time'] = $accumulator['time'] + $diffTime; 01359 ++$accumulator['count']; 01360 $debug->TimeAccumulatorList[$key] = $accumulator; 01361 } 01362 01363 01364 /*! 01365 \private 01366 Prints a full debug report with notice, warnings, errors and a timing report. 01367 */ 01368 function printReportInternal( $as_html = true, $returnReport = true, $allowedDebugLevels = false, 01369 $useAccumulators = true, $useTiming = true, $useIncludedFiles = false ) 01370 { 01371 $reportStart = microtime( true ); 01372 01373 if ( isset( $GLOBALS['eZDebugStyles'] ) ) 01374 { 01375 $styles = $GLOBALS['eZDebugStyles']; 01376 } 01377 else 01378 { 01379 $styles = array( 'strict' => false, 01380 'strict-end' => false, 01381 'warning' => false, 01382 'warning-end' => false, 01383 'error' => false, 01384 'error-end' => false, 01385 'debug' => false, 01386 'debug-end' => false, 01387 'notice' => false, 01388 'notice-end' => false, 01389 'timing' => false, 01390 'timing-end' => false, 01391 'mark' => false, 01392 'mark-end' => false, 01393 'emphasize' => false, 01394 'emphasize-end' => false, 01395 'bold' => false, 01396 'bold-end' => false ); 01397 } 01398 if ( !$allowedDebugLevels ) 01399 { 01400 $allowedDebugLevels = array( self::LEVEL_NOTICE, self::LEVEL_WARNING, self::LEVEL_ERROR, 01401 self::LEVEL_DEBUG, self::LEVEL_TIMING_POINT, self::LEVEL_STRICT ); 01402 } 01403 01404 $startTime = $this->ScriptStart; 01405 if ( $this->ScriptStop == null ) 01406 { 01407 $endTime = $reportStart; 01408 } 01409 else 01410 { 01411 $endTime = $this->ScriptStop; 01412 } 01413 $totalElapsed = $endTime - $startTime; 01414 if ( function_exists( 'memory_get_peak_usage' ) ) 01415 { 01416 $peakMemory = memory_get_peak_usage( true ); 01417 } 01418 01419 if ( $returnReport ) 01420 { 01421 ob_start(); 01422 } 01423 01424 if ( $as_html ) 01425 { 01426 echo "<div id=\"debug\"><h2>eZ debug</h2>"; 01427 01428 if ( !$this->UseCSS ) 01429 { 01430 echo "<style type='text/css'> 01431 <!-- 01432 "; 01433 readfile( 'design/standard/stylesheets/debug.css' ); 01434 echo " 01435 --> 01436 </style>"; 01437 } 01438 echo "<table title='Table for actual debug output, shows notices, warnings and errors'>"; 01439 } 01440 01441 $this->printTopReportsList(); 01442 01443 $hasLevel = array( self::LEVEL_NOTICE => false, 01444 self::LEVEL_WARNING => false, 01445 self::LEVEL_ERROR => false, 01446 self::LEVEL_TIMING_POINT => false, 01447 self::LEVEL_DEBUG => false, 01448 self::LEVEL_STRICT => false ); 01449 01450 foreach ( $this->DebugStrings as $debug ) 01451 { 01452 if ( !in_array( $debug['Level'], $allowedDebugLevels ) ) 01453 continue; 01454 $time = strftime ("%b %d %Y %H:%M:%S", $debug['Time'] ); 01455 01456 $outputData = $this->OutputFormat[$debug["Level"]]; 01457 if ( is_array( $outputData ) ) 01458 { 01459 $identifierText = ''; 01460 if ( !$hasLevel[$debug['Level']] ) 01461 { 01462 $hasLevel[$debug['Level']] = true; 01463 $identifierText = ' id="' . $outputData['xhtml-identifier'] . '"'; 01464 } 01465 $style = $outputData["style"]; 01466 $name = $outputData["name"]; 01467 $label = $debug["Label"]; 01468 $bgclass = $debug["BackgroundClass"]; 01469 $pre = ($bgclass != '' ? " class='$bgclass'" : ''); 01470 if ( $as_html ) 01471 { 01472 $label = htmlspecialchars( $label ); 01473 01474 $contents = ''; 01475 if ( extension_loaded( 'xdebug' ) && ( strncmp( self::XDEBUG_SIGNATURE, $debug['String'], strlen( self::XDEBUG_SIGNATURE ) ) === 0 ) ) 01476 $contents = substr( $debug['String'], strlen( self::XDEBUG_SIGNATURE ) ); 01477 else 01478 $contents = htmlspecialchars( $debug['String'] ); 01479 01480 echo "<tr class='$style'><td class='debugheader'$identifierText><b><span>$name:</span> $label</b></td> 01481 <td class='debugheader'>$time</td></tr> 01482 <tr><td colspan='2'><pre$pre>" . $contents . "</pre></td></tr>"; 01483 } 01484 else 01485 { 01486 echo $styles[$outputData['style']] . "$name:" . $styles[$outputData['style'].'-end'] . " "; 01487 echo $styles['bold'] . "($label)" . $styles['bold-end'] . "\n" . $debug["String"] . "\n\n"; 01488 } 01489 } 01490 } 01491 if ( $as_html ) 01492 { 01493 echo "</table>"; 01494 01495 // Resources we always print out, just like log messages 01496 01497 echo "<h3>Main resources:</h3>"; 01498 echo "<table id='debug_resources' title='Most important resource consumption indicators'>"; 01499 } 01500 if ( $as_html ) 01501 { 01502 echo "<tr class='data'><td>Total runtime</td><td>" . 01503 number_format( $totalElapsed, $this->TimingAccuracy ) . " sec</td></tr>"; 01504 } 01505 else 01506 { 01507 echo "Total runtime: " . 01508 number_format( $totalElapsed, $this->TimingAccuracy ) . " sec\n"; 01509 } 01510 if ( isset( $peakMemory ) ) 01511 { 01512 if ( $as_html ) 01513 { 01514 echo "<tr class='data'><td>Peak memory usage</td><td>" . 01515 number_format( $peakMemory / 1024, $this->TimingAccuracy ) . " KB</td></tr>"; 01516 } 01517 else 01518 { 01519 echo "Peak memory usage: " . 01520 number_format( $peakMemory / 1024, $this->TimingAccuracy ) . " KB\n"; 01521 } 01522 } 01523 $dbini = eZINI::instance(); 01524 // note: we cannot use $db->databasename() because we get the same for mysql and mysqli 01525 $type = preg_replace( '/^ez/', '', $dbini->variable( 'DatabaseSettings', 'DatabaseImplementation' ) ); 01526 $type .= '_query'; 01527 if ( isset( $this->TimeAccumulatorList[$type] ) ) 01528 { 01529 if ( $as_html ) 01530 { 01531 echo "<tr class='data'><td>Database Queries</td><td>" . 01532 $this->TimeAccumulatorList[$type]['count'] . "</td></tr>"; 01533 } 01534 else 01535 { 01536 echo "Database Queries: " . 01537 $this->TimeAccumulatorList[$type]['count'] . "\n"; 01538 } 01539 } 01540 if ( $as_html ) 01541 { 01542 echo "</table>"; 01543 } 01544 01545 if ( $useTiming ) 01546 { 01547 if ( $as_html ) 01548 { 01549 echo "<h3>Timing points:</h3>"; 01550 echo "<table id='timingpoints' title='Timing point stats'><tr><th>Checkpoint</th><th>Start (sec)</th><th>Duration (sec)</th><th>Memory at start (KB)</th><th>Memory used (KB)</th></tr>"; 01551 } 01552 01553 for ( $i = 0, $l = count( $this->TimePoints ); $i < $l; ++$i ) 01554 { 01555 $point = $this->TimePoints[$i]; 01556 $nextPoint = false; 01557 if ( isset( $this->TimePoints[$i + 1] ) ) 01558 $nextPoint = $this->TimePoints[$i + 1]; 01559 $time = $point["Time"]; 01560 $nextTime = false; 01561 $elapsed = $time - $startTime; 01562 01563 $relMemory = 0; 01564 $memory = $point["MemoryUsage"]; 01565 // Calculate relative time and memory usage 01566 if ( $nextPoint !== false ) 01567 { 01568 $nextTime = $nextPoint["Time"]; 01569 $relElapsed = $nextTime - $time; 01570 $relElapsed = number_format( $relElapsed, $this->TimingAccuracy ); 01571 01572 $nextMemory = $nextPoint["MemoryUsage"]; 01573 $relMemory = $nextMemory - $memory; 01574 $relMemory = number_format( $relMemory / 1024, $this->TimingAccuracy ); 01575 } 01576 else 01577 { 01578 $relElapsed = $as_html ? ' ' : ''; 01579 $relMemory = $as_html ? ' ' : ''; 01580 } 01581 01582 // Convert memory usage to human readable 01583 $memory = number_format( $memory / 1024, $this->TimingAccuracy ); 01584 $elapsed = number_format( $elapsed, $this->TimingAccuracy ); 01585 01586 if ( $as_html ) 01587 { 01588 echo "<tr class='data'><td>" . $point["Description"] . "</td> 01589 <td align=\"right\">$elapsed</td><td align=\"right\">$relElapsed</td> 01590 <td align=\"right\">$memory</td><td align=\"right\">$relMemory</td></tr>"; 01591 } 01592 else 01593 { 01594 echo $point["Description"] . ' ' . $elapsed . $relElapsed . "\n"; 01595 } 01596 } 01597 01598 if ( $as_html ) 01599 { 01600 echo "</table>"; 01601 } 01602 } 01603 01604 if ( $useAccumulators ) 01605 { 01606 $timeList = $this->TimeAccumulatorList; 01607 $groups = $this->TimeAccumulatorGroupList; 01608 $groupList = array(); 01609 foreach ( $groups as $groupKey => $keyList ) 01610 { 01611 if ( count( $keyList ) == 0 and 01612 !array_key_exists( $groupKey, $timeList ) ) 01613 continue; 01614 $groupList[$groupKey] = array( 'name' => $groupKey ); 01615 if ( array_key_exists( $groupKey, $timeList ) ) 01616 { 01617 if ( $timeList[$groupKey]['time'] != 0 ) 01618 $groupList[$groupKey]['time_data'] = $timeList[$groupKey]; 01619 $groupList[$groupKey]['name'] = $timeList[$groupKey]['name']; 01620 unset( $timeList[$groupKey] ); 01621 } 01622 $groupChildren = array(); 01623 foreach ( $keyList as $timeKey ) 01624 { 01625 if ( array_key_exists( $timeKey, $timeList ) ) 01626 { 01627 $groupChildren[] = $timeList[$timeKey]; 01628 unset( $timeList[$timeKey] ); 01629 } 01630 } 01631 $groupList[$groupKey]['children'] = $groupChildren; 01632 } 01633 if ( count( $timeList ) > 0 ) 01634 { 01635 $groupList['general'] = array( 'name' => 'General', 01636 'children' => $timeList ); 01637 } 01638 01639 if ( $as_html ) 01640 { 01641 echo "<h3>Time accumulators:</h3>"; 01642 echo "<table id='timeaccumulators' title='Detailed list of time accumulators'><tr><th> Accumulator</th><th> Duration (sec)</th><th> Duration (%)</th><th> Count</th><th> Average (sec)</th></tr>"; 01643 } 01644 01645 foreach ( $groupList as $group ) 01646 { 01647 $groupName = $group['name']; 01648 $groupChildren = $group['children']; 01649 if ( count( $groupChildren ) == 0 and 01650 !array_key_exists( 'time_data', $group ) ) 01651 continue; 01652 if ( $as_html ) 01653 echo "<tr class='group'><td><b>$groupName</b></td>"; 01654 else 01655 echo "Group " . $styles['mark'] . "$groupName:" . $styles['mark-end'] . " "; 01656 if ( array_key_exists( 'time_data', $group ) ) 01657 { 01658 $groupData = $group['time_data']; 01659 $groupElapsed = number_format( ( $groupData['time'] ), $this->TimingAccuracy ); 01660 $groupPercent = number_format( ( $groupData['time'] * 100.0 ) / $totalElapsed, 1 ); 01661 $groupCount = $groupData['count']; 01662 $groupAverage = number_format( ( $groupData['time'] / $groupData['count'] ), $this->TimingAccuracy ); 01663 if ( $as_html ) 01664 { 01665 echo ( "<td align=\"right\"><i>$groupElapsed</i></td>". 01666 "<td align=\"right\"><i>$groupPercent</i></td>". 01667 "<td align=\"right\"><i>$groupCount</i></td>". 01668 "<td align=\"right\"><i>$groupAverage</i></td>" ); 01669 } 01670 else 01671 { 01672 echo $styles['emphasize'] . "$groupElapsed" . $styles['emphasize-end'] . " sec ($groupPercent%), $groupAverage avg sec ($groupCount)"; 01673 } 01674 } 01675 else if ( $as_html ) 01676 { 01677 echo ( "<td></td>". 01678 "<td></td>". 01679 "<td></td>". 01680 "<td></td>" ); 01681 } 01682 if ( $as_html ) 01683 echo "</tr>"; 01684 else 01685 echo "\n"; 01686 01687 foreach ( $groupChildren as $child ) 01688 { 01689 $childName = $child['name']; 01690 $childElapsed = number_format( ( $child['time'] ), $this->TimingAccuracy ); 01691 $childPercent = number_format( ( $child['time'] * 100.0 ) / $totalElapsed, $this->PercentAccuracy ); 01692 $childCount = $child['count']; 01693 $childAverage = 0.0; 01694 if ( $childCount > 0 ) 01695 { 01696 $childAverage = $child['time'] / $childCount; 01697 } 01698 $childAverage = number_format( $childAverage, $this->PercentAccuracy ); 01699 01700 if ( $as_html ) 01701 { 01702 echo ( "<tr class='data'>" . 01703 "<td>$childName</td>" . 01704 "<td align=\"right\">$childElapsed</td>" . 01705 "<td align=\"right\">$childPercent</td>" . 01706 "<td align=\"right\">$childCount</td>" . 01707 "<td align=\"right\">$childAverage</td>" . 01708 "</tr>" ); 01709 } 01710 else 01711 { 01712 echo "$childName: " . $styles['emphasize'] . $childElapsed . $styles['emphasize-end'] . " sec ($childPercent%), $childAverage avg sec ($childCount)\n"; 01713 } 01714 } 01715 } 01716 01717 if ( $as_html ) 01718 { 01719 echo "<tr><td colspan=\"5\">Note: percentages do not add up to 100% because some accumulators overlap</td></tr>"; 01720 echo "</table>"; 01721 } 01722 } 01723 01724 if ( $useIncludedFiles ) 01725 { 01726 if ( $as_html ) 01727 { 01728 echo "<h3>Included files:</h3><table id=\"debug_includes\" title='List of included php files used in the processing of this page'><tr><th>File</th></tr>"; 01729 } 01730 else 01731 { 01732 echo $styles['emphasize'] . "Includes" . $styles['emphasize-end'] . "\n"; 01733 } 01734 $phpFiles = get_included_files(); 01735 $currentPathReg = preg_quote( realpath( "." ) ); 01736 foreach ( $phpFiles as $phpFile ) 01737 { 01738 if ( preg_match( "#^$currentPathReg/(.+)$#", $phpFile, $matches ) ) 01739 $phpFile = $matches[1]; 01740 if ( $as_html ) 01741 { 01742 echo "<tr class='data'><td>$phpFile</td></tr>"; 01743 } 01744 else 01745 { 01746 echo "$phpFile\n"; 01747 } 01748 } 01749 if ( $as_html ) 01750 { 01751 echo "<tr><td><b> Number of files included: " . count( $phpFiles ) . "</b></td></tr>"; 01752 echo "</table>"; 01753 } 01754 } 01755 01756 $this->printBottomReportsList( $as_html ); 01757 01758 if ( $as_html ) 01759 { 01760 $reportStop = microtime( true ); 01761 $reportTime = number_format( $reportStop - $reportStart, 4 ); 01762 echo "<p><b>Time used to render debug report: $reportTime secs</b></p>"; 01763 01764 echo "</div>"; 01765 } 01766 01767 if ( $returnReport ) 01768 { 01769 $returnText = ob_get_contents(); 01770 ob_end_clean(); 01771 return $returnText; 01772 } 01773 else 01774 { 01775 return NULL; 01776 } 01777 } 01778 01779 /*! 01780 Appends report to 'top' reports list. 01781 */ 01782 static function appendTopReport( $reportName, $reportContent ) 01783 { 01784 $debug = eZDebug::instance(); 01785 $debug->topReportsList[$reportName] = $reportContent; 01786 } 01787 01788 /*! 01789 Prints all 'top' reports 01790 */ 01791 static function printTopReportsList() 01792 { 01793 $debug = eZDebug::instance(); 01794 $reportNames = array_keys( $debug->topReportsList ); 01795 foreach ( $reportNames as $reportName ) 01796 { 01797 echo $debug->topReportsList[$reportName]; 01798 } 01799 } 01800 01801 /*! 01802 Appends report to 'bottom' reports list. 01803 */ 01804 static function appendBottomReport( $reportName, $reportContent ) 01805 { 01806 $debug = eZDebug::instance(); 01807 $debug->bottomReportsList[$reportName] = $reportContent; 01808 } 01809 01810 /** 01811 * Loop over all bottom reports and if callable call them with $as_html parameter, 01812 * if not output as is (string). 01813 * 01814 * @param bool $as_html 01815 */ 01816 static function printBottomReportsList( $as_html = true ) 01817 { 01818 $debug = eZDebug::instance(); 01819 $reportNames = array_keys( $debug->bottomReportsList ); 01820 foreach ( $reportNames as $reportName ) 01821 { 01822 if ( is_callable( $debug->bottomReportsList[$reportName] ) ) 01823 { 01824 echo call_user_func_array( $debug->bottomReportsList[$reportName], array( $as_html ) ); 01825 } 01826 else 01827 { 01828 echo $debug->bottomReportsList[$reportName]; 01829 } 01830 } 01831 } 01832 01833 /*! 01834 If debugging is allowed, given the limitations of the DebugByIP and DebugByUser settings. 01835 */ 01836 function isDebugAllowed() 01837 { 01838 01839 } 01840 01841 /*! 01842 If debugging is allowed for the current IP address. 01843 */ 01844 private static function isAllowedByCurrentIP( $allowedIpList ) 01845 { 01846 $ipAddress = eZSys::clientIP(); 01847 if ( $ipAddress ) 01848 { 01849 foreach( $allowedIpList as $itemToMatch ) 01850 { 01851 if ( preg_match("/^(([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+))(\/([0-9]+)$|$)/", $itemToMatch, $matches ) ) 01852 { 01853 if ( $matches[6] ) 01854 { 01855 if ( self::isIPInNet( $ipAddress, $matches[1], $matches[7] ) ) 01856 { 01857 return true; 01858 } 01859 } 01860 else 01861 { 01862 if ( $matches[1] == $ipAddress ) 01863 { 01864 return true; 01865 } 01866 } 01867 } 01868 } 01869 01870 return false; 01871 } 01872 else 01873 { 01874 return eZSys::isShellExecution() && in_array( 'commandline', $allowedIpList ); 01875 } 01876 } 01877 01878 /** 01879 * Exception based error handler, very basic 01880 * @since 4.5 01881 * @throws ErrorException 01882 */ 01883 public static function exceptionErrorHandler( $errno, $errstr, $errfile, $errline ) 01884 { 01885 throw new ErrorException($errstr, 0, $errno, $errfile, $errline); 01886 } 01887 01888 /// \privatesection 01889 /// String array containing the debug information 01890 public $DebugStrings = array(); 01891 01892 /// Array which contains the time points 01893 public $TimePoints = array(); 01894 01895 /// Array which contains the temporary time points 01896 public $TmpTimePoints; 01897 01898 /// Array wich contains time accumulators 01899 public $TimeAccumulatorList = array(); 01900 01901 /// Determines which debug messages should be shown 01902 public $ShowTypes; 01903 01904 /// Determines what to do with php errors, ignore, fetch or output 01905 public $HandleType; 01906 01907 /// An array of the outputformats for the different debug levels 01908 public $OutputFormat; 01909 01910 /// An array of logfiles used by the debug class with each key being the debug level 01911 public $LogFiles; 01912 01913 /// How many places behind . should be displayed when showing times 01914 public $TimingAccuracy = 4; 01915 01916 /// How many places behind . should be displayed when showing percentages 01917 public $PercentAccuracy = 4; 01918 01919 /// Whether to use external CSS or output own CSS. True if external is to be used. 01920 public $UseCSS; 01921 01922 /// Determines how messages are output (screen/log) 01923 public $MessageOutput; 01924 01925 /// A list of message types 01926 public $MessageTypes; 01927 01928 /// A map with message types and whether they should do file logging. 01929 public $LogFileEnabled; 01930 01931 /// Controls whether logfiles are used at all. 01932 public $GlobalLogFileEnabled; 01933 01934 /// The time when the script was started 01935 public $ScriptStart; 01936 01937 /// The time when the script was stopped (of course this is an approximation, 01938 /// since the script must stop after printing debug info) 01939 public $ScriptStop; 01940 01941 /// A list of override directories 01942 public $OverrideList; 01943 01944 /// A list of debug reports that appears at the bottom of debug output 01945 public $bottomReportsList; 01946 01947 /// A list of debug reports that appears at the top of debug output 01948 public $topReportsList; 01949 01950 private $recursionFlag = false; 01951 } 01952 01953 ?>