Subversion Repositories bysoftdeveloper

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

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 32 alvawu
        if(!Array.indexOf){
1419
            Array.prototype.indexOf = function(obj){
1420
                for(var i=0; i<this.length; i++){
1421
                    if(this[i]==obj){
1422
                        return i;
1423
                    }
1424
                }
1425
                return -1;
1426
            }
1427
        }
1428 31 alvawu
        String.prototype.trim = function() {
1429
                return this.replace(/^\s+|\s+$/g,"");
1430
        }
1431
        String.prototype.ltrim = function() {
1432
                return this.replace(/^\s+/,"");
1433
        }
1434
        String.prototype.rtrim = function() {
1435
                return this.replace(/\s+$/,"");
1436
        }
1437 32 alvawu
 
1438
        var _get = function(v, i, t, o){
1439
                var parent = o || document;
1440 31 alvawu
                switch(i){
1441
                case 'id':
1442 32 alvawu
                        return parent.getElementById(v);
1443 31 alvawu
                case 'name':
1444
                        if(t == 'list')
1445 32 alvawu
                                return parent.getElementsByName(v);
1446 31 alvawu
                        else
1447 32 alvawu
                                return parent.getElementByName(v);
1448
 
1449 31 alvawu
                default:
1450 32 alvawu
                        return parent.getElementById(v);
1451 31 alvawu
            }
1452
        }
1453 7 cavin.deng
        function bysoftdeveloperAjax(options){
1454
 
1455
                var isOpera = navigator.userAgent.indexOf('Opera') > -1;
1456
                var isIE = navigator.userAgent.indexOf('MSIE') > 1 && !isOpera;
1457
                var isMoz = navigator.userAgent.indexOf('Mozilla/5.') == 0 && !isOpera;
1458
 
1459
                var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
1460
 
1461
                // default value for each ajax options;
1462
                var method = 'post';
1463
                var callback = null;
1464
                var asyn = true;
1465
                var values = null;
1466
                var url  = null;
1467
 
1468
                if( options != null ){
1469
                        for( var k in options ){
1470
                                var v = options[k];
1471
                                switch( k ){
1472
                                        case 'method':
1473
                                                var method = (v + '' ).toLowerCase();
1474
                                                break;
1475
                                        case 'callback':
1476
                                                callback = v;
1477
                                                break;
1478
                                        case 'asyn':
1479
                                                if( v ){
1480
                                                        asyn = true;
1481
                                                }else{
1482
                                                        asyn = false;
1483
                                                }
1484
                                                break;
1485
                                        case 'data':
1486
                                                values = v;
1487
                                                break;
1488
                                        case 'url':
1489
                                                url = v;
1490
                                                break;
1491
                                        default:
1492
                                                // error options
1493
                                                break;
1494
                                }
1495
                        }
1496
                }
1497
 
1498
                var pairs = [];
1499
 
1500
                // compose the request data;
1501
                for(var p in values){
1502
                        var obj = values[p];   
1503
                        if( typeof(obj) == 'object' ){
1504
                                var c = obj.constructor;
1505
                                // Array or hash Array(object)
1506
                                if( c != null && (c == Array || c == Object) ){
1507
                                        for( var z in obj ){
1508
                                                pair = encodeURIComponent( p + '[' + z + ']' ) + '=' + encodeURIComponent( obj[z] );
1509
                                                pairs.push( pair );
1510
                                        }
1511
                                }else{
1512
                                        pair = encodeURIComponent(p) + encodeURIComponent( obj );
1513
                                        pairs.push( pair );
1514
                                }
1515
                        }else{
1516
                                pair = encodeURIComponent(p) + '=' + encodeURIComponent(obj);
1517
                                pairs.push(pair);
1518
                        }
1519
                }
1520
                var data = pairs.join('&');
1521
 
1522
                var result;
1523
 
1524
                if( asyn || (! asyn && ! isMoz) ){
1525
                        request.onreadystatechange = function(){
1526
                                if( request.readyState == 4 ){  // If the request is finished
1527
                                        if(request.status == 200){  // If it was successful
1528 31 alvawu
                                                _get('bysoftdeveloper-loading').style.display = 'none';
1529 7 cavin.deng
                                                result = request.responseText;
1530
                                                if( callback ){
1531
                                                        result = callback(result);  // Display the server's response
1532
                                                }
1533
                                        }
1534
                                }
1535
                        };
1536
                }
1537
 
1538
                if( method == 'get' ){
1539
                        url = url.replace('?', '');
1540
                        url = url + '?' + data;
1541
                }
1542 31 alvawu
                _get('bysoftdeveloper-loading').style.display = 'block';
1543 7 cavin.deng
                request.open( method.toUpperCase(), url, asyn);
1544
                request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1545
 
1546
                if( method == 'post' ){
1547
                        request.send( data );
1548
                }else{
1549
                        request.send( null );
1550
                }
1551
 
1552
                // @see, http://hi.baidu.com/snowleung/blog/item/2bbad188cbdd7d9da5c2728f.html
1553
                if(  ! asyn && isMoz  ){
1554 31 alvawu
 
1555 7 cavin.deng
                        result = request.responseText;
1556
                        if( callback ){
1557
                                result = callback( result );
1558
                        }
1559
                }
1560
                return result;
1561
        }
