Subversion Repositories bysoftdeveloper

[/] [kernel/] [ezdebug.php] - Blame information for rev 31

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 cavin.deng
<?php
2
//
3
// Definition of eZDebug class
4
//
5
// Created on: <12-Feb-2002 11:00:54 bf>
6
//
7
// ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
8
// SOFTWARE NAME: eZ Publish
9
// SOFTWARE RELEASE: 4.4.0
10
// COPYRIGHT NOTICE: Copyright (C) 1999-2010 eZ Systems AS
11
// SOFTWARE LICENSE: GNU General Public License v2.0
12
// NOTICE: >
13
//   This program is free software; you can redistribute it and/or
14
//   modify it under the terms of version 2.0  of the GNU General
15
//   Public License as published by the Free Software Foundation.
16
//
17
//   This program is distributed in the hope that it will be useful,
18
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
//   GNU General Public License for more details.
21
//
22
//   You should have received a copy of version 2.0 of the GNU General
23
//   Public License along with this program; if not, write to the Free
24
//   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25
//   MA 02110-1301, USA.
26
// ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
27
//
28
 
29
/*! \defgroup eZUtils Utility classes */
30
 
31
/*!
32
  \class eZDebug ezdebug.php
33
  \ingroup eZUtils
34
  \brief Advanced debug/log system
35
 
36
  The eZ debug library is used to handle debug information. It
37
  can display information on screen and/or write it to log files.
38
 
39
  You can enable on-screen debug information for specific IP addresses.
40
 
41
  Timing points can be placed in the code to time the different sections of code.
42
 
43
  Each debug message can be turned on/off by using the showTypes() function.
44
 
45
  PHP error messages can also be shown using setHandleType().
46
 
47
  \code
48
 
49
  // write a temporary debug message
50
  eZDebug::writeDebug( "Test" );
51
 
52
  // write a notice
53
  eZDebug::writeNotice( "Image found" );
54
 
55
  // write a warning
56
  eZDebug::writeWarning( "Image not found, using default" );
57
 
58
  // write an error
59
  eZDebug::writeError( "Object not found, bailing.." );
60
 
61
  // add a timing points
62
  eZDebug::addTimingPoint( "Module Found" );
63
 
64
  //.... code
65
 
66
  eZDebug::addTimingPoint( "Module loading" );
67
 
68
  // print the results on screen.
69
  eZDebug::printReport();
70
 
71
  \endcode
72
*/
73
 
