Completed
Push — master ( 038e9c...515afa )
by Michael
17s
created

XoopsLogger::XoopsLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
     * Deprecated, use getInstance() instead
68
     */
69
    public function instance()
70
    {
71
        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...
72
    }
73
74
    /**
75
     * Get a reference to the only instance of this class
76
     *
77
     * @return object XoopsLogger  reference to the only instance
78
     */
79
    public static function getInstance()
80
    {
81
        static $instance;
82
        if (!isset($instance)) {
83
            $instance = new XoopsLogger();
84
            // Always catch errors, for security reasons
85
            set_error_handler('XoopsErrorHandler_HandleError');
86
            // grab any uncaught exception
87
            set_exception_handler(array($instance, 'handleException'));
88
        }
89
90
        return $instance;
91
    }
92
93
    /**
94
     * Enable logger output rendering
95
     * When output rendering is enabled, the logger will insert its output within the page content.
96
     * If the string <!--{xo-logger-output}--> is found in the page content, the logger output will
97
     * replace it, otherwise it will be inserted after all the page output.
98
     */
99
    public function enableRendering()
100
    {
101
        if (!$this->renderingEnabled) {
102
            ob_start(array(&$this, 'render'));
103
            $this->renderingEnabled = true;
104
        }
105
    }
106
107
    /**
108
     * Returns the current microtime in seconds.
109
     *
110
     * @return float
111
     */
112
    public function microtime()
113
    {
114
        $now = explode(' ', microtime());
115
116
        return (float)$now[0] + (float)$now[1];
117
    }
118
119
    /**
120
     * Start a timer
121
     *
122
     * @param string $name name of the timer
123
     */
124
    public function startTime($name = 'XOOPS')
125
    {
126
        if ($this->activated) {
127
            $this->logstart[$name] = $this->microtime();
128
        }
129
    }
130
131
    /**
132
     * Stop a timer
133
     *
134
     * @param string $name name of the timer
135
     */
136
    public function stopTime($name = 'XOOPS')
137
    {
138
        if ($this->activated) {
139
            $this->logend[$name] = $this->microtime();
140
        }
141
    }
142
143
    /**
144
     * Log a database query
145
     *
146
     * @param string $sql   SQL string
147
     * @param string $error error message (if any)
148
     * @param int    $errno error number (if any)
149
     * @param null   $query_time
150
     */
151
    public function addQuery($sql, $error = null, $errno = null, $query_time = null)
152
    {
153
        if ($this->activated) {
154
            $this->queries[] = array('sql' => $sql, 'error' => $error, 'errno' => $errno, 'query_time' => $query_time);
155
        }
156
    }
157
158
    /**
159
     * Log display of a block
160
     *
161
     * @param string $name      name of the block
162
     * @param bool   $cached    was the block cached?
163
     * @param int    $cachetime cachetime of the block
164
     */
165
    public function addBlock($name, $cached = false, $cachetime = 0)
166
    {
167
        if ($this->activated) {
168
            $this->blocks[] = array('name' => $name, 'cached' => $cached, 'cachetime' => $cachetime);
169
        }
170
    }
171
172
    /**
173
     * Log extra information
174
     *
175
     * @param string $name name for the entry
176
     * @param int    $msg  text message for the entry
177
     */
178
    public function addExtra($name, $msg)
179
    {
180
        if ($this->activated) {
181
            $this->extra[] = array('name' => $name, 'msg' => $msg);
182
        }
183
    }
184
185
    /**
186
     * Log messages for deprecated functions
187
     *
188
     * @deprecated
189
     *
190
     * @param int $msg text message for the entry
191
     *
192
     */
193
    public function addDeprecated($msg)
194
    {
195
        if ($this->activated) {
196
            $backTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
197
            $miniTrace = ' trace: ';
198
            foreach ($backTrace as $i => $trace) {
199
                $miniTrace .= $trace['file'] . ':' . $trace['line'] . ' ';
200
            }
201
            $miniTrace = str_replace(XOOPS_VAR_PATH, '', $miniTrace);
202
            $miniTrace = str_replace(XOOPS_PATH, '', $miniTrace);
203
            $miniTrace = str_replace(XOOPS_ROOT_PATH, '', $miniTrace);
204
205
            $this->deprecated[] = $msg . $miniTrace;
206
        }
207
    }
208
209
    /**
210
     * Error handling callback (called by the zend engine)
211
     *
212
     * @param integer $errno
213
     * @param string  $errstr
214
     * @param string  $errfile
215
     * @param string  $errline
216
     */
217
    public function handleError($errno, $errstr, $errfile, $errline)
218
    {
219
        if ($this->activated && ($errno & error_reporting())) {
220
            // NOTE: we only store relative pathnames
221
            $this->errors[] = compact('errno', 'errstr', 'errfile', 'errline');
222
        }
223
        if ($errno == E_USER_ERROR) {
224
            $trace = true;
225
            if (substr($errstr, 0, '8') === 'notrace:') {
226
                $trace  = false;
227
                $errstr = substr($errstr, 8);
228
            }
229
            echo sprintf(_XOOPS_FATAL_MESSAGE, $errstr);
230
            if ($trace && function_exists('debug_backtrace')) {
231
                echo "<div style='color:#f0f0f0;background-color:#f0f0f0;'>" . _XOOPS_FATAL_BACKTRACE . ':<br>';
232
                $trace = debug_backtrace();
233
                array_shift($trace);
234
                foreach ($trace as $step) {
235
                    if (isset($step['file'])) {
236
                        echo $this->sanitizePath($step['file']);
237
                        echo ' (' . $step['line'] . ")\n<br>";
238
                    }
239
                }
240
                echo '</div>';
241
            }
242
            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...
243
        }
244
    }
245
246
    /**
247
     * Exception handling callback.
248
     *
249
     * @param \Exception|\Throwable $e uncaught Exception or Error
250
     *
251
     * @return void
252
     */
253
    public function handleException($e)
254
    {
255
        if ($this->isThrowable($e)) {
256
            $msg = get_class($e) . ': ' . $e->getMessage();
257
            $this->handleError(E_USER_ERROR, $msg, $e->getFile(), $e->getLine());
258
        }
259
    }
260
261
    /**
262
     * Determine if an object implements Throwable (or is an Exception that would under PHP 7.)
263
     *
264
     * @param mixed $e Expected to be an object related to Exception or Throwable
265
     *
266
     * @return bool true if related to Throwable or Exception, otherwise false
267
     */
268
    protected function isThrowable($e)
269
    {
270
        $type = interface_exists('\Throwable', false) ? '\Throwable' : '\Exception';
271
        return $e instanceof $type;
272
    }
273
274
    /**
275
     *
276
     * @access protected
277
     *
278
     * @param string $path
279
     *
280
     * @return mixed|string
281
     */
282
    public function sanitizePath($path)
283
    {
284
        $path = str_replace(array('\\', XOOPS_ROOT_PATH, str_replace('\\', '/', realpath(XOOPS_ROOT_PATH))), array('/', '', ''), $path);
285
286
        return $path;
287
    }
288
289
    /**
290
     * Output buffering callback inserting logger dump in page output
291
     * @param $output
292
     * @return string
293
     */
294
    public function render($output)
295
    {
296
        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...
297
        if (!$this->activated) {
298
            return $output;
299
        }
300
301
        $log                    = $this->dump($this->usePopup ? 'popup' : '');
302
        $this->renderingEnabled = $this->activated = false;
303
        $pattern                = '<!--{xo-logger-output}-->';
304
        $pos                    = strpos($output, $pattern);
305
        if ($pos !== false) {
306
            return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
307
        } else {
308
            return $output . $log;
309
        }
310
    }