1562 32 alvawu
var goX=_get('debug').style.left;
1563
var goY=_get('debug').style.top;
1564
function goTo(a, t) {
1565
        a = a || 0.1;
1566
        t = t || 16;
1567
 
1568
        var x1 = 0;
1569
        var y1 = 0;
1570
        var x2 = 0;
1571
        var y2 = 0;
1572
        var x3 = 0;
1573
        var y3 = 0;
1574
 
1575
        if (document.documentElement) {
1576
                x1 = document.documentElement.scrollLeft || 0;
1577
                y1 = document.documentElement.scrollTop || 0;
1578
        }
1579
        if (document.body) {
1580
                x2 = document.body.scrollLeft || 0;
1581
                y2 = document.body.scrollTop || 0;
1582
        }
1583
        var x3 = window.scrollX || 0;
1584
        var y3 = window.scrollY || 0;
1585
 
1586
        var x = Math.max(x1, Math.max(x2, x3));
1587
        var y = Math.max(y1, Math.max(y2, y3));
1588
 
1589
        var speed = 1 + a;
1590
        window.scrollTo(Math.floor(x / speed), Math.floor(y / speed));
1591
        if(x > goX || y > goY) {
1592
                var f = "goTo(" + a + ", " + t + ")";
1593
                window.setTimeout(f, t);
1594
        }
1595
}
1596 5 cavin.deng
/*
1597
Yetii - Yet (E)Another Tab Interface Implementation
1598
version 1.6
1599
http://www.kminek.pl/lab/yetii/
1600
Copyright (c) Grzegorz Wojcik
1601
Code licensed under the BSD License:
1602
http://www.kminek.pl/bsdlicense.txt
1603
*/
1604
function Yetii() {
1605
 
1606
        this.defaults = {
1607
 
1608
                id: null,
1609
                active: 1,
1610
                interval: null,
1611
                wait: null,
1612 31 alvawu
                persist: true,
1613 5 cavin.deng
                tabclass: 'tab',
1614
                activeclass: 'active',
1615
                callback: null,
1616
                leavecallback: null
1617
 
1618
        };
1619
 
1620
        this.activebackup = null;
1621
 
1622
        for (var n in arguments[0]) { this.defaults[n]=arguments[0][n]; };     
1623
 
1624
        this.getTabs = function() {
1625
 
1626
        var retnode = [];
1627 31 alvawu
        var elem = _get(this.defaults.id).getElementsByTagName('*');
1628 5 cavin.deng
 
1629
                var regexp = new RegExp("(^|\\s)" + this.defaults.tabclass.replace(/\-/g, "\\-") + "(\\s|$)");
1630
 
1631
        for (var i = 0; i < elem.length; i++) {
1632
                        if (regexp.test(elem[i].className)) retnode.push(elem[i]);
1633
        }
1634
 
1635
        return retnode;
1636
 
1637
    };
1638
 
1639 31 alvawu
        this.links = _get(this.defaults.id + '-nav').getElementsByTagName('a');
1640
        this.listitems = _get(this.defaults.id + '-nav').getElementsByTagName('li');
1641 5 cavin.deng
 
1642
        this.show = function(number) {
1643
 
1644
        for (var i = 0; i < this.tabs.length; i++) {
1645
 
1646
                        this.tabs[i].style.display = ((i+1)==number) ? 'block' : 'none';
1647
 
1648
                        if ((i+1)==number) {
1649
                                this.addClass(this.links[i], this.defaults.activeclass);
1650
                                this.addClass(this.listitems[i], this.defaults.activeclass + 'li');
1651
                        } else {
1652
                                this.removeClass(this.links[i], this.defaults.activeclass);
1653
                                this.removeClass(this.listitems[i], this.defaults.activeclass + 'li');
1654
                        }
1655
 
1656
                }
1657
 
1658
 
1659
                if (this.defaults.leavecallback && (number != this.activebackup)) this.defaults.leavecallback(this.defaults.active);
1660
 
1661
                this.activebackup = number;
1662
 
1663
 
1664
                this.defaults.active = number;
1665
 
1666
                if (this.defaults.callback) this.defaults.callback(number);
1667
 
1668
 
1669
    };
1670
 
1671
        this.rotate = function(interval) {
1672
 
1673
        this.show(this.defaults.active);
1674
        this.defaults.active++;
1675
 
1676
        if (this.defaults.active > this.tabs.length) this.defaults.active = 1;
1677
 
1678
 
1679
        var self = this;
1680
 
1681
                if (this.defaults.wait) clearTimeout(this.timer2);
1682
 
1683
        this.timer1 = setTimeout(function(){self.rotate(interval);}, interval*1000);
1684
 
1685
    };
1686
 
1687
        this.next = function() {
1688
 
1689
        var _target = (this.defaults.active + 1 > this.tabs.length) ? 1 : this.defaults.active + 1;
1690
        this.show(_target);
1691
        this.defaults.active = _target;
1692
 
1693
    };
1694
 
1695
        this.previous = function() {
1696
 
1697
        var _target = ((this.defaults.active - 1) == 0) ? this.tabs.length : this.defaults.active - 1;
1698
        this.show(_target);
1699
        this.defaults.active = _target;
1700
 
1701
    };
1702
 
1703
        this.previous = function() {
1704
 
1705
                this.defaults.active--;
1706
        if(!this.defaults.active) this.defaults.active = this.tabs.length;
1707
                this.show(this.defaults.active);
1708
 
1709
        };
1710
 
1711
        this.gup = function(name) {
1712
                name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
1713
                var regexS = "[\\?&]"+name+"=([^&#]*)";
1714
                var regex = new RegExp( regexS );
1715
                var results = regex.exec( window.location.href );
1716
                if (results == null) return null;
1717
                else return results[1];
1718
        };
1719
 
1720
        this.parseurl = function(tabinterfaceid) {
1721
 
1722
                var result = this.gup(tabinterfaceid);
1723
 
1724
                if (result==null) return null;
1725
                if (parseInt(result)) return parseInt(result);
1726 31 alvawu
                if (_get(result)) {    
1727 5 cavin.deng
                        for (var i=0;i<this.tabs.length;i++) {
1728
                                if (this.tabs[i].id == result) return (i+1);
1729
                        }
1730
                }
1731
 
1732
                return null;
1733
 
1734
        };
1735
 
1736
        this.createCookie = function(name,value,days) {
1737
                if (days) {
1738
                        var date = new Date();
1739
                        date.setTime(date.getTime()+(days*24*60*60*1000));
1740
                        var expires = "; expires="+date.toGMTString();
1741
                }
1742
                else var expires = "";
1743
                document.cookie = name+"="+value+expires+"; path=/";
1744
        };
1745
 
1746
        this.readCookie = function(name) {
1747
                var nameEQ = name + "=";
1748
                var ca = document.cookie.split(';');
1749
                for(var i=0;i < ca.length;i++) {
1750
                        var c = ca[i];
1751
                        while (c.charAt(0)==' ') c = c.substring(1,c.length);
1752
                        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
1753
                }
1754
                return null;
1755
        };
1756
 
1757
        this.contains = function(el, item, from) {
1758
                return el.indexOf(item, from) != -1;
1759
        };
1760
 
1761
        this.hasClass = function(el, className){
1762
                return this.contains(el.className, className, ' ');
1763
        };
1764
 
1765
        this.addClass = function(el, className){
1766
                if (!this.hasClass(el, className)) el.className = (el.className + ' ' + className).replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
1767
        };
1768
 
1769
        this.removeClass = function(el, className){
1770
                el.className = el.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
1771
                el.className.replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
1772
        };
1773
 
1774
 
1775
        this.tabs = this.getTabs();
1776
        this.defaults.active = (this.parseurl(this.defaults.id)) ? this.parseurl(this.defaults.id) : this.defaults.active;
1777
        if (this.defaults.persist && this.readCookie(this.defaults.id)) this.defaults.active = this.readCookie(this.defaults.id);  
1778
        this.activebackup = this.defaults.active;
1779
        this.show(this.defaults.active);
1780
 
1781
        var self = this;
1782
        for (var i = 0; i < this.links.length; i++) {
1783
        this.links[i].customindex = i+1;
1784
        this.links[i].onclick = function(){
1785
 
1786
                if (self.timer1) clearTimeout(self.timer1);
1787
                if (self.timer2) clearTimeout(self.timer2);
1788
 
1789
                self.show(this.customindex);
1790
                if (self.defaults.persist) self.createCookie(self.defaults.id, this.customindex, 0);
1791
 
1792
                if (self.defaults.wait) self.timer2 = setTimeout(function(){self.rotate(self.defaults.interval);}, self.defaults.wait*1000);
1793
 
1794
                return false;
1795
        };
1796
    }
1797
 
1798
        if (this.defaults.interval) this.rotate(this.defaults.interval);
1799
 
1800
};
1801
</script>
1802
<script type="text/javascript">
1803
function bysoftdeveloperToggleDebugBox(){
1804
        bysoftdeveloperToggleById('bysoftdeveloper-wrapper');
1805 17 cavin.deng
        bysoftdeveloperToggleById('bysoftdeveloper-clear-cache');
1806
        //bysoftdeveloperToggleInlineById('bysoftdeveloper-clear-cache');
1807 5 cavin.deng
}
1808 32 alvawu
//var bysoftdeveloperDebugArray = _get('debug-row', 'name', 'list');
1809
var bysoftdeveloperDebugArray = document.getElementsByTagName('dl');
1810
var bysoftdeveloperDebugFilter = function(){
1811
    var cb = _get('bysoftdeveloper-debug-filter', 'name', 'list');
1812
    var checked_level = Array();
1813
    for(var k = 0; k < cb.length; k++){
1814
 
1815
        if(cb[k].checked){
1816 17 cavin.deng
 
1817 32 alvawu
                checked_level.push(cb[k].value);
1818
        }
1819
    }
1820
 
1821
        for(k = 0; k < bysoftdeveloperDebugArray.length; k++){
1822
 
1823
                if(typeof(bysoftdeveloperDebugArray[k]) == 'object' && bysoftdeveloperDebugArray[k].getAttribute('name') == 'debug-row') {
1824
                if(checked_level.indexOf(bysoftdeveloperDebugArray[k].className) == -1  ){
1825
                        bysoftdeveloperDebugArray[k].style.display = 'none';
1826
                }else{
1827
                        bysoftdeveloperDebugArray[k].style.display = '';
1828
                }
1829
        }
1830
    }
1831
}
1832
 
1833
var bysoftdeveloperDebugTabAccordion = function(ah){
1834
    var ctn = ah.nextSibling;
1835
    if( ctn.style.display == 'none' ){
1836
        ctn.style.display = 'block';
1837
    }else{
1838
        ctn.style.display = 'none';
1839
    }
1840
}
1841
 
1842
 
1843 17 cavin.deng
function bysoftdeveloperToggleInlineById(e, status) {
1844 31 alvawu
        if( typeof e == 'string' ) e = _get(e);
1845 17 cavin.deng
 
1846
        if( status != undefined ){
1847
                var value = (status == 'inline' || (status != 'none' && status) ) ? 'inline' : 'none';
1848
                e.style.display = value;
1849
                return true;
1850
        }
1851
 
1852
        if( e.style.display == 'inline' ){
1853
                e.style.display = 'none';
1854
        }else if(e.style.display == 'none'){
1855
                e.style.display = 'inline';
1856
        }else{
1857
                e.style.display = 'none';
1858
        }
1859
}
1860 5 cavin.deng
function bysoftdeveloperToggleById(e, status){
1861 31 alvawu
        if( typeof e == 'string' ) e = _get(e);
1862 5 cavin.deng
 
1863
        if( status != undefined ){
1864
                var value = (status == 'block' || (status != 'none' && status) ) ? 'block' : 'none';
1865
                e.style.display = value;
1866
                return true;
1867
        }
1868
 
1869
        if( e.style.display == 'block' ){
1870
                e.style.display = 'none';
1871
        }else if(e.style.display == 'none'){
1872
                e.style.display = 'block';
1873
        }else{
1874
                e.style.display = 'none';
1875
        }
1876
}
1877
function bysoftdeveloperDebugFloatInternal(){
1878 31 alvawu
        var positionY = $float_y;
1879 5 cavin.deng
 
1880 31 alvawu
        var contentObject = _get('bysoftdeveloper-wrapper');
1881 5 cavin.deng
        if( contentObject.style.display == 'block' ){
1882
                return;
1883
        }
1884
 
1885 31 alvawu
        var obj = _get('debug');
1886 5 cavin.deng
 
1887
        var deltaY;
1888
 
1889
        if( typeof window.pageYOffset != 'undefined' ){
1890
                deltaY = window.pageYOffset;   
1891
        }else if( typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat' ){
1892
                deltaY = document.documentElement.scrollTop;
1893
        }else if( typeof document.body != 'undefined' ){
1894
                deltaY = document.body.scrollTop;
1895
        }
1896
 
1897
        deltaY = parseInt(deltaY);
1898
 
1899
        obj.style.top = positionY + deltaY + 'px';
1900
}
1901
function bysoftdeveloperDebugFloat(){
1902
        setInterval(bysoftdeveloperDebugFloatInternal, 100);
1903
}
1904
 
1905
// template_usage_float_id function, float event dealing
1906
if (window.addEventListener){
1907
        window.addEventListener('load', bysoftdeveloperDebugFloat, false);
1908
}else if (window.attachEvent){
1909
        window.attachEvent('onload', bysoftdeveloperDebugFloat);
1910
}else{
1911
        window.onload = bysoftdeveloperDebugFloat;
1912
}
1913 7 cavin.deng
 
1914 5 cavin.deng
</script>
1915 7 cavin.deng
 
1916 5 cavin.deng
<style type="text/css">
1917
pre{
1918
        white-space: pre-line;
1919
}
1920 32 alvawu
#bysoftdeveloper-content h2{
1921
        font-size: 120%;
1922
        cursor: pointer;
1923
        border: 1px solid #ccc;
1924
        margin-bottom: 5px;
1925
        background: #eee;
1926
}
1927 31 alvawu
.bysoftdeveloper-tabs-container a{
1928
    color: #E55211;
1929
    text-decoration: none;
1930
}
1931
.bysoftdeveloper-tabs-container{
1932 32 alvawu
        font-family: monospace;
1933
        font-size: 110%;
1934 31 alvawu
 
1935
}
1936 5 cavin.deng
.bysoftdeveloper-ul-layout a.active{
1937
    background: none repeat scroll 0 0 #FFFFFF;
1938
    color: #0000FF;
1939
    cursor: default;
1940
    padding-bottom: 5px;
1941
}
1942
.bysoftdeveloper-ul-layout a{
1943
    background: none repeat scroll 0 0 #EEEEEE;
1944
    border-color: #CCCCCC #CCCCCC -moz-use-text-color;
1945
    border-style: solid solid none;
1946
    border-width: 1px 1px 0;
1947
    color: #666666;
1948 6 cavin.deng
    float: left;
1949 5 cavin.deng
    display: block;
1950
    font-weight: bold;
1951
    padding: 4px 8px;
1952
    text-decoration: none;
1953
}
1954
 
