XoopsLogger   B
last analyzed

Complexity

Total Complexity 52

Size/Duplication

Total Lines 408
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 106
c 2
b 0
f 1
dl 0
loc 408
rs 7.44
wmc 52

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A enableRendering() 0 5 2
A getInstance() 0 12 2
A instance() 0 3 1
A sanitizePath() 0 5 1
A addExtra() 0 4 2
A dumpExtra() 0 5 1
A dumpQueries() 0 5 1
A sanitizeDbMessage() 0 7 1
A dumpBlocks() 0 5 1
A microtime() 0 6 1
A dump() 0 5 1
A startTime() 0 4 2
A dumpAll() 0 5 1
A stopTime() 0 4 2
A addBlock() 0 4 2
A dumpTime() 0 17 5
A render() 0 15 4
A addDeprecated() 0 13 3
A isThrowable() 0 4 2
A addQuery() 0 4 2
A handleException() 0 5 2
B handleError() 0 28 10
A triggerError() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like XoopsLogger often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XoopsLogger, and based on these observations, apply Extract Interface, too.

1
<?php
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-2020 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://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();
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
        /** @var array $now */
115
        $now = explode(' ', microtime());
116
117
        return (float)$now[0] + (float)$now[1];
118
    }
119
120
    /**
121
     * Start a timer
122
     *
123
     * @param string $name name of the timer
124
     */
125
    public function startTime($name = 'XOOPS')
126
    {
127
        if ($this->activated) {
128
            $this->logstart[$name] = $this->microtime();
129
        }
130
    }
131
132
    /**
133
     * Stop a timer
134
     *
135
     * @param string $name name of the timer
136
     */
137
    public function stopTime($name = 'XOOPS')
138
    {
139
        if ($this->activated) {
140
            $this->logend[$name] = $this->microtime();
141
        }
142
    }
143
144
    /**
145
     * Log a database query
146
     *
147
     * @param string $sql   SQL string
148
     * @param string $error error message (if any)
149
     * @param int    $errno error number (if any)
150
     * @param null   $query_time
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $query_time is correct as it would always require null to be passed?
Loading history...
151
     */
152
    public function addQuery($sql, $error = null, $errno = null, $query_time = null)
153
    {
154
        if ($this->activated) {
155
            $this->queries[] = array('sql' => $sql, 'error' => $error, 'errno' => $errno, 'query_time' => $query_time);
156
        }
157
    }
158
159
    /**
160
     * Log display of a block
161
     *
162
     * @param string $name      name of the block
163
     * @param bool   $cached    was the block cached?
164
     * @param int    $cachetime cachetime of the block
165
     */
166
    public function addBlock($name, $cached = false, $cachetime = 0)
167
    {
168
        if ($this->activated) {
169
            $this->blocks[] = array('name' => $name, 'cached' => $cached, 'cachetime' => $cachetime);
170
        }
171
    }
172
173
    /**
174
     * Log extra information
175
     *
176
     * @param string $name name for the entry
177
     * @param int    $msg  text message for the entry
178
     */
179
    public function addExtra($name, $msg)
180
    {
181
        if ($this->activated) {
182
            $this->extra[] = array('name' => $name, 'msg' => $msg);
183
        }
184
    }
185
186
    /**
187
     * Log messages for deprecated functions
188
     *
189
     * this was deprecated, but is still in broad use?
190
     *
191
     * @param string $msg text message for the entry
192
     *
193
     */
194
    public function addDeprecated($msg)
195
    {
196
        if ($this->activated) {
197
            $backTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
198
            $miniTrace = ' trace: ';
199
            foreach ($backTrace as $i => $trace) {
200
                $miniTrace .= $trace['file'] . ':' . $trace['line'] . ' ';
201
            }
202
            $miniTrace = str_replace(XOOPS_VAR_PATH, '', $miniTrace);
203
            $miniTrace = str_replace(XOOPS_PATH, '', $miniTrace);
204
            $miniTrace = str_replace(XOOPS_ROOT_PATH, '', $miniTrace);
205
206
            $this->deprecated[] = $msg . $miniTrace;
207
        }
208
    }