74
@include_once('extension/bysoftdeveloper/kernel/eztemplatesstatisticsreporter.php');
75
class eZDebug
76
{
77
    const LEVEL_NOTICE = 1;
78
    const LEVEL_WARNING = 2;
79
    const LEVEL_ERROR = 3;
80
    const LEVEL_TIMING_POINT = 4;
81
    const LEVEL_DEBUG = 5;
82
    const LEVEL_STRICT = 6;
83
 
84
    const SHOW_NOTICE = 1; // 1 << (EZ_LEVEL_NOTICE - 1)
85
    const SHOW_WARNING = 2; // 1 << (EZ_LEVEL_WARNING - 1)
86
    const SHOW_ERROR = 4; // 1 << (EZ_LEVEL_ERROR - 1)
87
    const SHOW_TIMING_POINT = 8; // 1 << (EZ_LEVEL_TIMING_POINT - 1)
88
    const SHOW_DEBUG = 16; // 1 << (EZ_LEVEL_DEBUG - 1)
89
    const SHOW_STRICT = 32; // 1 << (EZ_LEVEL_STRICT - 1)
90
    const SHOW_ALL = 63; // EZ_SHOW_NOTICE | EZ_SHOW_WARNING | EZ_SHOW_ERROR | EZ_SHOW_TIMING_POINT | EZ_SHOW_DEBUG | EZ_SHOW_STRICT
91
 
92
    const HANDLE_NONE = 0;
93
    const HANDLE_FROM_PHP = 1;
94
    const HANDLE_TO_PHP = 2;
95 30 cavin.deng
    const HANDLE_EXCEPTION = 3;
96 5 cavin.deng
 
97
    const OUTPUT_MESSAGE_SCREEN = 1;
98
    const OUTPUT_MESSAGE_STORE = 2;
99
 
100
    const MAX_LOGFILE_SIZE = 204800; // 200*1024
101
    const MAX_LOGROTATE_FILES = 3;
102
 
103
    const XDEBUG_SIGNATURE = '--XDEBUG--';
104
    /*!
105
      Creates a new debug object.
106
    */
107
    function __construct( )
108
    {
109
        $this->TmpTimePoints = array( self::LEVEL_NOTICE => array(),
110
                                      self::LEVEL_WARNING => array(),
111
                                      self::LEVEL_ERROR => array(),
112
                                      self::LEVEL_DEBUG => array(),
113
                                      self::LEVEL_STRICT => array() );
114
 
115
        $this->OutputFormat = array( self::LEVEL_NOTICE => array( "color" => "green",
116
                                                               'style' => 'notice',
117
                                                               'xhtml-identifier' => 'ezdebug-first-notice',
118
                                                               "name" => "Notice" ),
119
                                     self::LEVEL_WARNING => array( "color" => "orange",
120
                                                                'style' => 'warning',
121
                                                                'xhtml-identifier' => 'ezdebug-first-warning',
122
                                                                "name" => "Warning" ),
123
                                     self::LEVEL_ERROR => array( "color" => "red",
124
                                                              'style' => 'error',
125
                                                              'xhtml-identifier' => 'ezdebug-first-error',
126
                                                              "name" => "Error" ),
127
                                     self::LEVEL_DEBUG => array( "color" => "brown",
128
                                                              'style' => 'debug',
129
                                                              'xhtml-identifier' => 'ezdebug-first-debug',
130
                                                              "name" => "Debug" ),
131
                                     self::LEVEL_TIMING_POINT => array( "color" => "blue",
132
                                                                     'style' => 'timing',
133
                                                                     'xhtml-identifier' => 'ezdebug-first-timing-point',
134
                                                                     "name" => "Timing" ),
135
                                     self::LEVEL_STRICT => array( "color" => "purple",
136
                                                              'style' => 'strict',
137
                                                              'xhtml-identifier' => 'ezdebug-first-strict',
138
                                                              'name' => 'Strict' ) );
139
        $this->LogFiles = array( self::LEVEL_NOTICE => array( "var/log/",
140
                                                           "notice.log" ),
141
                                 self::LEVEL_WARNING => array( "var/log/",
142
                                                            "warning.log" ),
143
                                 self::LEVEL_ERROR => array( "var/log/",
144
                                                          "error.log" ),
145
                                 self::LEVEL_DEBUG => array( "var/log/",
146
                                                          "debug.log" ),
147
                                 self::LEVEL_STRICT => array( 'var/log/',
148
                                                           'strict.log' ) );
149
        $this->MessageTypes = array( self::LEVEL_NOTICE,
150
                                     self::LEVEL_WARNING,
151
                                     self::LEVEL_ERROR,
152
                                     self::LEVEL_TIMING_POINT,
153
                                     self::LEVEL_DEBUG,
154
                                     self::LEVEL_STRICT );
155
        $this->MessageNames = array( self::LEVEL_NOTICE => 'Notice',
156
                                     self::LEVEL_WARNING => 'Warning',
157
                                     self::LEVEL_ERROR => 'Error',
158
                                     self::LEVEL_TIMING_POINT => 'TimingPoint',
159
                                     self::LEVEL_DEBUG => 'Debug',
160
                                     self::LEVEL_STRICT => 'Strict' );
161
        $this->LogFileEnabled = array( self::LEVEL_NOTICE => true,
162
                                       self::LEVEL_WARNING => true,
163
                                       self::LEVEL_ERROR => true,
164
                                       self::LEVEL_TIMING_POINT => true,
165
                                       self::LEVEL_DEBUG => true,
166
                                       self::LEVEL_STRICT => true );
167
        $this->AlwaysLog = array( self::LEVEL_NOTICE => false,
168
                                  self::LEVEL_WARNING => false,
169
                                  self::LEVEL_ERROR => true, // Error is on by default, due to its importance
170
                                  self::LEVEL_TIMING_POINT => false,
171
                                  self::LEVEL_DEBUG => false,
172
                                  self::LEVEL_STRICT => false );
173
        $this->GlobalLogFileEnabled = true;
174
        if ( isset( $GLOBALS['eZDebugLogFileEnabled'] ) )
175
        {
176
            $this->GlobalLogFileEnabled = $GLOBALS['eZDebugLogFileEnabled'];
177
        }
178
        $this->ShowTypes = self::SHOW_ALL;
179
        $this->HandleType = self::HANDLE_NONE;
180
        $this->OldHandler = false;
181
        $this->UseCSS = false;
182
        $this->MessageOutput = self::OUTPUT_MESSAGE_STORE;
183
        $this->ScriptStart = microtime( true );
184
        $this->TimeAccumulatorList = array();
185
        $this->TimeAccumulatorGroupList = array();
186
        $this->OverrideList = array();
187
        $this->topReportsList = array();
188
        $this->bottomReportsList = array();
189
    }
190
 
191
    function reset()
192
    {
193
        $this->DebugStrings = array();
194
        $this->TmpTimePoints = array( self::LEVEL_NOTICE => array(),
195
                                      self::LEVEL_WARNING => array(),
196
                                      self::LEVEL_ERROR => array(),
197
                                      self::LEVEL_DEBUG => array(),
198
                                      self::LEVEL_STRICT => array() );
199
        $this->TimeAccumulatorList = array();
200
        $this->TimeAccumulatorGroupList = array();
201
        $this->topReportsList = array();
202
        $this->bottomReportsList = array();
203
    }
204
 
205
    /*!
206
     \return the name of the message type.
207
    */
208
    function messageName( $messageType )
209
    {
210
        return $this->MessageNames[$messageType];
211
    }
212
 
213
    /**
214
     * Returns a shared instance of the eZDebug class.
215
     *
216
     * @return eZDebug
217
     */
218
    static function instance( )
219
    {
220
        if ( empty( $GLOBALS["eZDebugGlobalInstance"] ) )
221
        {
222
            $GLOBALS["eZDebugGlobalInstance"] = new eZDebug();
223
        }
224
        return $GLOBALS["eZDebugGlobalInstance"];
225
    }
226
 
227
    /*!
228
     \static
229
     Returns true if the message type $type can be shown.
230
    */
231
    static function showMessage( $type )
232
    {
233
        $debug = eZDebug::instance();
234
        return $debug->ShowTypes & $type;
235
    }
236
 
237
    /*!
238
     \return \c true if the debug level \a $level should always log to file.
239
    */
240
    static function alwaysLogMessage( $level )
241
    {
242
        $instance = eZDebug::instance();
243
        // If there is a global setting for this get the value
244
        // and unset it globally
245
        if ( isset( $GLOBALS['eZDebugAlwaysLog'] ) )
246
        {
247
            $instance->AlwaysLog = $GLOBALS['eZDebugAlwaysLog'] + $instance->AlwaysLog;
248
            unset( $GLOBALS['eZDebugAlwaysLog'] );
249
        }
250
 
251
        if ( !isset( $instance->AlwaysLog[$level] ) )
252
        {
253
            return false;
254
        }
255
        return $instance->AlwaysLog[$level];
256
    }
257
 
258
    /*!
259
     Determines how PHP errors are handled. If $type is self::HANDLE_TO_PHP all error messages
260
     is sent to PHP using trigger_error(), if $type is self::HANDLE_FROM_PHP all error messages
261
     from PHP is fetched using a custom error handler and output as a usual eZDebug message.
262
     If $type is self::HANDLE_NONE there is no error exchange between PHP and eZDebug.
263
    */
264
    static function setHandleType( $type )
265
    {
266
        $instance = eZDebug::instance();
267
 
268
        if ( $type != self::HANDLE_TO_PHP and
269
             $type != self::HANDLE_FROM_PHP )
270
            $type = self::HANDLE_NONE;
271
        if ( extension_loaded( 'xdebug' ) and
272
             $type == self::HANDLE_FROM_PHP )
273
            $type = self::HANDLE_NONE;
274
        if ( $type == $instance->HandleType )
275
            return $instance->HandleType;
276
 
277
        if ( $instance->HandleType == self::HANDLE_FROM_PHP )
278
            restore_error_handler();
279
        switch ( $type )
280
        {
281
            case self::HANDLE_FROM_PHP:
282
            {
283
                set_error_handler( array( $instance, 'recursionProtectErrorHandler' ) );
284
            } break;
285
 
286
            case self::HANDLE_TO_PHP:
287
            {
288
                restore_error_handler();
289
            } break;
290
 
291
            case self::HANDLE_NONE:
292
            {
293
            }
294
        }
295
        $oldHandleType = $instance->HandleType;
296
        $instance->HandleType = $type;
297
        return $oldHandleType;
298
    }
299
 
300
    /*!
301
     \static
302
     Sets types to be shown to $types and returns the old show types.
303
     If $types is not supplied the current value is returned and no change is done.
304
     $types is one or more of self::SHOW_NOTICE, self::SHOW_WARNING, self::SHOW_ERROR, self::SHOW_TIMING_POINT
305
     or'ed together.
306
    */
307
    static function showTypes( $types = false )
308
    {
309
        $instance = eZDebug::instance();
310
 
311
        if ( $types === false )
312
        {
313
            return $instance->ShowTypes;
314
        }
315
        $old_types = $instance->ShowTypes;
316
        $instance->ShowTypes = $types;
317
        return $old_types;
318
    }
319
 
320
    public function recursionProtectErrorHandler( $errno, $errstr, $errfile, $errline )
321
    {
322
        if ( $this->recursionFlag )
323
        {
324
            print( "Fatal debug error: A recursion in debug error handler was detected, aborting debug message.<br/>" );
325
            $this->recursionFlag = false;
326
            return;
327
        }
328
 
329
        $this->recursionFlag = true;
330
 
331
        $result = $this->errorHandler( $errno, $errstr, $errfile, $errline );
332
        $this->recursionFlag = false;
333
        return $result;
334
    }
335
 
336
    /*!
337
     Handles PHP errors, creates notice, warning and error messages for
338
     the various PHP error types.
339
    */
340
    function errorHandler( $errno, $errstr, $errfile, $errline )
341
    {
342
        if ( error_reporting() == 0 ) // @ error-control operator is used
343
            return;
344
        if ( !eZDebug::isDebugEnabled() )
345
            return;
346
        $str = "$errstr in $errfile on line $errline";
347
        if ( empty( $GLOBALS['eZDebugPHPErrorNames'] ) )
348
        {
349
            $GLOBALS['eZDebugPHPErrorNames'] =
350
                array( E_ERROR => 'E_ERROR',
351
                       E_PARSE => 'E_PARSE',
352
                       E_CORE_ERROR => 'E_CORE_ERROR',
353
                       E_COMPILE_ERROR => 'E_COMPILE_ERROR',
354
                       E_USER_ERROR => 'E_USER_ERROR',
355
                       E_WARNING => 'E_WARNING',
356
                       E_CORE_WARNING => 'E_CORE_WARNING',
357
                       E_COMPILE_WARNING => 'E_COMPILE_WARNING',
358
                       E_USER_WARNING => 'E_USER_WARNING',
359
                       E_NOTICE => 'E_NOTICE',
360
                       E_USER_NOTICE => 'E_USER_NOTICE',
361
                       E_STRICT => 'E_STRICT' );
362
            // Since PHP 5.2
363
            if ( defined('E_RECOVERABLE_ERROR') )
364
                $GLOBALS['eZDebugPHPErrorNames'][E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR';
365
            // Since PHP 5.3
366
            if ( defined('E_DEPRECATED') )
367
                $GLOBALS['eZDebugPHPErrorNames'][E_DEPRECATED] = 'E_DEPRECATED';
368
            if ( defined('E_USER_DEPRECATED') )
369
                $GLOBALS['eZDebugPHPErrorNames'][E_USER_DEPRECATED] = 'E_USER_DEPRECATED';
370
 
371
        }
372
        $errname = "Unknown error code ($errno)";
373
        if ( isset( $GLOBALS['eZDebugPHPErrorNames'][$errno] ) )
374
        {
375
            $errname = $GLOBALS['eZDebugPHPErrorNames'][$errno];
376
        }
377
        switch ( $errname )
378
        {
379
            case 'E_ERROR':
380
            case 'E_PARSE':
381
            case 'E_CORE_ERROR':
382
            case 'E_COMPILE_ERROR':
383
            case 'E_USER_ERROR':
384
            case 'E_RECOVERABLE_ERROR':
385
            {
386
                $this->writeError( $str, 'PHP: ' . $errname );
387
            } break;
388
 
389
            case 'E_WARNING':
390
            case 'E_CORE_WARNING':
391
            case 'E_COMPILE_WARNING':
392
            case 'E_USER_WARNING':
393
            case 'E_DEPRECATED':
394
            case 'E_USER_DEPRECATED':
395
            {
396
                $this->writeWarning( $str, 'PHP: ' . $errname );
397
            } break;
398
 
399
            case 'E_NOTICE':
400
            case 'E_USER_NOTICE':
401
            {
402
                $this->writeNotice( $str, 'PHP: ' . $errname );
403
            } break;
404
 
405
            case 'E_STRICT':
406
            {
407
                return $this->writeStrict( $str, 'PHP: ' . $errname );
408
            } break;
409
            default:
410
            {
411
                 $this->writeError( $str, 'PHP: ' . $errname );
412
            } break;
413
        }
414
    }
415
 
416
    /*!
417
      \static
418
      Writes a strict debug message.
419
 
420
      The global variable \c 'eZDebugStrict' will be set to \c true if the notice is added.
421
      \param $label This label will be associated with the strict message, e.g. to say where the message came from.
422
      \param $backgroundClass A string defining the class to use in the HTML debug output.
423
    */
424
    static function writeStrict( $string, $label = "", $backgroundClass = "" )
425
    {
426
        $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_STRICT );
427
        $enabled = eZDebug::isDebugEnabled();
428
        if ( !$alwaysLog and !$enabled )
429
            return;
430
 
431
        $show = eZDebug::showMessage( self::SHOW_STRICT );
432
        if ( !$alwaysLog and !$show )
433
            return;
434
 
435
        if ( is_object( $string ) || is_array( $string ) )
436
             $string = eZDebug::dumpVariable( $string );
437
 
438
        $GLOBALS['eZDebugStrict'] = true;
439
        if ( !isset( $GLOBALS['eZDebugStrictCount'] ) )
440
            $GLOBALS['eZDebugStrictCount'] = 0;
441
        ++$GLOBALS['eZDebugStrictCount'];
442
 
443
        $debug = eZDebug::instance();
444
        if ( $debug->HandleType == self::HANDLE_TO_PHP )
445
        {
446
            // If we get here only because of $alwaysLog we should not trigger a PHP error
447
            if ( $enabled and $show )
448
            {
449
                // we can't trigger E_STRICT but we can let the default error handler handle it
450
                // see http://www.php.net/manual/en/function.set-error-handler.php#69218
451
                return false;
452
            }
453
        }
454
        else
455
        {
456
            $debug->write( $string, self::LEVEL_STRICT, $label, $backgroundClass, $alwaysLog );
457
            return true;
458
        }
459
    }
460
 
461
    /*!
462
      \static
463
      Writes a debug notice.
464
 
465
      The global variable \c 'eZDebugNotice' will be set to \c true if the notice is added.
466
      \param $label This label will be associated with the notice, e.g. to say where the notice came from.
467
      \param $backgroundClass A string defining the class to use in the HTML debug output.
468
    */
469
    static function writeNotice( $string, $label = "", $backgroundClass = "" )
470
    {
471
        $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_NOTICE );
472
        $enabled = eZDebug::isDebugEnabled();
473
        if ( !$alwaysLog and !$enabled )
474
            return;
475
 
476
        $show = eZDebug::showMessage( self::SHOW_NOTICE );
477
        if ( !$alwaysLog and !$show )
478
            return;
479
 
480
        if ( is_object( $string ) || is_array( $string ) )
481
             $string = eZDebug::dumpVariable( $string );
482
 
483
        $GLOBALS['eZDebugNotice'] = true;
484
        if ( !isset( $GLOBALS['eZDebugNoticeCount'] ) )
485
            $GLOBALS['eZDebugNoticeCount'] = 0;
486
        ++$GLOBALS['eZDebugNoticeCount'];
487
 
488
        $debug = eZDebug::instance();
489
        if ( $debug->HandleType == self::HANDLE_TO_PHP )
490
        {
491
            // If we get here only because of $alwaysLog we should not trigger a PHP error
492
            if ( $enabled and $show )
493
            {
494
                if ( $label )
495
                    $string = "$label: $string";
496
                trigger_error( $string, E_USER_NOTICE );
497
            }
498
        }
499
        else
500
        {
501
            $debug->write( $string, self::LEVEL_NOTICE, $label, $backgroundClass, $alwaysLog );
502
        }
503
    }
504
 
505
    /*!
506
      \static
507
      Writes a debug warning.
508
 
509
      The global variable \c 'eZDebugWarning' will be set to \c true if the notice is added.
510
      \param $label This label will be associated with the notice, e.g. to say where the notice came from.
511
    */
512
    static function writeWarning( $string, $label = "", $backgroundClass = "" )
513
    {
514
        $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_WARNING );
515
        $enabled = eZDebug::isDebugEnabled();
516
        if ( !$alwaysLog and !$enabled )
517
            return;
518
 
519
        $show = eZDebug::showMessage( self::SHOW_WARNING );
520
        if ( !$alwaysLog and !$show )
521
            return;
522
 
523
        if ( is_object( $string ) || is_array( $string ) )
524
            $string = eZDebug::dumpVariable( $string );
525
 
526
        $GLOBALS['eZDebugWarning'] = true;
527
        if ( !isset( $GLOBALS['eZDebugWarningCount'] ) )
