1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: use Psr\Log\LoggerInterface;
13: use Psr\Log\LogLevel;
14: use Xoops\Core\Logger;
15:
16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
31: class LegacyLogger implements LoggerInterface
32: {
33: 34: 35:
36: protected $queries = array();
37:
38: 39: 40:
41: protected $blocks = array();
42:
43: 44: 45:
46: protected $extra = array();
47:
48: 49: 50:
51: protected $logstart = array();
52:
53: 54: 55:
56: protected $logend = array();
57:
58: 59: 60:
61: protected $errors = array();
62:
63: 64: 65:
66: protected $deprecated = array();
67:
68: 69: 70:
71: protected $renderingEnabled = false;
72:
73: 74: 75:
76: protected $activated = false;
77:
78: 79: 80:
81: protected $configs = false;
82:
83: 84: 85:
86: public function __construct()
87: {
88: Logger::getInstance()->addLogger($this);
89: }
90:
91: 92: 93:
94: protected $usePopup = false;
95:
96:
97: 98: 99: 100: 101:
102: public static function getInstance()
103: {
104: static $instance;
105: if (!isset($instance)) {
106: $class = __CLASS__;
107: $instance = new $class();
108: }
109:
110: return $instance;
111: }
112:
113: 114: 115: 116: 117: 118: 119:
120: public function setConfigs($configs)
121: {
122: $this->configs = $configs;
123: }
124:
125: 126: 127: 128: 129:
130: public function disable()
131: {
132:
133: $this->activated = false;
134: }
135:
136: 137: 138: 139: 140: 141: 142: 143:
144: public function enable()
145: {
146: error_reporting(E_ALL | E_STRICT);
147: $xoops = Xoops::getInstance();
148: if ($this->configs && array_key_exists('logger_enable', $this->configs)) {
149: if ($this->configs['logger_popup']) {
150: $this->usePopup = true;
151: }
152: }
153: $this->activated = true;
154: $this->enableRendering();
155: }
156:
157: 158: 159: 160: 161:
162: public function isEnable()
163: {
164: return $this->activated;
165: }
166:
167: 168: 169: 170: 171:
172: public function quiet()
173: {
174: $this->activated = false;
175: }
176:
177: 178: 179: 180: 181:
182: private function addToTheme()
183: {
184: static $addedResource = false;
185:
186: if ($this->activated && !$addedResource) {
187: if (isset($GLOBALS['xoTheme'])) {
188: 189: 190: 191: 192: 193:
194: $addedResource = true;
195: }
196: }
197: }
198:
199: 200: 201: 202: 203: 204: 205:
206: public function startTime($name = 'XOOPS')
207: {
208: if ($this->activated) {
209: $this->logstart[$name] = microtime(true);
210: }
211: }
212:
213: 214: 215: 216: 217: 218: 219:
220: public function stopTime($name = 'XOOPS')
221: {
222: if ($this->activated) {
223: $this->logend[$name] = microtime(true);
224: }
225: }
226:
227: 228: 229: 230: 231: 232: 233: 234: 235: 236:
237: public function addQuery($sql, $error = null, $errno = null, $query_time = null)
238: {
239: if ($this->activated) {
240: $this->queries[] = array(
241: 'sql' => $sql, 'error' => $error, 'errno' => $errno, 'query_time' => $query_time
242: );
243: }
244: }
245:
246: 247: 248: 249: 250: 251: 252: 253: 254:
255: public function addBlock($name, $cached = false, $cachetime = 0)
256: {
257: if ($this->activated) {
258: $this->blocks[] = array('name' => $name, 'cached' => $cached, 'cachetime' => $cachetime);
259: }
260: }
261:
262: 263: 264: 265: 266: 267: 268: 269:
270: public function addExtra($name, $msg)
271: {
272: if ($this->activated) {
273: $this->extra[] = array('name' => $name, 'msg' => $msg);
274: }
275: }
276:
277: 278: 279: 280: 281: 282: 283:
284: public function addDeprecated($msg)
285: {
286: if ($this->activated) {
287: $this->deprecated[] = $msg;
288: }
289: }
290:
291: 292: 293: 294: 295: 296: 297:
298: public function addException($e)
299: {
300: if ($this->activated) {
301: $this->log(
302: LogLevel::ERROR,
303: 'Exception: ' . $e->getMessage() . ' - ' .
304: $this->sanitizePath($e->getFile()) . ' ' . $e->getLine()
305: );
306: }
307: }
308:
309: 310: 311: 312: 313: 314: 315:
316: public function sanitizePath($path)
317: {
318: $path = str_replace(
319: array(
320: '\\',
321: \XoopsBaseConfig::get('root-path'),
322: str_replace('\\', '/', realpath(\XoopsBaseConfig::get('root-path')))
323: ),
324: array('/', '', ''),
325: $path
326: );
327: return $path;
328: }
329:
330: 331: 332: 333: 334: 335: 336: 337:
338: public function enableRendering()
339: {
340: if (!$this->renderingEnabled) {
341: ob_start(array(&$this, 'render'));
342: $this->renderingEnabled = true;
343: }
344: }
345:
346: 347: 348: 349: 350: 351: 352:
353: public function render($output)
354: {
355: if (!$this->activated) {
356: return $output;
357: }
358:
359: $log = $this->dump($this->usePopup ? 'popup' : '');
360: $this->renderingEnabled = $this->activated = false;
361:
362: $pattern = '<!--{xo-logger-output}-->';
363: $pos = strpos($output, $pattern);
364: if ($pos !== false) {
365: return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
366: } else {
367: return $output . $log;
368: }
369: }
370:
371: 372: 373: 374: 375: 376: 377:
378: public function dump($mode = '')
379: {
380: $ret = '';
381:
382: $xoops = Xoops::getInstance();
383:
384: $ret = '';
385: if ($mode === 'popup') {
386: $dump = $this->dump('');
387: $content = '
388: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
389: <head>
390: <meta http-equiv="content-language" content="' . XoopsLocale::getLangCode() . '" />
391: <meta http-equiv="content-type" content="text/html; charset=' . XoopsLocale::getCharset() . '" />
392: <title>' . $xoops->getConfig('sitename') . ' - ' . _MD_LOGGER_DEBUG . ' </title>
393: <meta name="generator" content="XOOPS" />
394: <link rel="stylesheet" type="text/css" media="all" href="' . $xoops->getCss($xoops->getConfig('theme_set')) . '" />
395: </head>
396: <body>' . $dump . '
397: <div style="text-align:center;">
398: <input class="formButton" value="' . XoopsLocale::A_CLOSE . '" type="button" onclick="javascript:window.close();" />
399: </div>
400: ';
401: $ret .= '
402: <script type="text/javascript">
403: debug_window = openWithSelfMain("about:blank", "popup", 680, 450, true);
404: debug_window.document.clear();
405: ';
406: $lines = preg_split("/(\r\n|\r|\n)( *)/", $content);
407: foreach ($lines as $line) {
408: $ret .= "\n" . 'debug_window.document.writeln("'
409: . str_replace(array('"', '</'), array('\"', '<\/'), $line) . '");';
410: }
411: $ret .= '
412: debug_window.focus();
413: debug_window.document.close();
414: </script>
415: ';
416: }
417:
418: $this->addExtra(
419: _MD_LOGGER_INCLUDED_FILES,
420: sprintf(_MD_LOGGER_FILES, count(get_included_files()))
421: );
422:
423: 424: 425: 426: 427: 428: 429: 430: 431: 432:
433:
434: $memory = 0;
435:
436: if (function_exists('memory_get_usage')) {
437: $memory = memory_get_usage() . ' bytes';
438: } else {
439: if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
440: $out = array();
441: exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $out);
442: if (isset($out[5])) {
443: $memory = sprintf(_MD_LOGGER_MEM_ESTIMATED, substr($out[5], strpos($out[5], ':') + 1));
444: }
445: }
446: }
447: if ($memory) {
448: $this->addExtra(_MD_LOGGER_MEM_USAGE, $memory);
449: }
450:
451: if (empty($mode)) {
452: $views = array('errors', 'deprecated', 'queries', 'blocks', 'extra');
453: $ret .= "\n<div id=\"xo-logger-output\">\n<div id='xo-logger-tabs'>\n";
454: $ret .= "<a href='javascript:xoSetLoggerView(\"none\")'>" . _MD_LOGGER_NONE . "</a>\n";
455: $ret .= "<a href='javascript:xoSetLoggerView(\"\")'>" . _MD_LOGGER_ALL . "</a>\n";
456: foreach ($views as $view) {
457: $count = count($this->$view);
458: $ret .= "<a href='javascript:xoSetLoggerView(\"$view\")'>" . constant('_MD_LOGGER_' . strtoupper($view)) . " ($count)</a>\n";
459: }
460: $count = count($this->logstart);
461: $ret .= "<a href='javascript:xoSetLoggerView(\"timers\")'>" . _MD_LOGGER_TIMERS . "($count)</a>\n";
462: $ret .= "</div>\n";
463: }
464:
465: if (empty($mode) || $mode === 'errors') {
466: $class = 'even';
467: $ret .= '<table id="xo-logger-errors" class="outer"><thead><tr><th>' . _MD_LOGGER_ERRORS . '</th></tr></thead><tbody>';
468: foreach ($this->errors as $error) {
469: $ret .= "\n<tr><td class='$class'>";
470: $ret .= $error;
471: $ret .= "<br />\n</td></tr>";
472: $class = ($class === 'odd') ? 'even' : 'odd';
473: }
474: $ret .= "\n</tbody></table>\n";
475: }
476:
477: if (empty($mode) || $mode === 'deprecated') {
478: $class = 'even';
479: $ret .= '<table id="xo-logger-deprecated" class="outer"><thead><tr><th>' . _MD_LOGGER_DEPRECATED . '</th></tr></thead><tbody>';
480: foreach ($this->deprecated as $message) {
481: $ret .= "\n<tr><td class='$class'>";
482: $ret .= $message;
483: $ret .= "<br />\n</td></tr>";
484: $class = ($class === 'odd') ? 'even' : 'odd';
485: }
486: $ret .= "\n</tbody></table>\n";
487: }
488:
489: if (empty($mode) || $mode === 'queries') {
490: $class = 'even';
491: $ret .= '<table id="xo-logger-queries" class="outer"><thead><tr><th>' . _MD_LOGGER_QUERIES . '</th></tr></thead><tbody>';
492: $pattern = '/\b' . preg_quote(\XoopsBaseConfig::get('db-prefix')) . '\_/i';
493:
494: foreach ($this->queries as $q) {
495: $sql = preg_replace($pattern, '', $q['sql']);
496: $query_time = isset($q['query_time']) ? sprintf('%0.6f - ', $q['query_time']) : '';
497:
498: if (isset($q['error'])) {
499: $ret .= '<tr class="' . $class . '"><td><span style="color:#ff0000;">' . $query_time . htmlentities($sql) . '<br /><strong>Error number:</strong> ' . $q['errno'] . '<br /><strong>Error message:</strong> ' . $q['error'] . '</span></td></tr>';
500: } else {
501: $ret .= '<tr class="' . $class . '"><td>' . $query_time . htmlentities($sql) . '</td></tr>';
502: }
503:
504: $class = ($class === 'odd') ? 'even' : 'odd';
505: }
506: $ret .= '</tbody><tfoot><tr class="foot"><td>' . _MD_LOGGER_TOTAL . ': <span style="color:#ff0000;">' . count($this->queries) . '</span></td></tr></tfoot></table>';
507: }
508: if (empty($mode) || $mode === 'blocks') {
509: $class = 'even';
510: $ret .= '<table id="xo-logger-blocks" class="outer"><thead><tr><th>' . _MD_LOGGER_BLOCKS . '</th></tr></thead><tbody>';
511: foreach ($this->blocks as $b) {
512: if ($b['cached']) {
513: $ret .= '<tr><td class="' . $class . '"><strong>' . $b['name'] . ':</strong> ' . sprintf(_MD_LOGGER_CACHED, (int)($b['cachetime'])) . '</td></tr>';
514: } else {
515: $ret .= '<tr><td class="' . $class . '"><strong>' . $b['name'] . ':</strong> ' . _MD_LOGGER_NOT_CACHED . '</td></tr>';
516: }
517: $class = ($class === 'odd') ? 'even' : 'odd';
518: }
519: $ret .= '</tbody><tfoot><tr class="foot"><td>' . _MD_LOGGER_TOTAL . ': <span style="color:#ff0000;">' . count($this->blocks) . '</span></td></tr></tfoot></table>';
520: }
521: if (empty($mode) || $mode === 'extra') {
522: $class = 'even';
523: $ret .= '<table id="xo-logger-extra" class="outer"><thead><tr><th>' . _MD_LOGGER_EXTRA . '</th></tr></thead><tbody>';
524: foreach ($this->extra as $ex) {
525: $ret .= '<tr><td class="' . $class . '"><strong>';
526: $ret .= htmlspecialchars($ex['name']) . ':</strong> ' . htmlspecialchars($ex['msg']);
527: $ret .= '</td></tr>';
528: $class = ($class === 'odd') ? 'even' : 'odd';
529: }
530: $ret .= '</tbody></table>';
531: }
532: if (empty($mode) || $mode === 'timers') {
533: $class = 'even';
534: $ret .= '<table id="xo-logger-timers" class="outer"><thead><tr><th>' . _MD_LOGGER_TIMERS . '</th></tr></thead><tbody>';
535: foreach ($this->logstart as $k => $v) {
536: $ret .= '<tr><td class="' . $class . '"><strong>';
537: $ret .= sprintf(_MD_LOGGER_TIMETOLOAD, htmlspecialchars($k) . '</strong>', '<span style="color:#ff0000;">' . sprintf("%.03f", $this->dumpTime($k)) . '</span>');
538: $ret .= '</td></tr>';
539: $class = ($class === 'odd') ? 'even' : 'odd';
540: }
541: $ret .= '</tbody></table>';
542: }
543:
544: if (empty($mode)) {
545: $ret .= <<<EOT
546: </div>
547: <script type="text/javascript">
548: function xoLogCreateCookie(name,value,days) {
549: if (days) {
550: var date = new Date();
551: date.setTime(date.getTime()+(days*24*60*60*1000));
552: var expires = "; expires="+date.toGMTString();
553: }
554: else var expires = "";
555: document.cookie = name+"="+value+expires+"; path=/";
556: }
557: function xoLogReadCookie(name) {
558: var nameEQ = name + "=";
559: var ca = document.cookie.split(';');
560: for(var i=0;i < ca.length;i++) {
561: var c = ca[i];
562: while (c.charAt(0)==' ') c = c.substring(1,c.length);
563: if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
564: }
565: return null;
566: }
567: function xoLogEraseCookie(name) {
568: createCookie(name,"",-1);
569: }
570: function xoSetLoggerView( name ) {
571: var log = document.getElementById( "xo-logger-output" );
572: if ( !log ) return;
573: var i, elt;
574: for ( i=0; i!=log.childNodes.length; i++ ) {
575: elt = log.childNodes[i];
576: if ( elt.tagName && elt.tagName.toLowerCase() != 'script' && elt.id != "xo-logger-tabs" ) {
577: elt.style.display = ( !name || elt.id == "xo-logger-" + name ) ? "block" : "none";
578: }
579: }
580: xoLogCreateCookie( 'XOLOGGERVIEW', name, 1 );
581: }
582: xoSetLoggerView( xoLogReadCookie( 'XOLOGGERVIEW' ) );
583: </script>
584:
585: EOT;
586: }
587:
588: return $ret;
589: }
590:
591: 592: 593: 594: 595: 596: 597: 598:
599: public function dumpTime($name = 'XOOPS', $unset = false)
600: {
601: if (!$this->activated) {
602: return null;
603: }
604:
605: if (!isset($this->logstart[$name])) {
606: return 0;
607: }
608: $stop = isset($this->logend[$name]) ? $this->logend[$name] : microtime(true);
609: $start = $this->logstart[$name];
610:
611: if ($unset) {
612: unset($this->logstart[$name]);
613: unset($this->logend[$name]);
614: }
615:
616: return $stop - $start;
617: }
618:
619:
620: 621: 622: 623: 624: 625: 626: 627:
628: public function emergency($message, array $context = array())
629: {
630: if ($this->activated) {
631: $this->log(LogLevel::EMERGENCY, $message, $context);
632: }
633: }
634:
635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645:
646: public function alert($message, array $context = array())
647: {
648: if ($this->activated) {
649: $this->log(LogLevel::ALERT, $message, $context);
650: }
651: }
652:
653: 654: 655: 656: 657: 658: 659: 660: 661: 662:
663: public function critical($message, array $context = array())
664: {
665: if ($this->activated) {
666: $this->log(LogLevel::CRITICAL, $message, $context);
667: }
668: }
669:
670: 671: 672: 673: 674: 675: 676: 677: 678:
679: public function error($message, array $context = array())
680: {
681: if ($this->activated) {
682: $this->log(LogLevel::ERROR, $message, $context);
683: }
684: }
685:
686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696:
697: public function warning($message, array $context = array())
698: {
699: if ($this->activated) {
700: $this->log(LogLevel::WARNING, $message, $context);
701: }
702: }
703:
704: 705: 706: 707: 708: 709: 710: 711:
712: public function notice($message, array $context = array())
713: {
714: if ($this->activated) {
715: $this->log(LogLevel::NOTICE, $message, $context);
716: }
717: }
718:
719: 720: 721: 722: 723: 724: 725: 726: 727: 728:
729: public function info($message, array $context = array())
730: {
731: if ($this->activated) {
732: $this->log(LogLevel::INFO, $message, $context);
733: }
734: }
735:
736: 737: 738: 739: 740: 741: 742: 743:
744: public function debug($message, array $context = array())
745: {
746: if ($this->activated) {
747: $this->log(LogLevel::DEBUG, $message, $context);
748: }
749: }
750:
751: 752: 753: 754: 755: 756: 757: 758: 759:
760: public function log($level, $message, array $context = array())
761: {
762: if (!$this->activated) {
763: return;
764: }
765:
766: $this->errors[] = $message;
767: }
768: }
769: