Completed
Pull Request — master (#74)
by Richard
11:52
created

XoopsLogger::startTime()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 33 and the first side effect is on line 23.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Xoops Logger handlers - component main class file
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @subpackage          logger
16
 * @since               2.3.0
17
 * @author              Kazumi Ono  <[email protected]>
18
 * @author              Skalpa Keo <[email protected]>
19
 * @author              Taiwen Jiang <[email protected]>
20
 *
21
 * @todo                Not well written, just keep as it is. Refactored in 3.0
22
 */
23
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
24
25
/**
26
 * Collects information for a page request
27
 *
28
 * Records information about database queries, blocks, and execution time
29
 * and can display it as HTML. It also catches php runtime errors.
30
 *
31
 * @package kernel
32
 */
33
class XoopsLogger
34
{
35
    /**
36
     * *#@+
37
     *
38
     * @var array
39
     */
40
    public $queries    = array();
41
    public $blocks     = array();
42
    public $extra      = array();
43
    public $logstart   = array();
44
    public $logend     = array();
45
    public $errors     = array();
46
    public $deprecated = array();
47
    /**
48
     * *#@-
49
     */
50
51
    public $usePopup  = false;
52
    public $activated = true;
53
54
    /**
55
     * *@access protected
56
     */
57
    public $renderingEnabled = false;
58
59
    /**
60
     * XoopsLogger::__construct()
61
     */
62
    public function __construct()
63
    {
64
    }
65
66
    /**
67
     * XoopsLogger::XoopsLogger()
68
     */
69
    public function XoopsLogger()
70
    {
71
    }
72
73
    /**
74
     * Deprecated, use getInstance() instead
75
     */
76
    public function instance()
77
    {
78
        return XoopsLogger::getInstance();
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
79
    }
80
81
    /**
82
     * Get a reference to the only instance of this class
83
     *
84
     * @return object XoopsLogger  reference to the only instance
85
     */
86
    public static function getInstance()
87
    {
88
        static $instance;
89
        if (!isset($instance)) {
90
            $instance = new XoopsLogger();
91
            // Always catch errors, for security reasons
92
            set_error_handler('XoopsErrorHandler_HandleError');
93
            // grab any uncaught exception
94
            set_exception_handler(array($instance, 'handleException'));
95
        }
96
97
        return $instance;
98
    }
99
100
    /**
101
     * Enable logger output rendering
102
     * When output rendering is enabled, the logger will insert its output within the page content.
103
     * If the string <!--{xo-logger-output}--> is found in the page content, the logger output will
104
     * replace it, otherwise it will be inserted after all the page output.
105
     */
106
    public function enableRendering()
107
    {
108
        if (!$this->renderingEnabled) {
109
            ob_start(array(&$this, 'render'));
110
            $this->renderingEnabled = true;
111
        }
112
    }
113
114
    /**
115
     * Returns the current microtime in seconds.
116
     *
117
     * @return float
118
     */
119
    public function microtime()
120
    {
121
        $now = explode(' ', microtime());
122
123
        return (float)$now[0] + (float)$now[1];
124
    }
125
126
    /**
127
     * Start a timer
128
     *
129
     * @param string $name name of the timer
130
     */
131
    public function startTime($name = 'XOOPS')
132
    {
133
        if ($this->activated) {
134
            $this->logstart[$name] = $this->microtime();
135
        }
136
    }
137
138
    /**
139
     * Stop a timer
140
     *
141
     * @param string $name name of the timer
142
     */
143
    public function stopTime($name = 'XOOPS')
144
    {
145
        if ($this->activated) {
146
            $this->logend[$name] = $this->microtime();
147
        }
148
    }
149
150
    /**
151
     * Log a database query
152
     *
153
     * @param string $sql   SQL string
154
     * @param string $error error message (if any)
155
     * @param int    $errno error number (if any)
156
     * @param null   $query_time
157
     */
158
    public function addQuery($sql, $error = null, $errno = null, $query_time = null)
159
    {
160
        if ($this->activated) {
161
            $this->queries[] = array('sql' => $sql, 'error' => $error, 'errno' => $errno, 'query_time' => $query_time);
162
        }
163
    }
164
165
    /**
166
     * Log display of a block
167
     *
168
     * @param string $name      name of the block
169
     * @param bool   $cached    was the block cached?
170
     * @param int    $cachetime cachetime of the block
171
     */
172
    public function addBlock($name, $cached = false, $cachetime = 0)
173
    {
174
        if ($this->activated) {
175
            $this->blocks[] = array('name' => $name, 'cached' => $cached, 'cachetime' => $cachetime);
176
        }
177
    }
178
179
    /**
180
     * Log extra information
181
     *
182
     * @param string $name name for the entry
183
     * @param int    $msg  text message for the entry
184
     */
185
    public function addExtra($name, $msg)
186
    {
187
        if ($this->activated) {
188
            $this->extra[] = array('name' => $name, 'msg' => $msg);
189
        }
190
    }
191
192
    /**
193
     * Log messages for deprecated functions
194
     *
195
     * @deprecated
196
     *
197
     * @param int $msg text message for the entry
198
     *
199
     */
200
    public function addDeprecated($msg)
201
    {
202
        if ($this->activated) {
203
            $this->deprecated[] = $msg;
204
        }
205
    }
206
207
    /**
208
     * Error handling callback (called by the zend engine)
209
     *
210
     * @param integer $errno
211
     * @param string  $errstr
212
     * @param string  $errfile
213
     * @param string  $errline
214
     */
215
    public function handleError($errno, $errstr, $errfile, $errline)
216
    {
217
        if ($this->activated && ($errno & error_reporting())) {
218
            // NOTE: we only store relative pathnames
219
            $this->errors[] = compact('errno', 'errstr', 'errfile', 'errline');
220
        }
221
        if ($errno == E_USER_ERROR) {
222
            $trace = true;
223
            if (substr($errstr, 0, '8') === 'notrace:') {
224
                $trace  = false;
225
                $errstr = substr($errstr, 8);
226
            }
227
            echo sprintf(_XOOPS_FATAL_MESSAGE, $errstr);
228
            if ($trace && function_exists('debug_backtrace')) {
229
                echo "<div style='color:#f0f0f0;background-color:#f0f0f0;'>" . _XOOPS_FATAL_BACKTRACE . ':<br />';
230
                $trace = debug_backtrace();
231
                array_shift($trace);
232
                foreach ($trace as $step) {
233
                    if (isset($step['file'])) {
234
                        echo $this->sanitizePath($step['file']);
235
                        echo ' (' . $step['line'] . ")\n<br />";
236
                    }
237
                }
238
                echo '</div>';
239
            }
240
            exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method handleError() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
241
        }
242
    }
243
244
    /**
245
     * Exception handling callback.
246
     *
247
     * @param \Exception|\Throwable $e uncaught Exception or Error
248
     *
249
     * @return void
250
     */
251
    public function handleException($e)
252
    {
253
        if ($this->isThrowable($e)) {
254
            $msg = get_class($e) . ': ' . $e->getMessage();
255
            $this->handleError(E_USER_ERROR, $msg, $e->getFile(), $e->getLine());
256
        }
257
    }
258
259
    /**
260
     * Determine if an object implements Throwable (or is an Exception that would under PHP 7.)
261
     *
262
     * @param mixed $e Expected to be an object related to Exception or Throwable
263
     *
264
     * @return bool true if related to Throwable or Exception, otherwise false
265
     */
266
    protected function isThrowable($e)
267
    {
268
        $type = interface_exists('\Throwable', false) ? '\Throwable' : '\Exception';
269
        return $e instanceof $type;
270
    }
271
272
    /**
273
     *
274
     * @access protected
275
     *
276
     * @param string $path
277
     *
278
     * @return mixed|string
279
     */
280
    public function sanitizePath($path)
281
    {
282
        $path = str_replace(array('\\', XOOPS_ROOT_PATH, str_replace('\\', '/', realpath(XOOPS_ROOT_PATH))), array('/', '', ''), $path);
283
284
        return $path;
285
    }
286
287
    /**
288
     * Output buffering callback inserting logger dump in page output
289
     * @param $output
290
     * @return string
291
     */
292
    public function render($output)
293
    {
294
        global $xoopsUser;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
295
        if (!$this->activated) {
296
            return $output;
297
        }
298
299
        $log                    = $this->dump($this->usePopup ? 'popup' : '');
300
        $this->renderingEnabled = $this->activated = false;
301
        $pattern                = '<!--{xo-logger-output}-->';
302
        $pos                    = strpos($output, $pattern);
303
        if ($pos !== false) {
304
            return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
305
        } else {
306
            return $output . $log;
307
        }
308
    }
309
310
    /**
311
     * *#@+
312
     *
313
     * @protected
314
     * @param string $mode
315
     * @return
316
     */
317
    public function dump($mode = '')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
318
    {
319
        include XOOPS_ROOT_PATH . '/class/logger/render.php';
320
321
        return $ret;
0 ignored issues
show
Bug introduced by
The variable $ret does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
322
    }
323
324
    /**
325
     * get the current execution time of a timer
326
     *
327
     * @param  string $name  name of the counter
328
     * @param  bool   $unset removes counter from global log
329
     * @return float  current execution time of the counter
0 ignored issues
show
Documentation introduced by
Should the return type not be null|integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
330
     */
331
    public function dumpTime($name = 'XOOPS', $unset = false)
332
    {
333
        if (!$this->activated) {
334
            return null;
335
        }
336
337
        if (!isset($this->logstart[$name])) {
338
            return 0;
339
        }
340
        $stop  = isset($this->logend[$name]) ? $this->logend[$name] : $this->microtime();
341
        $start = $this->logstart[$name];
342
343
        if ($unset) {
344
            unset($this->logstart[$name]);
345
        }
346
347
        return $stop - $start;
348
    }
349
350
    /**
351
     * XoopsLogger::triggerError()
352
     *
353
     * @deprecated
354
     * @param  int     $errkey
355
     * @param  string  $errStr
356
     * @param  string  $errFile
357
     * @param  string  $errLine
358
     * @param  integer $errNo
359
     * @return void
360
     */
361
    public function triggerError($errkey = 0, $errStr = '', $errFile = '', $errLine = '', $errNo = 0)
362
    {
363
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->triggerError();\' is deprecated since XOOPS 2.5.4');
364
365
        if (!empty($errStr)) {
366
            $errStr = sprintf($errStr, $errkey);
367
        }
368
        $errFile = $this->sanitizePath($errFile);
369
        $this->handleError($errNo, $errStr, $errFile, $errLine);
370
    }
371
372
    /**
373
     * *#@+
374
     *
375
     * @deprecated
376
     */
377
    public function dumpAll()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
378
    {
379
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpAll();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'\');\' instead.');
380
381
        return $this->dump('');
382
    }