209
210
    /**
211
     * Error handling callback (called by the zend engine)
212
     *
213
     * @param integer $errno
214
     * @param string  $errstr
215
     * @param string  $errfile
216
     * @param string  $errline
217
     * @param array|null $trace
218
     */
219
    public function handleError($errno, $errstr, $errfile, $errline,$trace=null)
220
    {
221
        if ($this->activated && ($errno & error_reporting())) {
222
            // NOTE: we only store relative pathnames
223
            $this->errors[] = compact('errno', 'errstr', 'errfile', 'errline');
224
        }
225
        if ($errno == E_USER_ERROR) {
226
            $includeTrace = true;
227
            if (substr($errstr, 0, '8') === 'notrace:') {
228
                $includeTrace  = false;
229
                $errstr = substr($errstr, 8);
230
            }
231
            echo sprintf(_XOOPS_FATAL_MESSAGE, $errstr);
232
            if ($includeTrace) {
233
                echo "<div style='color:#f0f0f0;background-color:#f0f0f0;'>" . _XOOPS_FATAL_BACKTRACE . ':<br>';
234
                if ($trace === null && function_exists('debug_backtrace')) {
235
                    $trace = \debug_backtrace();
236
                    array_shift($trace);  // Remove the first element, which is this function itself
237
                }
238
                foreach ($trace as $step) {
239
                    if (isset($step['file'])) {
240
                        echo $this->sanitizePath($step['file']);
241
                        echo ' (' . $step['line'] . ")\n<br>";
242
                    }
243
                }
244
                echo '</div>';
245
            }
246
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
247
        }
248
    }
249
250
    /**
251
     * Exception handling callback.
252
     *
253
     * @param \Exception|\Throwable $e uncaught Exception or Error
254
     *
255
     * @return void
256
     */
257
    public function handleException($e)
258
    {
259
        if ($this->isThrowable($e)) {
260
            $msg = get_class($e) . ': ' . $this->sanitizePath($this->sanitizeDbMessage($e->getMessage()));
261
            $this->handleError(E_USER_ERROR, $msg, $e->getFile(), $e->getLine(), $e->getTrace());
262
        }
263
    }
264
265
    /**
266
     * Determine if an object implements Throwable (or is an Exception that would under PHP 7.)
267
     *
268
     * @param mixed $e Expected to be an object related to Exception or Throwable
269
     *
270
     * @return bool true if related to Throwable or Exception, otherwise false
271
     */
272
    protected function isThrowable($e)
273
    {
274
        $type = interface_exists('\Throwable', false) ? '\Throwable' : '\Exception';
275
        return $e instanceof $type;
276
    }
277
278
    /**
279
     *
280
     * @access protected
281
     *
282
     * @param string $path
283
     *
284
     * @return mixed|string
285
     */
286
    public function sanitizePath($path)
287
    {
288
        $path = str_replace(array('\\', XOOPS_ROOT_PATH, str_replace('\\', '/', realpath(XOOPS_ROOT_PATH))), array('/', '', ''), $path);
289
290
        return $path;
291
    }
292
293
    /**
294
     * sanitizeDbMessage
295
     * @access protected
296
     *
297
     * @param string $message
298
     *
299
     * @return string
300
     */
301
    protected function sanitizeDbMessage($message)
302
    {
303
        // XOOPS_DB_PREFIX  XOOPS_DB_NAME
304
        $message = str_replace(XOOPS_DB_PREFIX.'_', '', $message);
305
        $message = str_replace(XOOPS_DB_NAME.'.', '', $message);
306
307
        return $message;
308
    }
309
310
    /**
311
     * Output buffering callback inserting logger dump in page output
312
     * @param $output
313
     * @return string
314
     */
315
    public function render($output)
316
    {
317
        global $xoopsUser;
318
        if (!$this->activated) {
319
            return $output;
320
        }
321
322
        $log                    = $this->dump($this->usePopup ? 'popup' : '');
323
        $this->renderingEnabled = $this->activated = false;
324
        $pattern                = '<!--{xo-logger-output}-->';
325
        $pos                    = strpos($output, $pattern);
326
        if ($pos !== false) {
327
            return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
328
        } else {
329
            return $output . $log;
330
        }
331
    }