528
            $GLOBALS['eZDebugWarningCount'] = 0;
529
        ++$GLOBALS['eZDebugWarningCount'];
530
 
531
        $debug = eZDebug::instance();
532
        if ( $debug->HandleType == self::HANDLE_TO_PHP )
533
        {
534
            // If we get here only because of $alwaysLog we should not trigger a PHP error
535
            if ( $enabled and $show )
536
            {
537
                if ( $label )
538
                    $string = "$label: $string";
539
                trigger_error( $string, E_USER_WARNING );
540
            }
541
        }
542
        else
543
        {
544
            $debug->write( $string, self::LEVEL_WARNING, $label, $backgroundClass, $alwaysLog );
545
        }
546
    }
547
 
548
    /*!
549
      \static
550
      Writes a debug error.
551
 
552
      The global variable \c 'eZDebugError' will be set to \c true if the notice is added.
553
      \param $label This label will be associated with the notice, e.g. to say where the notice came from.
554
    */
555
    static function writeError( $string, $label = "", $backgroundClass = "" )
556
    {
557
        $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_ERROR );
558
        $enabled = eZDebug::isDebugEnabled();
559
        if ( !$alwaysLog and !$enabled )
560
            return;
561
 
562
        $show = eZDebug::showMessage( self::SHOW_ERROR );
563
        if ( !$alwaysLog and !$show )
564
            return;
565
 
566
        if ( is_object( $string ) || is_array( $string ) )
567
            $string = eZDebug::dumpVariable( $string );
568
 
569
        $GLOBALS['eZDebugError'] = true;
570
        if ( !isset( $GLOBALS['eZDebugErrorCount'] ) )
571
            $GLOBALS['eZDebugErrorCount'] = 0;
572
        ++$GLOBALS['eZDebugErrorCount'];
573
 
574
        $debug = eZDebug::instance();
575
        if ( $debug->HandleType == self::HANDLE_TO_PHP )
576
        {
577
            // If we get here only because of $alwaysLog we should not trigger a PHP error
578
            if ( $enabled and $show )
579
            {
580
                if ( $label )
581
                    $string = "$label: $string";
582
                trigger_error( $string, E_USER_ERROR );
583
            }
584
        }
585
        else
586
        {
587
            $debug->write( $string, self::LEVEL_ERROR, $label, $backgroundClass, $alwaysLog );
588
        }
589
    }
590
 
591
    /*!
592
      \static
593
      Writes a debug message.
594
 
595
      The global variable \c 'eZDebugDebug' will be set to \c true if the notice is added.
596
      \param $label This label will be associated with the notice, e.g. to say where the notice came from.
597
    */
598
    static function writeDebug( $string, $label = "", $backgroundClass = "" )
599
    {
600
        $alwaysLog = eZDebug::alwaysLogMessage( self::LEVEL_DEBUG );
601
        $enabled = eZDebug::isDebugEnabled();
602
        if ( !$alwaysLog and !$enabled )
603
            return;
604
 
605
        $show = eZDebug::showMessage( self::SHOW_DEBUG );
606
        if ( !$alwaysLog and !$show )
607
            return;
608
 
609
        if ( is_object( $string ) || is_array( $string ) )
610
            $string = eZDebug::dumpVariable( $string );
611
 
612
        $GLOBALS['eZDebugDebug'] = true;
613
        if ( !isset( $GLOBALS['eZDebugDebugCount'] ) )
614
            $GLOBALS['eZDebugDebugCount'] = 0;
615
        ++$GLOBALS['eZDebugDebugCount'];
616
 
617
        $debug = eZDebug::instance();
618
        if ( $debug->HandleType == self::HANDLE_TO_PHP )
619
        {
620
            // If we get here only because of $alwaysLog we should not trigger a PHP error
621
            if ( $enabled and $show )
622
            {
623
                if ( $label )
624
                    $string = "$label: $string";
625
                trigger_error( $string, E_USER_NOTICE );
626
            }
627
        }
628
        else
629
        {
630
            $debug->write( $string, self::LEVEL_DEBUG, $label, $backgroundClass, $alwaysLog );
631
        }
632
    }
633
 
634
    /*!
635
      \static
636
      \private
637
      Dumps the variables contents using the var_dump function
638
    */
639
    static function dumpVariable( $var )
640
    {
641
        // If we have var_export (PHP >= 4.2.0) we use the instead
642
        // provides better output, doesn't require output buffering
643
        // and doesn't get mangled by Xdebug
644
 
645
        // dl: we should always use 'var_dump' since 'var_export' is
646
        // unable to handle recursion properly.
647
        //if ( function_exists( 'var_export' ) )
648
        //    return var_export( $var, true );
649
 
650
        ob_start();
651
        var_dump( $var );
652
        $variableContents = '';
653
        if ( extension_loaded( 'xdebug' ) )
654
           $variableContents = self::XDEBUG_SIGNATURE;
655
        $variableContents .= ob_get_contents();
656
        ob_end_clean();
657
        return $variableContents;
658
    }
659
 
660
    /*!
661
     Enables/disables the use of external CSS. If false a <style> tag is output
662
     before the debug list. Default is to use internal css.
663
    */
664
    static function setUseExternalCSS( $use )
665
    {
666
        eZDebug::instance()->UseCSS = $use;
667
    }
668
 
669
    /*!
670
     Determines the way messages are output, the \a $output parameter
671
     is self::OUTPUT_MESSAGE_SCREEN and self::OUTPUT_MESSAGE_STORE ored together.
672
    */
673
    function setMessageOutput( $output )
674
    {
675
        $this->MessageOutput = $output;
676
    }
677
 
678
    function setStoreLog( $store )
679
    {
680
        $this->StoreLog = $store;
681
    }
682
 
683
    /*!
684
      Adds a new timing point for the benchmark report.
685
    */
686
    static function addTimingPoint( $description = "" )
687
    {
688
        if ( !eZDebug::isDebugEnabled() )
689
            return;
690
        if ( !eZDebug::showMessage( self::SHOW_TIMING_POINT ) )
691
            return;
692
        $debug = eZDebug::instance();
693
 
694
        $time = microtime( true );
695
        $usedMemory = 0;
696
        if ( function_exists( "memory_get_usage" ) )
697
            $usedMemory = memory_get_usage();
698
        $tp = array( "Time" => $time,
699
                     "Description" => $description,
700
                     "MemoryUsage" => $usedMemory );
701
        $debug->TimePoints[] = $tp;
702
        $desc = "Timing Point: $description";
703
        foreach ( array( self::LEVEL_NOTICE, self::LEVEL_WARNING, self::LEVEL_ERROR, self::LEVEL_DEBUG, self::LEVEL_STRICT ) as $lvl )
704
        {
705
            if ( isset( $debug->TmpTimePoints[$lvl] ) )
706
                $debug->TmpTimePoints[$lvl] = array();
707
            if ( $debug->TmpTimePoints[$lvl] === false and
708
                 $debug->isLogFileEnabled( $lvl ) )
709
            {
710
                $files = $debug->logFiles();
711
                $file = $files[$lvl];
712
                $debug->writeFile( $file, $desc, $lvl );
713
            }
714
            else
715
                array_push( $debug->TmpTimePoints[$lvl],  $tp );
716
        }
717
        $debug->write( $description, self::LEVEL_TIMING_POINT );
718
    }
719
 
720
    /*!
721
      \private
722
      Writes a debug log message.
723
    */
724
    function write( $string, $verbosityLevel = self::LEVEL_NOTICE, $label = "", $backgroundClass = "", $alwaysLog = false )
725
    {
726
        $enabled = eZDebug::isDebugEnabled();
727
        if ( !$alwaysLog and !$enabled )
728
            return;
729
        switch ( $verbosityLevel )
730
        {
731
            case self::LEVEL_NOTICE:
732
            case self::LEVEL_WARNING:
733
            case self::LEVEL_ERROR:
734
            case self::LEVEL_DEBUG:
735
            case self::LEVEL_TIMING_POINT:
736
            case self::LEVEL_STRICT:
737
                break;
738
 
739
            default:
740
                $verbosityLevel = self::LEVEL_ERROR;
741
            break;
742
        }
743
        if ( $this->MessageOutput & self::OUTPUT_MESSAGE_SCREEN and $enabled )
744
        {
745
            print( "$verbosityLevel: $string ($label)\n" );
746
        }
747
        $files = $this->logFiles();
748
        $fileName = false;
749
        if ( isset( $files[$verbosityLevel] ) )
750
            $fileName = $files[$verbosityLevel];
751
        if ( $this->MessageOutput & self::OUTPUT_MESSAGE_STORE or $alwaysLog )
752
        {
753
            if ( ! eZDebug::isLogOnlyEnabled() and $enabled )
754
            {
755
                $ip = eZSys::serverVariable( 'REMOTE_ADDR', true );
756
                if ( !$ip )
757
                    $ip = eZSys::serverVariable( 'HOSTNAME', true );
758
                $this->DebugStrings[] = array( "Level" => $verbosityLevel,
759
                                               "IP" => $ip,
760
                                               "Time" => time(),
761
                                               "Label" => $label,
762
                                               "String" => $string,
763
                                               "BackgroundClass" => $backgroundClass );
764
            }
765
 
766
            if ( $fileName !== false )
767
            {
768
                $timePoints = $this->TmpTimePoints[$verbosityLevel];
769
                if ( is_array( $timePoints ) )
770
                {
771
                    if ( $this->isLogFileEnabled( $verbosityLevel ) )
772
                    {
773
                        foreach ( $timePoints as $tp )
774
                        {
775
                            $desc = "Timing Point: " . $tp["Description"];
776
                            if ( $this->isLogFileEnabled( $verbosityLevel ) )
777
                            {
778
                                $this->writeFile( $fileName, $desc, $verbosityLevel, $alwaysLog );
779
                            }
780
                        }
781
                    }
782
                    $this->TmpTimePoints[$verbosityLevel] = false;
783
                }
784
                if ( $this->isLogFileEnabled( $verbosityLevel ) )
785
                {
786
                    $string = "$label:\n$string";
787
                    $this->writeFile( $fileName, $string, $verbosityLevel, $alwaysLog );
788
                }
789
            }
790
        }
791
    }
792
 
793
    /*!
794
     \static
795
     \return the maxium size for a log file in bytes.
796
    */
797
    static function maxLogSize()
798
    {
799
        if ( isset( $GLOBALS['eZDebugMaxLogSize'] ) )
800
        {
801
            return $GLOBALS['eZDebugMaxLogSize'];
802
        }
803
        return self::MAX_LOGFILE_SIZE;
804
    }
805
 
806
    /*!
807
     \static
808
     Sets the maxium size for a log file to \a $size.
809
    */
810
    static function setMaxLogSize( $size )
811
    {
812
        $GLOBALS['eZDebugMaxLogSize'] = $size;
813
    }
814
 
815
    /*!
816
     \static
817
     \return the maxium number of logrotate files to keep.
818
    */
819
    static function maxLogrotateFiles()