311
312
    /**
313
     * *#@+
314
     *
315
     * @protected
316
     * @param string $mode
317
     * @return
318
     */
319
    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...
320
    {
321
        include XOOPS_ROOT_PATH . '/class/logger/render.php';
322
323
        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...
324
    }
325
326
    /**
327
     * get the current execution time of a timer
328
     *
329
     * @param  string $name  name of the counter
330
     * @param  bool   $unset removes counter from global log
331
     * @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...
332
     */
333
    public function dumpTime($name = 'XOOPS', $unset = false)
334
    {
335
        if (!$this->activated) {
336
            return null;
337
        }
338
339
        if (!isset($this->logstart[$name])) {
340
            return 0;
341
        }
342
        $stop  = isset($this->logend[$name]) ? $this->logend[$name] : $this->microtime();
343
        $start = $this->logstart[$name];
344
345
        if ($unset) {
346
            unset($this->logstart[$name]);
347
        }
348
349
        return $stop - $start;
350
    }
351
352
    /**
353
     * XoopsLogger::triggerError()
354
     *
355
     * @deprecated
356
     * @param  int     $errkey
357
     * @param  string  $errStr
358
     * @param  string  $errFile
359
     * @param  string  $errLine
360
     * @param  integer $errNo
361
     * @return void
362
     */
363
    public function triggerError($errkey = 0, $errStr = '', $errFile = '', $errLine = '', $errNo = 0)
364
    {
365
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->triggerError();\' is deprecated since XOOPS 2.5.4');
366
367
        if (!empty($errStr)) {
368
            $errStr = sprintf($errStr, $errkey);
369
        }
370
        $errFile = $this->sanitizePath($errFile);
371
        $this->handleError($errNo, $errStr, $errFile, $errLine);
372
    }
373
374
    /**
375
     * *#@+
376
     *
377
     * @deprecated
378
     */
379
    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...
380
    {
381
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpAll();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'\');\' instead.');
382
383
        return $this->dump('');
384
    }
385
386
    /**
387
     * dnmp Blocks @deprecated
388
     *
389
     * @return dump
390
     */
391
    public function dumpBlocks()
392
    {
393
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpBlocks();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'blocks\');\' instead.');
394
395
        return $this->dump('blocks');
396
    }
397
398
    /**
399
     * dumpExtra @deprecated
400
     *
401
     * @return dimp
402
     */
403
    public function dumpExtra()
404
    {
405
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpExtra();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'extra\');\' instead.');
406
407
        return $this->dump('extra');
408
    }
409
410
    /**
411
     * dump Queries @deprecated
412
     *
413
     * @return unknown
414
     */
415
    public function dumpQueries()
416
    {
417
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpQueries();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'queries\');\' instead.');
418
419
        return $this->dump('queries');
420
    }
421
    /**
422
     * *#@-
423
     */
424
}
425
426
/**
427
 * PHP Error handler
428
 *
429
 * NB: You're not supposed to call this function directly, if you don't understand why, then
430
 * you'd better spend some time reading your PHP manual before you hurt somebody
431
 *
432
 * @internal : Using a function and not calling the handler method directly because of old PHP versions
433
 * set_error_handler() have problems with the array( obj,methodname ) syntax
434
 * @param       $errNo
435
 * @param       $errStr
436
 * @param       $errFile
437
 * @param       $errLine
438
 * @param  null $errContext
439
 * @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...
440
 */
441
function XoopsErrorHandler_HandleError($errNo, $errStr, $errFile, $errLine, $errContext = null)
442
{
443
    /*
444
    // We don't want every error to come through this will help speed things up'
445
    if ($errNo == '2048') {
446
        return true;
447
    }
448
    // XOOPS should always be STRICT compliant thus the above lines makes no sense and will be removed! -- Added by Taiwen Jiang
449
    */
450
    $logger = XoopsLogger::getInstance();
451
    $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...
452
    return null;
453
}
454