eZ Publish  [trunk]
ezdebug.php
Go to the documentation of this file.
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 ? '&nbsp;' : '';
01579                     $relMemory = $as_html ? '&nbsp;' : '';
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>&nbsp;Accumulator</th><th>&nbsp;Duration (sec)</th><th>&nbsp;Duration (%)</th><th>&nbsp;Count</th><th>&nbsp;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>&nbsp;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 ?>