820
    {
821
        if ( isset( $GLOBALS['eZDebugMaxLogrotateFiles'] ) )
822
        {
823
            return $GLOBALS['eZDebugMaxLogrotateFiles'];
824
        }
825
        return self::MAX_LOGROTATE_FILES;
826
    }
827
 
828
    /*!
829
     \static
830
     Sets the maxium number of logrotate files to keep to \a $files.
831
    */
832
    static function setLogrotateFiles( $files )
833
    {
834
        $GLOBALS['eZDebugMaxLogrotateFiles'] = $files;
835
    }
836
 
837
    /*!
838
     \static
839
     Rotates logfiles so the current logfile is backed up,
840
     old rotate logfiles are rotated once more and those that
841
     exceed maxLogrotateFiles() will be removed.
842
     Rotated files will get the extension .1, .2 etc.
843
    */
844
    static function rotateLog( $fileName )
845
    {
846
        $maxLogrotateFiles = eZDebug::maxLogrotateFiles();
847
        for ( $i = $maxLogrotateFiles; $i > 0; --$i )
848
        {
849
            $logRotateName = $fileName . '.' . $i;
850
            if ( @file_exists( $logRotateName ) )
851
            {
852
                if ( $i == $maxLogrotateFiles )
853
                {
854
                    @unlink( $logRotateName );
855
//                     print( "@unlink( $logRotateName )<br/>" );
856
                }
857
                else
858
                {
859
                    $newLogRotateName = $fileName . '.' . ($i + 1);
860
                    eZFile::rename( $logRotateName, $newLogRotateName );
861
//                     print( "@rename( $logRotateName, $newLogRotateName )<br/>" );
862
                }
863
            }
864
        }
865
        if ( @file_exists( $fileName ) )
866
        {
867
            $newLogRotateName = $fileName . '.' . 1;
868
            eZFile::rename( $fileName, $newLogRotateName );
869
//             print( "@rename( $fileName, $newLogRotateName )<br/>" );
870
            return true;
871
        }
872
        return false;
873
    }
874
 
875
    /*!
876
     \private
877
     Writes the log message $string to the file $fileName.
878
    */
879
    function writeFile( &$logFileData, &$string, $verbosityLevel, $alwaysLog = false )
880
    {
881
        $enabled = eZDebug::isDebugEnabled();
882
        if ( !$alwaysLog and !$enabled )
883
            return;
884
        if ( !$alwaysLog and !$this->isLogFileEnabled( $verbosityLevel ) )
885
            return;
886
        $oldHandleType = eZDebug::setHandleType( self::HANDLE_TO_PHP );
887
        $logDir = $logFileData[0];
888
        $logName = $logFileData[1];
889
        $fileName = $logDir . $logName;
890
        if ( !file_exists( $logDir ) )
891
        {
892
            eZDir::mkdir( $logDir, false, true );
893
        }
894
        $oldumask = @umask( 0 );
895
        $fileExisted = @file_exists( $fileName );
896
        if ( $fileExisted and
897
             filesize( $fileName ) > eZDebug::maxLogSize() )
898
        {
899
            if ( eZDebug::rotateLog( $fileName ) )
900
                $fileExisted = false;
901
        }
902
        $logFile = @fopen( $fileName, "a" );
903
        if ( $logFile )
904
        {
905
            $time = strftime( "%b %d %Y %H:%M:%S", strtotime( "now" ) );
906
            $ip = eZSys::serverVariable( 'REMOTE_ADDR', true );
907
            if ( !$ip )
908
                $ip = eZSys::serverVariable( 'HOSTNAME', true );
909
            $notice = "[ " . $time . " ] [" . $ip . "] " . $string . "\n";
910
            @fwrite( $logFile, $notice );
911
            @fclose( $logFile );
912
            if ( !$fileExisted )
913
            {
914
                $ini = eZINI::instance();
915
                $permissions = octdec( $ini->variable( 'FileSettings', 'LogFilePermissions' ) );
916
                @chmod( $fileName, $permissions );
917
            }
918
            @umask( $oldumask );
919
        }
920
        else
921
        {
922
            @umask( $oldumask );
923
            $logEnabled = $this->isLogFileEnabled( $verbosityLevel );
924
            $this->setLogFileEnabled( false, $verbosityLevel );
925
            if ( $verbosityLevel != self::LEVEL_ERROR or
926
                 $logEnabled )
927
            {
928
                eZDebug::setHandleType( $oldHandleType );
929
                $this->writeError( "Cannot open log file '$fileName' for writing\n" .
930
                                   "The web server must be allowed to modify the file.\n" .
931
                                   "File logging for '$fileName' is disabled." , 'eZDebug::writeFile' );
932
            }
933
        }
934
        eZDebug::setHandleType( $oldHandleType );
935
    }
936
 
937
    /*!
938
     \static
939
     Enables or disables logging to file for a given message type.
940
     If \a $types is not supplied it will do the operation for all types.
941
    */
942
    static function setLogFileEnabled( $enabled, $types = false )
943
    {
944
        $instance = eZDebug::instance();
945
        if ( $types === false )
946
        {
947
            $types = $instance->messageTypes();
948
        }
949
        if ( !is_array( $types ) )
950
        {
951
            $types = array( $types );
952
        }
953
        foreach ( $types as $type )
954
        {
955
            $instance->LogFileEnabled[$type] = $enabled;
956
        }
957
    }
958
 
959
    /*!
960
     \return true if the message type \a $type has logging to file enabled.
961
     \sa isGlobalLogFileEnabled, setIsLogFileEnabled
962
    */
963
    function isLogFileEnabled( $type )
964
    {
965
        if ( !$this->isGlobalLogFileEnabled() )
966
            return false;
967
        return $this->LogFileEnabled[$type];
968
    }
969
 
970
    /*!
971
     \return true if the message type \a $type has logging to file enabled.
972
     \sa isLogFileEnabled, setIsGlobalLogFileEnabled
973
    */
974
    function isGlobalLogFileEnabled()
975
    {
976
        return $this->GlobalLogFileEnabled;
977
    }
978
 
979
    /*!
980
     Sets whether the logfile \a $type is enabled or disabled to \a $enabled.
981
     \sa isLogFileEnabled
982
    */
983
    function setIsLogFileEnabled( $type, $enabled )
984
    {
985
        $this->LogFileEnabled[$type] = $enabled;
986
    }
987
 
988
    /*!
989
     Sets whether logfiles are enabled or disabled globally. Sets the value to \a $enabled.
990
     \sa isLogFileEnabled, isGlobalLogFileEnabled
991
    */
992
    function setIsGlobalLogFileEnabled( $enabled )
993
    {
994
        $this->GlobalLogFileEnabled = $enabled;
995
    }
996
 
997
    /*!
998
     Sets whether debug output should be logged only
999
    */
1000
    function setLogOnly( $enabled )
1001
    {
1002
        $GLOBALS['eZDebugLogOnly'] = $enabled;
1003
    }
1004
 
1005
    /*!
1006
     \return an array with the available message types.
1007
    */
1008
    function messageTypes()
1009
    {
1010
        return $this->MessageTypes;
1011
    }
1012
 
1013
    /*!
1014
     Returns an associative array of all the log files used by this class
1015
     where each key is the debug level (self::LEVEL_NOTICE, self::LEVEL_WARNING or self::LEVEL_ERROR or self::LEVEL_DEBUG).
1016
    */
1017
    function logFiles()
1018
    {
1019
        return $this->LogFiles;
1020
    }
1021
 
1022
    /*!
1023
     \static
1024
     \return true if debug should be enabled.
1025
     \note Will return false until the real settings has been updated with updateSettings()
1026
    */
1027
    static function isDebugEnabled()
1028
    {
1029
        if ( isset( $GLOBALS['eZDebugEnabled'] ) )
1030
        {
1031
            return $GLOBALS['eZDebugEnabled'];
1032
        }
1033
 
1034
        return false;
1035
    }
1036
 
1037
    /*!
1038
     \static
1039
     \return true if there should only be logging of debug strings to file.
1040
     \note Will return false until the real settings has been updated with updateSettings()
1041
    */
1042
    static function isLogOnlyEnabled()
1043
    {
1044
        if ( isset( $GLOBALS['eZDebugLogOnly'] ) )
1045
        {
1046
            return $GLOBALS['eZDebugLogOnly'];
1047
        }
1048
 
1049
        return false;
1050
    }
1051
 
1052
    /*!
1053
     \static
1054
     Determine if an ipaddress is in a network. E.G. 120.120.120.120 in 120.120.0.0/24.
1055
     \return true or false.
1056
    */
1057
    static function isIPInNet( $ipaddress, $network, $mask = 24 )
1058
    {
1059
        $lnet = ip2long( $network );
1060
        $lip = ip2long( $ipaddress );
1061
        $binnet = str_pad( decbin( $lnet ), 32, '0', STR_PAD_LEFT );
1062
        $firstpart = substr( $binnet, 0, $mask );
1063
        $binip = str_pad( decbin( $lip ), 32, '0', STR_PAD_LEFT );
1064
        $firstip = substr( $binip, 0, $mask );
1065
        return( strcmp( $firstpart, $firstip ) == 0 );
1066
    }
1067
 
1068
    /*!
1069
     \static
1070
     Updates the settings for debug handling with the settings array \a $settings.
1071
     The array must contain the following keys.
1072
     - debug-enabled - boolean which controls debug handling
1073
     - debug-by-ip   - boolean which controls IP controlled debugging
1074
     - debug-ip-list - array of IPs which gets debug
1075
     - debug-by-user - boolean which controls userID controlled debugging
1076
     - debug-user-list - array of UserIDs which gets debug
1077
    */
1078
    static function updateSettings( $settings )
1079
    {
1080
        // Make sure errors are handled by PHP when we read, including our own debug output.
1081
        $oldHandleType = eZDebug::setHandleType( self::HANDLE_TO_PHP );
1082
 
1083
        if ( isset( $settings['debug-log-files-enabled'] ) )
1084
        {
1085
            $GLOBALS['eZDebugLogFileEnabled'] = $settings['debug-log-files-enabled'];
1086
            if ( isset( $GLOBALS["eZDebugGlobalInstance"] ) )
1087
                $GLOBALS["eZDebugGlobalInstance"]->GlobalLogFileEnabled = $settings['debug-log-files-enabled'];
1088
        }
1089
 
1090
        if ( isset( $settings['debug-styles'] ) )
1091
        {
1092
            $GLOBALS['eZDebugStyles'] = $settings['debug-styles'];
1093
        }
1094
 
1095
        if ( isset( $settings['always-log'] ) and
1096
             is_array( $settings['always-log'] ) )
1097
        {
1098
            $GLOBALS['eZDebugAlwaysLog'] = $settings['always-log'];
1099
        }
1100
 
1101
        if ( isset( $settings['log-only'] ) )
1102
        {
1103
            $GLOBALS['eZDebugLogOnly'] = ( $settings['log-only'] == 'enabled' );
1104
        }
1105
 
1106
        $GLOBALS['eZDebugAllowedByIP'] = $settings['debug-by-ip'] ? self::isAllowedByCurrentIP( $settings['debug-ip-list'] ) : true;
1107
 
1108
        // updateSettings is meant to be called before the user session is started
1109
        // so we do not take debug-by-user into account yet, but store the debug-user-list in $GLOBALS
1110
        // so it can be used in the final check, done by checkDebugByUser()
1111
        if ( isset( $settings['debug-by-user'] ) && $settings['debug-by-user'] )
1112
        {
1113
            $GLOBALS['eZDebugUserIDList'] = $settings['debug-user-list'] ? $settings['debug-user-list'] : array();
1114
        }
1115
 
1116
        $GLOBALS['eZDebugAllowed'] = $GLOBALS['eZDebugAllowedByIP'];
1117
        $GLOBALS['eZDebugEnabled'] = $settings['debug-enabled'] && $GLOBALS['eZDebugAllowedByIP'];
1118
 
1119
        eZDebug::setHandleType( $oldHandleType );
1120
    }
