Passed
Pull Request — master (#1352)
by Richard
05:29 queued 35s
created

XoopsLogger::sanitizeDbMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 7
rs 10
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
        $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
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...
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
     * this was deprecated, but is still in broad use?
189
     *
190
     * @param string $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
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...
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) . ': ' . $this->sanitizeDbMessage($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
     * sanitizeDbMessage
291
     * @access protected
292
     *
293
     * @param string $message
294
     *
295
     * @return string
296
     */
297
    protected function sanitizeDbMessage($message)
298
    {
299
        // XOOPS_DB_PREFIX  XOOPS_DB_NAME
300
        $message = str_replace(XOOPS_DB_PREFIX.'_', '', $message);
301
        $message = str_replace(XOOPS_DB_NAME.'.', '', $message);
302
303
        return $message;
304
    }
305
306
    /**
307
     * Output buffering callback inserting logger dump in page output
308
     * @param $output
309
     * @return string
310
     */
311
    public function render($output)
312
    {
313
        global $xoopsUser;
314
        if (!$this->activated) {
315
            return $output;
316
        }
317
318
        $log                    = $this->dump($this->usePopup ? 'popup' : '');
319
        $this->renderingEnabled = $this->activated = false;
320
        $pattern                = '<!--{xo-logger-output}-->';
321
        $pos                    = strpos($output, $pattern);
322
        if ($pos !== false) {
323
            return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
324
        } else {
325
            return $output . $log;
326
        }
327
    }
328
329
    /**
330
     * *#@+
331
     *
332
     * @protected
333
     * @param string $mode
334
     * @return
335
     */
336
    public function dump($mode = '')
337
    {
338
        include XOOPS_ROOT_PATH . '/class/logger/render.php';
339
340
        return $ret;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ret seems to be never defined.
Loading history...
341
    }
342
343
    /**
344
     * get the current execution time of a timer
345
     *
346
     * @param  string $name  name of the counter
347
     * @param  bool   $unset removes counter from global log
348
     * @return float  current execution time of the counter
349
     */
350
    public function dumpTime($name = 'XOOPS', $unset = false)
351
    {
352
        if (!$this->activated) {
353
            return null;
354
        }
355
356
        if (!isset($this->logstart[$name])) {
357
            return 0;
358
        }
359
        $stop  = isset($this->logend[$name]) ? $this->logend[$name] : $this->microtime();
360
        $start = $this->logstart[$name];
361
362
        if ($unset) {
363
            unset($this->logstart[$name]);
364
        }
365
366
        return $stop - $start;
367
    }
368
369
    /**
370
     * XoopsLogger::triggerError()
371
     *
372
     * @deprecated
373
     * @param  int     $errkey
374
     * @param  string  $errStr
375
     * @param  string  $errFile
376
     * @param  string  $errLine
377
     * @param  integer $errNo
378
     * @return void
379
     */
380
    public function triggerError($errkey = 0, $errStr = '', $errFile = '', $errLine = '', $errNo = 0)
381
    {
382
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->triggerError();\' is deprecated since XOOPS 2.5.4');
383
384
        if (!empty($errStr)) {
385
            $errStr = sprintf($errStr, $errkey);
386
        }
387
        $errFile = $this->sanitizePath($errFile);
388
        $this->handleError($errNo, $errStr, $errFile, $errLine);
389
    }
390
391
    /**
392
     * *#@+
393
     *
394
     * @deprecated
395
     */
396
    public function dumpAll()
397
    {
398
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpAll();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'\');\' instead.');
399
400
        return $this->dump('');
401
    }
402
403
    /**
404
     * dumpBlocks @deprecated
405
     *
406
     * @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...
407
     */
408
    public function dumpBlocks()
409
    {
410
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpBlocks();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'blocks\');\' instead.');
411
412
        return $this->dump('blocks');
413
    }
414
415
    /**
416
     * dumpExtra @deprecated
417
     *
418
     * @return dump
419
     */
420
    public function dumpExtra()
421
    {
422
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpExtra();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'extra\');\' instead.');
423
424
        return $this->dump('extra');
425
    }
426
427
    /**
428
     * dump Queries @deprecated
429
     *
430
     * @return mixed
431
     */
432
    public function dumpQueries()
433
    {
434
        $GLOBALS['xoopsLogger']->addDeprecated('\'$xoopsLogger->dumpQueries();\' is deprecated since XOOPS 2.5.4, please use \'$xoopsLogger->dump(\'queries\');\' instead.');
435
436
        return $this->dump('queries');
437
    }
438
    /**
439
     * *#@-
440
     */
441
}
442
443
/**
444
 * PHP Error handler
445
 *
446
 * NB: You're not supposed to call this function directly, if you don't understand why, then
447
 * you'd better spend some time reading your PHP manual before you hurt somebody
448
 *
449
 * @internal Using a function and not calling the handler method directly because of old PHP versions
450
 * set_error_handler() have problems with the array( obj,methodname ) syntax
451
 * @param       $errNo
452
 * @param       $errStr
453
 * @param       $errFile
454
 * @param       $errLine
455
 * @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...
456
 * @return bool
457
 */
458
function XoopsErrorHandler_HandleError($errNo, $errStr, $errFile, $errLine, $errContext = null)
459
{
460
    /*
461
    // We don't want every error to come through this will help speed things up'
462
    if ($errNo == '2048') {
463
        return true;
464
    }
465
    // XOOPS should always be STRICT compliant thus the above lines makes no sense and will be removed! -- Added by Taiwen Jiang
466
    */
467
    $logger = XoopsLogger::getInstance();
468
    $logger->handleError($errNo, $errStr, $errFile, $errLine, $errContext);
469
    return null;
470
}
471