1955
.bysoftdeveloper-ul-layout{
1956
    list-style-type: none;
1957 6 cavin.deng
    height: 40px;
1958
    display:block;
1959
    margin: 4px; 4px;
1960 5 cavin.deng
}
1961
.bysoftdeveloper-ul-layout li{
1962
        float: left;
1963
    margin: 0 2px 0 0;
1964
}
1965
</style>
1966
EOT;
1967
            // cavin.deng
1968 31 alvawu
$tabini = eZINI::instance('bysoftdeveloper.ini');
1969
 
1970
$availableTabList = $tabini->variable('TabsSettings', 'AvaiableTabList');
1971
$tabsStartNum = 5;     
1972
$tabsHTML = $tabsContainerHTML = $tabsCallerHTML = $tabsInteractionHTML = '';
1973
 
1974
foreach($availableTabList as $key => $availableTab)
1975
{
1976
        // dynamic generation of tabs
1977
        $tabsHTML .= "<li><a href=\"#bysoftdeveloper-$key\">$availableTab</a></li>";
1978
 
1979
        // dynamic generation of tabs containers
1980
        $innerContent = file_get_contents(getcwd() . '/extension/bysoftdeveloper/tabs/' . $key . '/tabcontent.php');
1981
        $tabsContainerHTML .= "<div id='bysoftdeveloper-$key' class='bysoftdeveloper-tab-class'>$innerContent</div>";
1982
 
1983
        // dynamic generation of tabs caller
1984
        $tabloadfunction = $tabini->variable('Tab-' . $key, 'Tabload');
1985
        if(isset($tabloadfunction) && $tabloadfunction != '')
1986
        {
1987
                $tabsCallerHTML .=<<<EOT
1988 32 alvawu
                if (tabnumber == $tabsStartNum && typeof($tabloadfunction) == 'function' )
1989 31 alvawu
                {
1990
                        $tabloadfunction();
1991
                }
1992
EOT;
1993
        }
1994
        $tabsStartNum++;
1995
 
1996
        // dynamic generation of tabs interaction
1997
        $tabsInteractionHTML .= require_once(getcwd() . '/extension/bysoftdeveloper/tabs/' . $key . '/interact.php');
1998
//      echo $interactionContent;
1999
 
2000
}
2001
 