383
384
    /**
385
     * dnmp Blocks @deprecated
386
     *
387
     * @return dump
388
     */
389
    public function dumpBlocks()
390
    {
391
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpBlocks();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'blocks\');\' instead.');
392
393
        return $this->dump('blocks');
394
    }
395
396
    /**
397
     * dumpExtra @deprecated
398
     *
399
     * @return dimp
400
     */
401
    public function dumpExtra()
402
    {
403
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpExtra();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'extra\');\' instead.');
404
405
        return $this->dump('extra');
406
    }
407
408
    /**
409
     * dump Queries @deprecated
410
     *
411
     * @return unknown
412
     */
413
    public function dumpQueries()
414
    {
415
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpQueries();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'queries\');\' instead.');
416
417
        return $this->dump('queries');
418
    }
419
    /**
420
     * *#@-
421
     */
422
}
423
424
/**
425
 * PHP Error handler
426
 *
427
 * NB: You're not supposed to call this function directly, if you don't understand why, then
428
 * you'd better spend some time reading your PHP manual before you hurt somebody
429
 *
430
 * @internal : Using a function and not calling the handler method directly because of old PHP versions
431
 * set_error_handler() have problems with the array( obj,methodname ) syntax
432
 * @param       $errNo
433
 * @param       $errStr
434
 * @param       $errFile
435
 * @param       $errLine
436
 * @param  null $errContext
437
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
438
 */
439
function XoopsErrorHandler_HandleError($errNo, $errStr, $errFile, $errLine, $errContext = null)
440
{
441
    /*
442
    // We don't want every error to come through this will help speed things up'
443
    if ($errNo == '2048') {
444
        return true;
445
    }
446
    // XOOPS should always be STRICT compliant thus the above lines makes no sense and will be removed! -- Added by Taiwen Jiang
447
    */
448
    $logger = XoopsLogger::getInstance();
449
    $logger->handleError($errNo, $errStr, $errFile, $errLine, $errContext);
0 ignored issues
show
Unused Code introduced by
The call to XoopsLogger::handleError() has too many arguments starting with $errContext.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
450
    return null;
451
}
452