1121
 
1122
    /*!
1123
      \static
1124
      Final checking for debug by user id.
1125
      Checks if we should enable debug.
1126
 
1127
      Returns false if debug-by-user is not active, was already checked before
1128
      or if there is no current user. Returns true otherwise.
1129
    */
1130
    static function checkDebugByUser()
1131
    {
1132
        if ( !isset( $GLOBALS['eZDebugUserIDList'] ) ||
1133
             !is_array( $GLOBALS['eZDebugUserIDList'] ) )
1134
        {
1135
            return false;
1136
        }
1137
        else
1138
        {
1139
            $currentUserID = eZUser::currentUserID();
1140
 
1141
            if ( !$currentUserID )
1142
            {
1143
                return false;
1144
            }
1145
            else
1146
            {
1147
                $GLOBALS['eZDebugAllowedByUser'] = in_array( $currentUserID, $GLOBALS['eZDebugUserIDList'] );
1148
 
1149
                if ( $GLOBALS['eZDebugAllowed'] )
1150
                {
1151
                    $GLOBALS['eZDebugAllowed'] = $GLOBALS['eZDebugAllowedByUser'];
1152
                }
1153
 
1154
                if ( $GLOBALS['eZDebugEnabled'] )
1155
                {
1156
                    $GLOBALS['eZDebugEnabled'] = $GLOBALS['eZDebugAllowedByUser'];
1157
                }
1158
 
1159
                unset( $GLOBALS['eZDebugUserIDList'] );
1160
 
1161
                return true;
1162
            }
1163
        }
1164
    }
1165
 
1166
    /*!
1167
      \static
1168
      Prints the debug report
1169
    */
1170
    static function printReport( $newWindow = false, $as_html = true, $returnReport = false,
1171
                           $allowedDebugLevels = false, $useAccumulators = true, $useTiming = true, $useIncludedFiles = false )