2002
 
2003
 
2004 17 cavin.deng
                        echo <<<EOT
2005 31 alvawu
        <div id="debug" style="position:absolute;left:$float_x;z-index:999;font-size:11px;font-family:Verdana,Arial,Tahoma,'Courier New';">
2006 32 alvawu
                <div id="bysoftdeveloper-toggle" style="cursor:pointer;height:20px;background-color:green;color:white;padding-left:3px;padding-right:3px;" onclick="javascript:bysoftdeveloperToggleDebugBox();">
2007 17 cavin.deng
                        <a style="color:white;float:left;">Debug Tool</a>
2008 32 alvawu
 
2009 17 cavin.deng
                        <a onclick="javascript:bysoftdeveloperClearCache(event);"
2010
                        id="bysoftdeveloper-clear-cache"
2011
                        style="display:none;color:white;float:right;">
2012
                        Clear Cache
2013
                </a>
2014
                </div>
2015 32 alvawu
                <div id="bysoftdeveloper-message" style="display:none;padding-left:10px;padding-right:10px;font-weight:bold;background-color:green;color:white;text-align:center;">
2016 17 cavin.deng
                </div>
2017
                <div id="bysoftdeveloper-wrapper"
2018 32 alvawu
                        style="display:none;background-color:white;border:3px solid green;">
2019 17 cavin.deng
 
2020
                        <ul id="bysoftdeveloper-wrapper-nav" class="bysoftdeveloper-ul-layout">
2021
                    <li><a href="#bysoftdeveloper-content">Debug</a></li>
2022
                    <li><a href="#bysoftdeveloper-template">Templates</a></li>
2023
                    <li><a href="#bysoftdeveloper-toolbar">Toolbar</a></li>
2024
                    <li><a href="#bysoftdeveloper-ini">Ini</a></li>
2025 31 alvawu
                    $tabsHTML
2026
                    <li id="bysoftdeveloper-loading" style="display:none;"><img src="/extension/bysoftdeveloper/design/standard/images/ajax.gif" /></li>
2027 17 cavin.deng
                </ul>
2028 31 alvawu
 
2029 17 cavin.deng
EOT;
2030
 
2031 5 cavin.deng
            if ( !$this->UseCSS )
