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-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(); |
|
|
|
|
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(); |
|
|
|
|
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; |
|
|
|
|
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 = '') |
|
|
|
|
318
|
|
|
{ |
319
|
|
|
include XOOPS_ROOT_PATH . '/class/logger/render.php'; |
320
|
|
|
|
321
|
|
|
return $ret; |
|
|
|
|
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 |
|
|
|
|
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() |
|
|
|
|
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 |
|
|
|
|
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); |
|
|
|
|
450
|
|
|
return null; |
451
|
|
|
} |
452
|
|
|
|
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.