1172
    {
1173
        if ( !self::isDebugEnabled() )
1174
            return null;
1175
 
1176
        $debug = self::instance();
1177
        $report = $debug->printReportInternal( $as_html, $returnReport & $newWindow, $allowedDebugLevels, $useAccumulators, $useTiming, $useIncludedFiles );
1178
 
1179
        if ( $newWindow == true )
1180
        {
1181
            $debugFilePath = eZDir::path( array( eZSys::varDirectory(), 'cache', 'debug.html' ) );
1182
            $debugFileURL = $debugFilePath;
1183
            eZURI::transformURI( $debugFileURL, true );
1184
            print( "
1185
<script type='text/javascript'>
1186
<!--
1187
 
1188
(function()
1189
{
1190
    var debugWindow;
1191
 
1192
    if  (navigator.appName == \"Microsoft Internet Explorer\")
1193
    {
1194
        //Microsoft Internet Explorer
1195
        debugWindow = window.open( '$debugFileURL', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40');
1196
        debugWindow.document.close();
1197
        debugWindow.location.reload();
1198
    }
1199
    else if (navigator.appName == \"Opera\")
1200
    {
1201
        //Opera
1202
        debugWindow = window.open( '', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40');
1203
        debugWindow.location.href=\"$debugFileURL\";
1204
        debugWindow.navigate(\"$debugFileURL\");
1205
    }
1206
    else
1207
    {
1208
        //Mozilla, Firefox, etc.
1209
        debugWindow = window.open( '', 'ezdebug', 'width=500,height=550,status,scrollbars,resizable,screenX=0,screenY=20,left=20,top=40');
1210
        debugWindow.document.location.href=\"$debugFileURL\";
1211
    };
1212
})();
1213
 
1214
// -->
1215
</script>
1216
" );
1217
            $header = "<!DOCTYPE html><html><head><title>eZ debug</title></head><body>";
1218
            $footer = "</body></html>";
1219
            $fp = fopen( $debugFilePath, "w+" );
1220
 
1221
            fwrite( $fp, $header );
1222
            fwrite( $fp, $report );
1223
            fwrite( $fp, $footer );
1224
            fclose( $fp );
1225
        }
1226
        else
1227
        {
1228
            if ( $returnReport )
1229
                return $report;
1230
        }
1231
        return null;
1232
    }
1233
 
1234
    /**
1235
     * Returns the microtime as a float value. $mtime must be in microtime() format.
1236
     * @deprecated Since 4.4.0, use microtime( true ) instead
1237
    */
1238
    static function timeToFloat( $mtime )
1239
    {
1240
        $tTime = explode( " ", $mtime );
1241
        preg_match( "#0\.([0-9]+)#", "" . $tTime[0], $t1 );
1242
        $time = $tTime[1] . "." . $t1[1];
1243
        return $time;
1244
    }
1245
 
1246
    /*!
1247
     Sets the time of the start of the script ot \a $time.
1248
     If \a $time is not supplied it gets the current \c microtime( true ).
1249
     This is used to calculate total execution time and percentages.
1250
    */
1251
    static function setScriptStart( $time = false )
1252
    {
1253
        if ( $time == false )
1254
            $time = microtime( true );
1255
        $debug = eZDebug::instance();
1256
        $debug->ScriptStart = $time;
1257
    }
1258
 
1259
    /*!
1260
      Creates an accumulator group with key \a $key and group name \a $name.
1261
      If \a $name is not supplied name is taken from \a $key.
1262
    */
1263
    static function createAccumulatorGroup( $key, $name = false )
1264
    {
1265
        if ( !eZDebug::isDebugEnabled() )
1266
            return;
1267
        if ( $name == '' or
1268
             $name === false )
1269
            $name = $key;
1270
        $debug = eZDebug::instance();
1271
        if ( !array_key_exists( $key, $debug->TimeAccumulatorList ) )
1272
            $debug->TimeAccumulatorList[$key] = array( 'name' => $name,  'time' => 0, 'count' => 0, 'is_group' => true, 'in_group' => false );
1273
        if ( !array_key_exists( $key, $debug->TimeAccumulatorGroupList ) )
1274
            $debug->TimeAccumulatorGroupList[$key] = array();
1275
    }
1276
 
1277
    /*!
1278
     Creates a new accumulator entry if one does not already exist and initializes with default data.
1279
     If \a $name is not supplied name is taken from \a $key.
1280
     If \a $inGroup is supplied it will place the accumulator under the specified group.
1281
    */
1282
    static function createAccumulator( $key, $inGroup = false, $name = false )
1283
    {
1284
        if ( !eZDebug::isDebugEnabled() )
1285
            return;
1286
        if ( $name == '' or
1287
             $name === false )
1288
            $name = $key;
1289
        $debug = eZDebug::instance();
1290
        $isGroup = false;
1291
        if ( array_key_exists( $key, $debug->TimeAccumulatorList ) and
1292
             array_key_exists( $key, $debug->TimeAccumulatorGroupList ) )
1293
            $isGroup = true;
1294
        $debug->TimeAccumulatorList[$key] = array( 'name' => $name,  'time' => 0, 'count' => 0, 'is_group' => $isGroup, 'in_group' => $inGroup );
1295
        if ( $inGroup !== false )
1296
        {
1297
            $groupKeys = array();
1298
            if ( array_key_exists( $inGroup, $debug->TimeAccumulatorGroupList ) )
1299
                $groupKeys = $debug->TimeAccumulatorGroupList[$inGroup];
1300
            $debug->TimeAccumulatorGroupList[$inGroup] = array_unique( array_merge( $groupKeys, array( $key ) ) );
1301
            if ( array_key_exists( $inGroup, $debug->TimeAccumulatorList ) )
1302
                $debug->TimeAccumulatorList[$inGroup]['is_group'] = true;
1303
        }
1304
    }
1305
 
1306
    /*!
1307
     Starts an time count for the accumulator \a $key.
1308
     You can also specify a name which will be displayed.
1309
    */
1310
    static function accumulatorStart( $key, $inGroup = false, $name = false, $recursive = false )
1311
    {
1312
        if ( !eZDebug::isDebugEnabled() )
1313
            return;
1314
        $debug = eZDebug::instance();
1315
        $key = $key === false ? 'Default Debug-Accumulator' : $key;
1316
        if ( ! array_key_exists( $key, $debug->TimeAccumulatorList ) )
1317
        {
1318
            $debug->createAccumulator( $key, $inGroup, $name );
1319
        }
1320
 
1321
        if ( $recursive )
1322
        {
1323
            if ( isset( $debug->TimeAccumulatorList[$key]['recursive_counter'] ) )
1324
            {
1325
                $debug->TimeAccumulatorList[$key]['recursive_counter']++;
1326
                return;
1327
            }
1328
            $debug->TimeAccumulatorList[$key]['recursive_counter'] = 0;
1329
        }
1330
 
1331
        $debug->TimeAccumulatorList[$key]['temp_time'] = microtime( true );
1332
    }
1333
 
1334
    /*!
1335
     Stops a previous time count and adds the total time to the accumulator \a $key.
1336
    */
1337
    static function accumulatorStop( $key, $recursive = false )
1338
    {
1339
        if ( !eZDebug::isDebugEnabled() )
1340
            return;
1341
        $debug = eZDebug::instance();
1342
        $stopTime = microtime( true );
1343
        $key = $key === false ? 'Default Debug-Accumulator' : $key;
1344
        if ( ! array_key_exists( $key, $debug->TimeAccumulatorList ) )
1345
        {
1346
            eZDebug::writeWarning( "Accumulator '$key' does not exist, run eZDebug::accumulatorStart first", 'eZDebug::accumulatorStop' );
1347
            return;
1348
        }
1349
        $accumulator = $debug->TimeAccumulatorList[$key];
1350
        if ( $recursive )
1351
        {
1352
            if ( isset( $accumulator['recursive_counter'] ) )
1353
            {
1354
                if ( $accumulator['recursive_counter'] > 0 )
1355
                {
1356
                    $accumulator['recursive_counter']--;
1357
                    return;
1358
                }
1359
            }
1360
        }
1361
        $diffTime = $stopTime - $accumulator['temp_time'];
1362
        $accumulator['time'] = $accumulator['time'] + $diffTime;
1363
        ++$accumulator['count'];
1364
        $debug->TimeAccumulatorList[$key] = $accumulator;
1365
    }
1366
 
1367
 
1368
    /*!
1369
      \private
1370
      Prints a full debug report with notice, warnings, errors and a timing report.
1371
    */
1372
    function printReportInternal( $as_html = true, $returnReport = true, $allowedDebugLevels = false,
1373
                                  $useAccumulators = true, $useTiming = true, $useIncludedFiles = false )
1374
    {
1375
        $styles = array( 'strict' => false,
1376
                         'strict-end' => false,
1377
                         'warning' => false,
1378
                         'warning-end' => false,
1379
                         'error' => false,
1380
                         'error-end' => false,
1381
                         'debug' => false,
1382
                         'debug-end' => false,
1383
                         'notice' => false,
1384
                         'notice-end' => false,
1385
                         'timing' => false,
1386
                         'timing-end' => false,
1387
                         'mark' => false,
1388
                         'mark-end' => false,
1389
                         'emphasize' => false,
1390
                         'emphasize-end' => false,
1391
                         'bold' => false,
1392
                         'bold-end' => false );
1393
        if ( isset( $GLOBALS['eZDebugStyles'] ) )
1394
            $styles = $GLOBALS['eZDebugStyles'];
1395
        if ( !$allowedDebugLevels )
1396
            $allowedDebugLevels = array( self::LEVEL_NOTICE, self::LEVEL_WARNING, self::LEVEL_ERROR,
1397
                                         self::LEVEL_DEBUG, self::LEVEL_TIMING_POINT, self::LEVEL_STRICT );
1398
        $endTime = microtime( true );
1399
 
1400
        if ( $returnReport )
1401
        {
1402
            ob_start();
1403
        }
1404
 
1405
        if ( $as_html )
1406
        {
1407 31 alvawu
                $ini = eZINI::instance('bysoftdeveloper.ini');
1408
                $max_height = $ini->variable('BysoftDeveloper', 'MaxHeight');
1409
                $width = $ini->variable('BysoftDeveloper', 'Width');
1410
                $float_x = $ini->variable('BysoftDeveloper', 'FloatX');
1411
                $float_y = $ini->variable('BysoftDeveloper', 'FloatY');
1412 5 cavin.deng
            // cavin.deng
1413
echo <<<EOT
1414
<script type="text/javascript">
1415 7 cavin.deng
        //
1416 31 alvawu
        // author cavin.deng, alva.wu
1417 7 cavin.deng
        //
1418 31 alvawu
        String.prototype.trim = function() {
1419
                return this.replace(/^\s+|\s+$/g,"");
1420
        }
1421
        String.prototype.ltrim = function() {
1422
                return this.replace(/^\s+/,"");
1423
        }
1424
        String.prototype.rtrim = function() {
1425
                return this.replace(/\s+$/,"");
1426
        }
1427
        var _get = function(v, i, t){
1428
                switch(i){
1429
                case 'id':
1430
                        return document.getElementById(v);
1431
                case 'name':
1432
                        if(t == 'list')
1433
                                return document.getElementsByName(v);
1434
                        else
1435
                                return document.getElementByName(v);
1436
                default:
1437
                        return document.getElementById(v);
1438
            }
1439
        }
1440 7 cavin.deng
        function bysoftdeveloperAjax(options){
1441
 
1442
                var isOpera = navigator.userAgent.indexOf('Opera') > -1;
1443
                var isIE = navigator.userAgent.indexOf('MSIE') > 1 && !isOpera;
1444
                var isMoz = navigator.userAgent.indexOf('Mozilla/5.') == 0 && !isOpera;
1445
 
1446
                var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
1447
 
1448
                // default value for each ajax options;
1449
                var method = 'post';
1450
                var callback = null;
1451
                var asyn = true;
1452
                var values = null;
1453
                var url  = null;
1454
 
1455
                if( options != null ){
1456
                        for( var k in options ){
1457
                                var v = options[k];
1458
                                switch( k ){
1459
                                        case 'method':
1460
                                                var method = (v + '' ).toLowerCase();
1461
                                                break;
1462
                                        case 'callback':
1463
                                                callback = v;
1464
                                                break;
1465
                                        case 'asyn':
1466
                                                if( v ){
1467
                                                        asyn = true;
1468
                                                }else{
1469
                                                        asyn = false;
1470
                                                }
1471
                                                break;
1472
                                        case 'data':
1473
                                                values = v;
1474
                                                break;
1475
                                        case 'url':
1476
                                                url = v;
1477
                                                break;
1478
                                        default:
1479
                                                // error options
1480
                                                break;
1481
                                }
1482
                        }
1483
                }
1484
 
1485
                var pairs = [];
1486
 
1487
                // compose the request data;
1488
                for(var p in values){
1489
                        var obj = values[p];   
1490
                        if( typeof(obj) == 'object' ){
1491
                                var c = obj.constructor;
1492
                                // Array or hash Array(object)
1493
                                if( c != null && (c == Array || c == Object) ){
1494
                                        for( var z in obj ){
1495
                                                pair = encodeURIComponent( p + '[' + z + ']' ) + '=' + encodeURIComponent( obj[z] );
1496
                                                pairs.push( pair );
1497
                                        }
1498
                                }else{
1499
                                        pair = encodeURIComponent(p) + encodeURIComponent( obj );
1500
                                        pairs.push( pair );
1501
                                }
1502
                        }else{
1503
                                pair = encodeURIComponent(p) + '=' + encodeURIComponent(obj);
1504
                                pairs.push(pair);
1505
                        }
1506
                }
1507
                var data = pairs.join('&');
1508
 
1509
                var result;
1510
 
1511
                if( asyn || (! asyn && ! isMoz) ){
1512
                        request.onreadystatechange = function(){
1513
                                if( request.readyState == 4 ){  // If the request is finished
1514
                                        if(request.status == 200){  // If it was successful
1515 31 alvawu
                                                _get('bysoftdeveloper-loading').style.display = 'none';
1516 7 cavin.deng
                                                result = request.responseText;
1517
                                                if( callback ){
1518
                                                        result = callback(result);  // Display the server's response
1519
                                                }
1520
                                        }
1521
                                }
1522
                        };
1523
                }
1524
 
1525
                if( method == 'get' ){
1526
                        url = url.replace('?', '');
1527
                        url = url + '?' + data;
1528
                }
1529 31 alvawu
                _get('bysoftdeveloper-loading').style.display = 'block';
1530 7 cavin.deng
                request.open( method.toUpperCase(), url, asyn);
1531
                request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1532
 
1533
                if( method == 'post' ){
1534
                        request.send( data );
1535
                }else{
1536
                        request.send( null );
1537
                }
1538
 
1539
                // @see, http://hi.baidu.com/snowleung/blog/item/2bbad188cbdd7d9da5c2728f.html
1540
                if(  ! asyn && isMoz  ){
1541 31 alvawu
 
1542 7 cavin.deng
                        result = request.responseText;
1543
                        if( callback ){
1544
                                result = callback( result );
1545
                        }
1546
                }
1547
                return result;
1548
        }
1549 5 cavin.deng
/*
1550
Yetii - Yet (E)Another Tab Interface Implementation
1551
version 1.6
1552
http://www.kminek.pl/lab/yetii/
1553
Copyright (c) Grzegorz Wojcik
1554
Code licensed under the BSD License:
1555
http://www.kminek.pl/bsdlicense.txt
1556
*/
1557
function Yetii() {
1558
 
1559
        this.defaults = {
1560
 
1561
                id: null,
1562
                active: 1,
1563
                interval: null,
1564
                wait: null,
1565 31 alvawu
                persist: true,
1566 5 cavin.deng
                tabclass: 'tab',
1567
                activeclass: 'active',
1568
                callback: null,
1569
                leavecallback: null
1570
 
1571
        };
1572
 
1573
        this.activebackup = null;
1574
 
1575
        for (var n in arguments[0]) { this.defaults[n]=arguments[0][n]; };     
1576
 
1577
        this.getTabs = function() {
1578
 
1579
        var retnode = [];
1580 31 alvawu
        var elem = _get(this.defaults.id).getElementsByTagName('*');
1581 5 cavin.deng
 
1582
                var regexp = new RegExp("(^|\\s)" + this.defaults.tabclass.replace(/\-/g, "\\-") + "(\\s|$)");
1583
 
1584
        for (var i = 0; i < elem.length; i++) {
1585
                        if (regexp.test(elem[i].className)) retnode.push(elem[i]);
1586
        }
1587
 
1588
        return retnode;
1589
 
1590
    };
1591
 
1592 31 alvawu
        this.links = _get(this.defaults.id + '-nav').getElementsByTagName('a');
1593
        this.listitems = _get(this.defaults.id + '-nav').getElementsByTagName('li');
1594 5 cavin.deng
 
1595
        this.show = function(number) {
1596
 
1597
        for (var i = 0; i < this.tabs.length; i++) {
1598
 
1599
                        this.tabs[i].style.display = ((i+1)==number) ? 'block' : 'none';
1600
 
1601
                        if ((i+1)==number) {
1602
                                this.addClass(this.links[i], this.defaults.activeclass);
1603
                                this.addClass(this.listitems[i], this.defaults.activeclass + 'li');
1604
                        } else {
1605
                                this.removeClass(this.links[i], this.defaults.activeclass);
1606
                                this.removeClass(this.listitems[i], this.defaults.activeclass + 'li');
1607
                        }
1608
 
1609
                }
1610
 
1611
 
1612
                if (this.defaults.leavecallback && (number != this.activebackup)) this.defaults.leavecallback(this.defaults.active);
1613
 
1614
                this.activebackup = number;
1615
 
1616
 
1617
                this.defaults.active = number;
1618
 
1619
                if (this.defaults.callback) this.defaults.callback(number);
1620
 
1621
 
1622
    };
1623
 
1624
        this.rotate = function(interval) {
1625
 
1626
        this.show(this.defaults.active);
1627
        this.defaults.active++;
1628
 
1629
        if (this.defaults.active > this.tabs.length) this.defaults.active = 1;
1630
 
1631
 
1632
        var self = this;
1633
 
1634
                if (this.defaults.wait) clearTimeout(this.timer2);
1635
 
1636
        this.timer1 = setTimeout(function(){self.rotate(interval);}, interval*1000);
1637
 
1638
    };
1639
 
1640
        this.next = function() {
1641
 
1642
        var _target = (this.defaults.active + 1 > this.tabs.length) ? 1 : this.defaults.active + 1;
1643
        this.show(_target);
1644
        this.defaults.active = _target;
1645
 
1646
    };
1647
 
1648
        this.previous = function() {
1649
 
1650
        var _target = ((this.defaults.active - 1) == 0) ? this.tabs.length : this.defaults.active - 1;
1651
        this.show(_target);
1652
        this.defaults.active = _target;
1653
 
1654
    };
1655
 
1656
        this.previous = function() {
1657
 
1658
                this.defaults.active--;
1659
        if(!this.defaults.active) this.defaults.active = this.tabs.length;
1660
                this.show(this.defaults.active);
1661
 
1662
        };
1663
 
1664
        this.gup = function(name) {
1665
                name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
1666
                var regexS = "[\\?&]"+name+"=([^&#]*)";
1667
                var regex = new RegExp( regexS );
1668
                var results = regex.exec( window.location.href );
1669
                if (results == null) return null;
1670
                else return results[1];
1671
        };
1672
 
1673
        this.parseurl = function(tabinterfaceid) {
1674
 
1675
                var result = this.gup(tabinterfaceid);
1676
 
1677
                if (result==null) return null;
1678
                if (parseInt(result)) return parseInt(result);
1679 31 alvawu
                if (_get(result)) {    
1680 5 cavin.deng
                        for (var i=0;i<this.tabs.length;i++) {
1681
                                if (this.tabs[i].id == result) return (i+1);
1682
                        }
1683
                }
1684
 
1685
                return null;
1686
 
1687
        };
1688
 
1689
        this.createCookie = function(name,value,days) {
1690
                if (days) {
1691
                        var date = new Date();
1692
                        date.setTime(date.getTime()+(days*24*60*60*1000));
1693
                        var expires = "; expires="+date.toGMTString();
1694
                }
1695
                else var expires = "";
1696
                document.cookie = name+"="+value+expires+"; path=/";
1697
        };
1698
 
1699
        this.readCookie = function(name) {
1700
                var nameEQ = name + "=";
1701
                var ca = document.cookie.split(';');
1702
                for(var i=0;i < ca.length;i++) {
1703
                        var c = ca[i];
1704
                        while (c.charAt(0)==' ') c = c.substring(1,c.length);
1705
                        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
1706
                }
1707
                return null;
1708
        };
1709
 
1710
        this.contains = function(el, item, from) {
1711
                return el.indexOf(item, from) != -1;
1712
        };
1713
 
1714
        this.hasClass = function(el, className){
1715
                return this.contains(el.className, className, ' ');
1716
        };
1717
 
1718
        this.addClass = function(el, className){
1719
                if (!this.hasClass(el, className)) el.className = (el.className + ' ' + className).replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
1720
        };
1721
 
1722
        this.removeClass = function(el, className){
1723
                el.className = el.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
1724
                el.className.replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
1725
        };
1726
 
1727
 
1728
        this.tabs = this.getTabs();
1729
        this.defaults.active = (this.parseurl(this.defaults.id)) ? this.parseurl(this.defaults.id) : this.defaults.active;
1730
        if (this.defaults.persist && this.readCookie(this.defaults.id)) this.defaults.active = this.readCookie(this.defaults.id);  
1731
        this.activebackup = this.defaults.active;
1732
        this.show(this.defaults.active);
1733
 
1734
        var self = this;
1735
        for (var i = 0; i < this.links.length; i++) {
1736
        this.links[i].customindex = i+1;
1737
        this.links[i].onclick = function(){
1738
 
1739
                if (self.timer1) clearTimeout(self.timer1);
1740
                if (self.timer2) clearTimeout(self.timer2);
1741
 
1742
                self.show(this.customindex);
1743
                if (self.defaults.persist) self.createCookie(self.defaults.id, this.customindex, 0);
1744
 
1745
                if (self.defaults.wait) self.timer2 = setTimeout(function(){self.rotate(self.defaults.interval);}, self.defaults.wait*1000);
1746
 
1747
                return false;
1748
        };
1749
    }
1750
 
1751
        if (this.defaults.interval) this.rotate(this.defaults.interval);
1752
 
1753
};
1754
</script>
1755
<script type="text/javascript">
1756
function bysoftdeveloperToggleDebugBox(){
1757
        bysoftdeveloperToggleById('bysoftdeveloper-wrapper');
1758 17 cavin.deng
        bysoftdeveloperToggleById('bysoftdeveloper-clear-cache');
1759
        //bysoftdeveloperToggleInlineById('bysoftdeveloper-clear-cache');
1760 5 cavin.deng
}
1761 17 cavin.deng
 
1762
function bysoftdeveloperToggleInlineById(e, status) {
1763 31 alvawu
        if( typeof e == 'string' ) e = _get(e);
1764 17 cavin.deng
 
1765
        if( status != undefined ){
1766
                var value = (status == 'inline' || (status != 'none' && status) ) ? 'inline' : 'none';
1767
                e.style.display = value;
1768
                return true;
1769
        }
1770
 
1771
        if( e.style.display == 'inline' ){
1772
                e.style.display = 'none';
1773
        }else if(e.style.display == 'none'){
1774
                e.style.display = 'inline';
1775
        }else{
1776
                e.style.display = 'none';
1777
        }
1778
}
1779 5 cavin.deng
function bysoftdeveloperToggleById(e, status){
1780 31 alvawu
        if( typeof e == 'string' ) e = _get(e);
1781 5 cavin.deng
 
1782
        if( status != undefined ){
1783
                var value = (status == 'block' || (status != 'none' && status) ) ? 'block' : 'none';
1784
                e.style.display = value;
1785
                return true;
1786
        }
1787
 
1788
        if( e.style.display == 'block' ){
1789
                e.style.display = 'none';
1790
        }else if(e.style.display == 'none'){
1791
                e.style.display = 'block';
1792
        }else{
1793
                e.style.display = 'none';
1794
        }
1795
}
1796
function bysoftdeveloperDebugFloatInternal(){
1797 31 alvawu
        var positionY = $float_y;
1798 5 cavin.deng
 
1799 31 alvawu
        var contentObject = _get('bysoftdeveloper-wrapper');
1800 5 cavin.deng
        if( contentObject.style.display == 'block' ){
1801
                return;
1802
        }
1803
 
1804 31 alvawu
        var obj = _get('debug');
1805 5 cavin.deng
 
1806
        var deltaY;
1807
 
1808
        if( typeof window.pageYOffset != 'undefined' ){
1809
                deltaY = window.pageYOffset;   
1810
        }else if( typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat' ){
1811
                deltaY = document.documentElement.scrollTop;
1812
        }else if( typeof document.body != 'undefined' ){
1813
                deltaY = document.body.scrollTop;
1814
        }
1815
 
1816
        deltaY = parseInt(deltaY);
1817
 
1818
        obj.style.top = positionY + deltaY + 'px';
1819
}
1820
function bysoftdeveloperDebugFloat(){
1821
        setInterval(bysoftdeveloperDebugFloatInternal, 100);
1822
}
1823
 
1824
// template_usage_float_id function, float event dealing
1825
if (window.addEventListener){
1826
        window.addEventListener('load', bysoftdeveloperDebugFloat, false);
1827
}else if (window.attachEvent){
1828
        window.attachEvent('onload', bysoftdeveloperDebugFloat);
1829
}else{
1830
        window.onload = bysoftdeveloperDebugFloat;
1831
}
1832 7 cavin.deng
 
1833 5 cavin.deng
</script>
1834 7 cavin.deng
 
1835 5 cavin.deng
<style type="text/css">
1836
pre{
1837
        white-space: pre-line;
1838
}
1839 31 alvawu
.bysoftdeveloper-tabs-container a{
1840
    color: #E55211;
1841
    text-decoration: none;
1842
}
1843
.bysoftdeveloper-tabs-container{
1844
 
1845
}
1846 5 cavin.deng
.bysoftdeveloper-ul-layout a.active{
1847
    background: none repeat scroll 0 0 #FFFFFF;
1848
    color: #0000FF;
1849
    cursor: default;
1850
    padding-bottom: 5px;
1851
}
1852
.bysoftdeveloper-ul-layout a{
1853
    background: none repeat scroll 0 0 #EEEEEE;
1854
    border-color: #CCCCCC #CCCCCC -moz-use-text-color;
1855
    border-style: solid solid none;
1856
    border-width: 1px 1px 0;
1857
    color: #666666;
1858 6 cavin.deng
    float: left;
1859 5 cavin.deng
    display: block;
1860
    font-weight: bold;
1861
    padding: 4px 8px;
1862
    text-decoration: none;
1863
}
1864
 
1865
.bysoftdeveloper-ul-layout{
1866
    list-style-type: none;
1867 6 cavin.deng
    height: 40px;
1868
    display:block;
1869
    margin: 4px; 4px;
1870 5 cavin.deng
}
1871
.bysoftdeveloper-ul-layout li{
1872
        float: left;
1873
    margin: 0 2px 0 0;
1874
}
1875
</style>
1876
EOT;
1877
            // cavin.deng
1878 31 alvawu
$tabini = eZINI::instance('bysoftdeveloper.ini');
1879
 
1880
$availableTabList = $tabini->variable('TabsSettings', 'AvaiableTabList');
1881
$tabsStartNum = 5;     
1882
$tabsHTML = $tabsContainerHTML = $tabsCallerHTML = $tabsInteractionHTML = '';
1883
 
1884
foreach($availableTabList as $key => $availableTab)
1885
{
1886
        // dynamic generation of tabs
1887
        $tabsHTML .= "<li><a href=\"#bysoftdeveloper-$key\">$availableTab</a></li>";
1888
 
1889
        // dynamic generation of tabs containers
1890
        $innerContent = file_get_contents(getcwd() . '/extension/bysoftdeveloper/tabs/' . $key . '/tabcontent.php');
1891
        $tabsContainerHTML .= "<div id='bysoftdeveloper-$key' class='bysoftdeveloper-tab-class'>$innerContent</div>";
1892
 
1893
        // dynamic generation of tabs caller
1894
        $tabloadfunction = $tabini->variable('Tab-' . $key, 'Tabload');
1895
        if(isset($tabloadfunction) && $tabloadfunction != '')
1896
        {
1897
                $tabsCallerHTML .=<<<EOT
1898
                if (tabnumber == $tabsStartNum && $tabloadfunction instanceof Function )
1899
                {
1900
                        $tabloadfunction();
1901
                }
1902
EOT;
1903
        }
1904
        $tabsStartNum++;
1905
 
1906
        // dynamic generation of tabs interaction
1907
        $tabsInteractionHTML .= require_once(getcwd() . '/extension/bysoftdeveloper/tabs/' . $key . '/interact.php');
1908
//      echo $interactionContent;
1909
 
1910
}
1911
 
1912
 
1913
 
1914 17 cavin.deng
                        echo <<<EOT
1915 31 alvawu
        <div id="debug" style="position:absolute;left:$float_x;z-index:999;font-size:11px;font-family:Verdana,Arial,Tahoma,'Courier New';">
1916
                <div id="bysoftdeveloper-toggle" style="cursor:pointer;height:20px;background-color:green;color:white;" onclick="javascript:bysoftdeveloperToggleDebugBox();">
1917 17 cavin.deng
                        <a style="color:white;float:left;">Debug Tool</a>
1918
                        <a onclick="javascript:bysoftdeveloperClearCache(event);"
1919
                        id="bysoftdeveloper-clear-cache"
1920
                        style="display:none;color:white;float:right;">
1921
                        Clear Cache
1922
                </a>
1923
                </div>
1924
                <div id="bysoftdeveloper-message" style="padding-left:10px;padding-right:10px;background-color:green;color:white;text-align:center;">
1925
                </div>
1926
                <div id="bysoftdeveloper-wrapper"
1927 31 alvawu
                        style="display:none;background-color:white;border:3px solid green;width:$width;">
1928 17 cavin.deng
 
1929
                        <ul id="bysoftdeveloper-wrapper-nav" class="bysoftdeveloper-ul-layout">
1930
                    <li><a href="#bysoftdeveloper-content">Debug</a></li>
1931
                    <li><a href="#bysoftdeveloper-template">Templates</a></li>
1932
                    <li><a href="#bysoftdeveloper-toolbar">Toolbar</a></li>
1933
                    <li><a href="#bysoftdeveloper-ini">Ini</a></li>
1934 31 alvawu
                    $tabsHTML
1935
                    <li id="bysoftdeveloper-loading" style="display:none;"><img src="/extension/bysoftdeveloper/design/standard/images/ajax.gif" /></li>
1936 17 cavin.deng
                </ul>
1937 31 alvawu
 
1938 17 cavin.deng
EOT;
1939
 
1940 5 cavin.deng
            if ( !$this->UseCSS )
1941
            {
1942 17 cavin.deng
                echo <<<EOT
1943
<style type='text/css'>
1944
<!--
1945 5 cavin.deng
td.debugheader
1946
{
1947
    background-color : #eeeeee;
1948
    border-top : 1px solid #444488;
1949
    border-bottom : 1px solid #444488;
1950
    font-size : 65%;
1951
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
1952
}
1953
 
1954
pre.debugtransaction
1955
{
1956
    background-color : #f8f6d8;
1957
}
1958
 
1959
td.timingpoint1
1960
{
1961
    background-color : #ffffff;
1962
    border-top : 1px solid #444488;
1963
    font-size : 65%;
1964
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
1965
}
1966
 
1967
td.timingpoint2
1968
{
1969
    background-color : #eeeeee;
1970
    border-top : 1px solid #444488;
1971
    font-size : 65%;
1972
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
1973
}
1974
-->
1975 17 cavin.deng
</style>
1976
EOT;
1977 5 cavin.deng
            }
1978
            // cavin.deng
1979
            // capture main debug output
1980
            if ($as_html) {
1981
                ob_start();    
1982
            }
1983
            echo "<table style='border: 1px lightgray;' cellspacing='0' summary='Table for actual debug output, shows notices, warnings and errors.'>";
1984
        }
1985
 
1986
 
1987
        // cavin.deng capture output
1988
        ob_start();
1989
        $this->printTopReportsList();
1990
        $bysoftDebugToolbar = ob_get_clean();
1991
 
1992
        if ($as_html) {
1993
            $bysoftDebugToolbar = substr($bysoftDebugToolbar, strlen('<tr><td>'));
1994
            $pos = strrpos($bysoftDebugToolbar, '</td></tr>');
1995
            $bysoftDebugToolbar = substr($bysoftDebugToolbar, 0, $pos);
1996
        }
1997
 
1998
        $hasLevel = array( self::LEVEL_NOTICE => false,
1999
                           self::LEVEL_WARNING => false,
2000
                           self::LEVEL_ERROR => false,
2001
                           self::LEVEL_TIMING_POINT => false,
2002
                           self::LEVEL_DEBUG => false,
2003
                           self::LEVEL_STRICT => false );
2004
 
2005
        foreach ( $this->DebugStrings as $debug )
2006
        {
2007
            if ( !in_array( $debug['Level'], $allowedDebugLevels ) )
2008
                continue;
2009
            $time = strftime ("%b %d %Y %H:%M:%S", strtotime( "now" ) );
2010
 
2011
            $outputData = $this->OutputFormat[$debug["Level"]];
2012
            if ( is_array( $outputData ) )
2013
            {
2014
                $identifierText = '';
2015
                if ( !$hasLevel[$debug['Level']] )
2016
                {
2017
                    $hasLevel[$debug['Level']] = true;
2018
                    $identifierText = ' id="' . $outputData['xhtml-identifier'] . '"';
2019
                }
2020
                $color = $outputData["color"];
2021
                $name = $outputData["name"];
2022
                $label = $debug["Label"];
2023
                $bgclass = $debug["BackgroundClass"];
2024
                $pre = ($bgclass != '' ? " class='$bgclass'" : '');
2025
                if ( $as_html )
2026
                {
2027
                    $label = htmlspecialchars( $label );
2028
 
2029
                    $contents = '';
2030
                    if ( extension_loaded( 'xdebug' ) && ( strncmp( self::XDEBUG_SIGNATURE, $debug['String'], strlen( self::XDEBUG_SIGNATURE ) ) === 0 ) )
2031
                        $contents = substr( $debug['String'], strlen( self::XDEBUG_SIGNATURE ) );
2032
                    else
2033
                        $contents = htmlspecialchars( $debug['String'] );
2034
 
2035
                    echo "<tr><td class='debugheader' valign='top'$identifierText><b><span style='color: $color'>$name:</span> $label</b></td>
2036
                                    <td class='debugheader' valign='top'>$time</td></tr>
2037
                                    <tr><td colspan='2'><pre$pre>" .  $contents . "</pre></td></tr>";
2038
                }
2039
                else
2040
                {
2041
                    echo $styles[$outputData['style']] . "$name:" . $styles[$outputData['style'].'-end'] . " ";
2042
                    echo $styles['bold'] . "($label)" . $styles['bold-end'] . "\n" . $debug["String"] . "\n\n";
2043
                }
2044
            }
2045
            flush();
2046
        }
2047
        if ( $as_html )
2048
        {
2049
            echo "</table>";
2050
 
2051
            echo "<h2>Timing points:</h2>";
2052
            echo "<table id='timingpoints' style='border: 1px dashed black;' cellspacing='0' summary='Tabel of timingpoint stats.'><tr><th>Checkpoint</th><th>Elapsed</th><th>Rel. Elapsed</th><th>Memory</th><th>Rel. Memory</th></tr>";
2053
        }
2054
        $startTime = false;
2055
        $elapsed = 0.00;
2056
        $relElapsed = 0.00;
2057
        if ( $useTiming )
2058
        {
2059
            for ( $i = 0; $i < count( $this->TimePoints ); ++$i )
2060
            {
2061
                $point = $this->TimePoints[$i];
2062
                $nextPoint = false;
2063
                if ( isset( $this->TimePoints[$i + 1] ) )
2064
                    $nextPoint = $this->TimePoints[$i + 1];
2065
                $time = $point["Time"];
2066
                $nextTime = false;
2067
                if ( $startTime === false )
2068
                    $startTime = $time;
2069
                $elapsed = $time - $startTime;
2070
 
2071
                $relMemory = 0;
2072
                $memory = $point["MemoryUsage"];
2073
                // Calculate relative time and memory usage
2074
                if ( $nextPoint !== false )
2075
                {
2076
                    $nextTime = $nextPoint["Time"];
2077
                    $relElapsed = $nextTime - $time;
2078
                    $relElapsed = number_format( $relElapsed, $this->TimingAccuracy ) . " sec";
2079
 
2080
                    $nextMemory = $nextPoint["MemoryUsage"];
2081
                    $relMemory = $nextMemory - $memory;
2082
                    $relMemory = number_format( $relMemory / 1024, $this->TimingAccuracy ) . " KB";
2083
                }
2084
                else
2085
                {
2086
                    $relElapsed = $as_html ? '&nbsp;' : '';
2087
                    $relMemory = $as_html ? '&nbsp;' : '';
2088
                }
2089
 
2090
                // Convert memory usage to human readable
2091
                $memory = number_format( $memory / 1024, $this->TimingAccuracy ) . " KB";
2092
                $elapsed = number_format( $elapsed, $this->TimingAccuracy ) . " sec";
2093
 
2094
                if ( $i % 2 == 0 )
2095
                    $class = "timingpoint1";
2096
                else
2097
                    $class = "timingpoint2";
2098
 
2099
                if ( $as_html )
2100
                {
2101
                    echo "<tr><td class='$class'>" . $point["Description"] . "</td>
2102
                          <td class='$class' align='right'>$elapsed</td><td class='$class' align='right'>$relElapsed</td>
2103
                          <td class='$class' align='right'>$memory</td><td class='$class' align='right'>$relMemory</td></tr>";
2104
                }
2105
                else
2106
                {
2107
                    echo $point["Description"] . ' ' . $elapsed . $relElapsed . "\n";
2108
                }
2109
            }
2110
 
2111
            if ( count( $this->TimePoints ) > 0 )
2112
            {
2113
                $totalElapsed = $endTime - $startTime;
2114
 
2115
                if ( $as_html )
2116
                {
2117
                    echo "<tr><td><b>Total runtime:</b></td><td><b>" .
2118
    number_format( ( $totalElapsed ), $this->TimingAccuracy ) . " sec</b></td><td></td></tr>";
2119
                }
2120
                else
2121
                {
2122
                    echo "Total runtime: " .
2123
    number_format( ( $totalElapsed ), $this->TimingAccuracy ) . " sec\n";
2124
                }
2125
            }
2126
            else
2127
            {
2128
                if ( $as_html )
2129
                    echo "<tr><td> No timing points defined</td><td>";
2130
                else
2131
                    echo "No timing points defined\n";
2132
            }
2133
 
2134
            if ( function_exists( 'memory_get_peak_usage' ) )
2135
            {
2136
                $peakMemory = memory_get_peak_usage();
2137
                if ( $as_html )
2138
                {
2139
                    echo "<tr><td><b>Peak memory usage:</b></td><td><b>" .
2140
                        number_format( $peakMemory / 1024, $this->TimingAccuracy ) . " KB</b></td></tr>";
2141
                }
2142
                else
2143
                {
2144
                    echo "Peak memory usage: " .
2145
                        number_format( $peakMemory / 1024, $this->TimingAccuracy ) . " KB\n";
2146
                }
2147
            }
2148
        }
2149
        if ( $as_html )
2150
        {
2151
            echo "</table>";
2152
        }
2153
 
2154
        if ( $useIncludedFiles )
2155
        {
2156
            if ( $as_html )
2157
                echo "<h2>Included files:</h2><table style='border: 1px dashed black;' cellspacing='0' summary='Tabel list of included templates used in the processing of this page.'><tr><th>File</th></tr>";
2158
            else
2159
                echo $styles['emphasize'] . "Includes" . $styles['emphasize-end'] . "\n";
2160
            $phpFiles = get_included_files();
2161
            $j = 0;
2162
            $currentPathReg = preg_quote( realpath( "." ) );
2163
            foreach ( $phpFiles as $phpFile )
2164
            {
2165
                if ( preg_match( "#^$currentPathReg/(.+)$#", $phpFile, $matches ) )
2166
                    $phpFile = $matches[1];
2167
                if ( $as_html )
2168
                {
2169
                    if ( $j % 2 == 0 )
2170
                        $class = "timingpoint1";
2171
                    else
2172
                        $class = "timingpoint2";
2173
                    ++$j;
2174
                    echo "<tr><td class=\"$class\">$phpFile</td></tr>";
2175
                }
2176
                else
2177
                {
2178
                    echo "$phpFile\n";
2179
                }
2180
            }
2181