2032
            {
2033 17 cavin.deng
                echo <<<EOT
2034
<style type='text/css'>
2035
<!--
2036 5 cavin.deng
td.debugheader
2037
{
2038
    background-color : #eeeeee;
2039
    border-top : 1px solid #444488;
2040
    border-bottom : 1px solid #444488;
2041
    font-size : 65%;
2042
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
2043
}
2044
 
2045
pre.debugtransaction
2046
{
2047
    background-color : #f8f6d8;
2048
}
2049
 
2050
td.timingpoint1
2051
{
2052
    background-color : #ffffff;
2053
    border-top : 1px solid #444488;
2054
    font-size : 65%;
2055
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
2056
}
2057
 
2058
td.timingpoint2
2059
{
2060
    background-color : #eeeeee;
2061
    border-top : 1px solid #444488;
2062
    font-size : 65%;
2063
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
2064
}
2065
-->
2066 17 cavin.deng
</style>
2067
EOT;
2068 5 cavin.deng
            }
2069
            // cavin.deng
2070
            // capture main debug output
2071
            if ($as_html) {
2072
                ob_start();    
2073
            }
2074 32 alvawu
            echo "<h2 onclick='javascript:bysoftdeveloperDebugTabAccordion(this);'>Debug Messages:</h2>";
2075
            echo "<div style='width:$width;'><label style='display:inline;'><input type='checkbox' value='debuglevel-1' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_NOTICE]['color']};'>Notice</b></label>
2076
        <label style='display:inline;'><input type='checkbox' value='debuglevel-2' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_WARNING]['color']};'>Warning</b></label>
2077
        <label style='display:inline;'><input type='checkbox' value='debuglevel-3' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_ERROR]['color']};'>Error</b></label>
2078
        <label style='display:inline;'><input type='checkbox' value='debuglevel-4' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_TIMING_POINT]['color']};'>Timing point</b></label>
2079
        <label style='display:inline;'><input type='checkbox' value='debuglevel-5' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_DEBUG]['color']};'>Debug</b></label>
2080
        <label style='display:inline;'><input type='checkbox' value='debuglevel-6' name='bysoftdeveloper-debug-filter' checked='checked' onclick='javascript:bysoftdeveloperDebugFilter();' /><b style='color: {$this->OutputFormat[self::LEVEL_STRICT]['color']};'>Strict</b></label>";
2081 5 cavin.deng
        }
2082
 
2083
 
2084
        // cavin.deng capture output
2085
        ob_start();
2086
        $this->printTopReportsList();
2087
        $bysoftDebugToolbar = ob_get_clean();
2088
 
2089
        if ($as_html) {
2090
            $bysoftDebugToolbar = substr($bysoftDebugToolbar, strlen('<tr><td>'));
2091
            $pos = strrpos($bysoftDebugToolbar, '</td></tr>');
2092
            $bysoftDebugToolbar = substr($bysoftDebugToolbar, 0, $pos);
2093
        }
2094
 
2095
        $hasLevel = array( self::LEVEL_NOTICE => false,
2096
                           self::LEVEL_WARNING => false,
2097
                           self::LEVEL_ERROR => false,
2098
                           self::LEVEL_TIMING_POINT => false,
2099
                           self::LEVEL_DEBUG => false,
2100
                           self::LEVEL_STRICT => false );
2101
 
2102
        foreach ( $this->DebugStrings as $debug )