332
333
    /**
334
     * *#@+
335
     *
336
     * @protected
337
     * @param string $mode
338
     * @return
339
     */
340
    public function dump($mode = '')
341
    {
342
        include XOOPS_ROOT_PATH . '/class/logger/render.php';
343
344
        return $ret;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ret seems to be never defined.
Loading history...
345
    }
346
347
    /**
348
     * get the current execution time of a timer
349
     *
350
     * @param  string $name  name of the counter
351
     * @param  bool   $unset removes counter from global log
352
     * @return float  current execution time of the counter
353
     */
354
    public function dumpTime($name = 'XOOPS', $unset = false)
355
    {
356
        if (!$this->activated) {
357
            return null;
358
        }
359
360
        if (!isset($this->logstart[$name])) {
361
            return 0;
362
        }
363
        $stop  = isset($this->logend[$name]) ? $this->logend[$name] : $this->microtime();
364
        $start = $this->logstart[$name];
365
366
        if ($unset) {
367
            unset($this->logstart[$name]);
368
        }
369
370
        return $stop - $start;
371
    }
372
373
    /**
374
     * XoopsLogger::triggerError()
375
     *
376
     * @deprecated
377
     * @param  int     $errkey
378
     * @param  string  $errStr
379
     * @param  string  $errFile
380
     * @param  string  $errLine
381
     * @param  int $errNo
382
     * @return void
383
     */
384
    public function triggerError($errkey = 0, $errStr = '', $errFile = '', $errLine = '', $errNo = 0)
385
    {
386
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . '  is deprecated since XOOPS 2.5.4');
387
388
        if (!empty($errStr)) {
389
            $errStr = sprintf($errStr, $errkey);
390
        }
391
        $errFile = $this->sanitizePath($errFile);
392
        $this->handleError($errNo, $errStr, $errFile, $errLine);
393
    }
394
395
    /**
396
     * *#@+
397
     *
398
     * @deprecated
399
     */
400
    public function dumpAll()
401
    {
402
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . '  is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'\');\' instead.');
403
404
        return $this->dump('');
405
    }
406
407
    /**
408
     * dumpBlocks @deprecated
409
     *
410
     * @return dump
0 ignored issues
show
Bug introduced by
The type dump was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
411
     */
412
    public function dumpBlocks()
413
    {
414
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . '  is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'blocks\');\' instead.');
415
416
        return $this->dump('blocks');
417
    }
418
419
    /**
420
     * dumpExtra @deprecated
421
     *
422
     * @return dump
423
     */
424
    public function dumpExtra()
425
    {
426
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . '  is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'extra\');\' instead.');
427
428
        return $this->dump('extra');
429
    }
430
431
    /**
432
     * dump Queries @deprecated
433
     *
434
     * @return mixed
435
     */
436
    public function dumpQueries()
437
    {
438
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . '  is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'queries\');\' instead.');
439
440
        return $this->dump('queries');
441
    }
442
    /**
443
     * *#@-
444
     */
445
}
446
447
/**
448
 * PHP Error handler
449
 *
450
 * NB: You're not supposed to call this function directly, if you don't understand why, then
451
 * you'd better spend some time reading your PHP manual before you hurt somebody
452
 *
453
 * @internal Using a function and not calling the handler method directly because of old PHP versions
454
 * set_error_handler() have problems with the array( obj,methodname ) syntax
455
 * @param       $errNo
456
 * @param       $errStr
457
 * @param       $errFile
458
 * @param       $errLine
459
 * @param  null $errContext
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $errContext is correct as it would always require null to be passed?
Loading history...
460
 * @return bool
461
 */
462
function XoopsErrorHandler_HandleError($errNo, $errStr, $errFile, $errLine, $errContext = null)
463
{
464
    /*
465
    // We don't want every error to come through this will help speed things up'
466
    if ($errNo == '2048') {
467
        return true;
468
    }
469
    // XOOPS should always be STRICT compliant thus the above lines makes no sense and will be removed! -- Added by Taiwen Jiang
470
    */
471
    $logger = XoopsLogger::getInstance();
472
    $logger->handleError($errNo, $errStr, $errFile, $errLine, $errContext);
473
    return null;
474
}
475