2103
        {
2104
            if ( !in_array( $debug['Level'], $allowedDebugLevels ) )
2105
                continue;
2106
            $time = strftime ("%b %d %Y %H:%M:%S", strtotime( "now" ) );
2107
 
2108
            $outputData = $this->OutputFormat[$debug["Level"]];
2109
            if ( is_array( $outputData ) )
2110
            {
2111
                $identifierText = '';
2112
                if ( !$hasLevel[$debug['Level']] )
2113
                {
2114
                    $hasLevel[$debug['Level']] = true;
2115
                    $identifierText = ' id="' . $outputData['xhtml-identifier'] . '"';
2116
                }
2117
                $color = $outputData["color"];
2118
                $name = $outputData["name"];
2119
                $label = $debug["Label"];
2120
                $bgclass = $debug["BackgroundClass"];
2121
                $pre = ($bgclass != '' ? " class='$bgclass'" : '');
2122
                if ( $as_html )
2123
                {
2124
                    $label = htmlspecialchars( $label );
2125
 
2126
                    $contents = '';
2127
                    if ( extension_loaded( 'xdebug' ) && ( strncmp( self::XDEBUG_SIGNATURE, $debug['String'], strlen( self::XDEBUG_SIGNATURE ) ) === 0 ) )
2128
                        $contents = substr( $debug['String'], strlen( self::XDEBUG_SIGNATURE ) );
2129
                    else
2130
                        $contents = htmlspecialchars( $debug['String'] );
2131
 
2132 32 alvawu
             /*       echo "<tr class='debuglevel-{$debug['Level']}' name='debug-row'><td class='debugheader' valign='top'$identifierText><b><span style='color: $color'>$name:</span> $label</b></td>
2133 5 cavin.deng
                                    <td class='debugheader' valign='top'>$time</td></tr>
2134 32 alvawu
                                    <tr class='debuglevel-{$debug['Level']}' name='debug-row'><td colspan='2'><pre$pre>" .  $contents . "</pre></td></tr>";*/
2135
                    echo "<dl class='debuglevel-{$debug['Level']}' name='debug-row'><dt class='debugheader' valign='top'$identifierText><b><span style='color: $color'>$name:</span> $label</b></td>
2136
                                    <span class='debugheader' style='float:right; margin-right:5px;'>$time</span></dt>
2137
                                    <dd class='debuglevel-{$debug['Level']}'>";
2138
                    if($debug['Level'] == self::LEVEL_NOTICE)
2139
                        echo "<pre$pre style='width:$width;     overflow-x:scroll;'>  $contents </pre>";
2140
                    else
2141
                        echo $contents ;
2142
                    echo "</dd></dl>";
2143 5 cavin.deng
                }
2144
                else
2145
                {
2146
                    echo $styles[$outputData['style']] . "$name:" . $styles[$outputData['style'].'-end'] . " ";
2147
                    echo $styles['bold'] . "($label)" . $styles['bold-end'] . "\n" . $debug["String"] . "\n\n";
2148
                }
2149
            }
2150
            flush();
2151
        }
2152
        if ( $as_html )
2153
        {
2154 32 alvawu
   //         echo "</table>";
2155
                        echo '</div>';
2156
            echo "<h2 onclick='javascript:bysoftdeveloperDebugTabAccordion(this);'>Timing points:</h2>";
2157 5 cavin.deng
            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>";
2158
        }
2159
        $startTime = false;
2160
        $elapsed = 0.00;
2161
        $relElapsed = 0.00;
2162
        if ( $useTiming )
2163
        {
2164
            for ( $i = 0; $i < count( $this->TimePoints ); ++$i )
2165
            {
2166
                $point = $this->TimePoints[$i];
2167
                $nextPoint = false;
2168
                if ( isset( $this->TimePoints[$i + 1] ) )
2169
                    $nextPoint = $this->TimePoints[$i + 1];
2170
                $time = $point["Time"];
2171
                $nextTime = false;
2172
                if ( $startTime === false )
2173
                    $startTime = $time;
2174
                $elapsed = $time - $startTime;
2175
 
2176
                $relMemory = 0;
2177
                $memory = $point["MemoryUsage"];
2178
                // Calculate relative time and memory usage
2179
                if ( $nextPoint !== false )
2180
                {
2181
                    $nextTime = $nextPoint["Time"];
2182
                    $relElapsed = $nextTime - $time;
2183
                    $relElapsed = number_format( $relElapsed, $this->TimingAccuracy ) . " sec";
2184
 
2185
                    $nextMemory = $nextPoint["MemoryUsage"];
2186
                    $relMemory = $nextMemory - $memory;
2187
                    $relMemory = number_format( $relMemory / 1024, $this->TimingAccuracy ) . " KB";
2188
                }
2189
                else
2190
                {
2191
                    $relElapsed = $as_html ? '&nbsp;' : '';
2192
                    $relMemory = $as_html ? '&nbsp;' : '';
2193
                }
2194
 
2195
                // Convert memory usage to human readable
2196
                $memory = number_format(