1: <?php
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: namespace Thelia\Log;
24:
25: use Thelia\Model\ConfigQuery;
26: use Psr\Log\LoggerInterface;
27:
28: 29: 30: 31: 32: 33: 34: 35: 36:
37: class Tlog Implements LoggerInterface
38: {
39:
40: const VAR_LEVEL = "tlog_level";
41: const VAR_DESTINATIONS = "tlog_destinations";
42: const VAR_PREFIXE = "tlog_prefix";
43: const VAR_FILES = "tlog_files";
44: const VAR_IP = "tlog_ip";
45: const VAR_SHOW_REDIRECT = "tlog_show_redirect";
46:
47:
48: const DEBUG = 100;
49: const INFO = 200;
50: const NOTICE = 300;
51: const WARNING = 400;
52: const ERROR = 500;
53: const CRITICAL = 600;
54: const ALERT = 700;
55: const EMERGENCY = 800;
56: const MUET = PHP_INT_MAX;
57:
58: protected $levels = array(
59: 100 => "DEBUG",
60: 200 => "INFO",
61: 300 => "NOTICE",
62: 400 => "WARNING",
63: 500 => "ERROR",
64: 600 => "CRITICAL",
65: 700 => "ALERT",
66: 800 => "EMERGENCY"
67: );
68:
69:
70: const DEFAULT_LEVEL = self::DEBUG;
71: const DEFAUT_DESTINATIONS = "Thelia\Log\Destination\TlogDestinationFile";
72: const DEFAUT_PREFIXE = "#NUM: #NIVEAU [#FICHIER:#FONCTION()] {#LIGNE} #DATE #HEURE: ";
73: const DEFAUT_FILES = "*";
74: const DEFAUT_IP = "";
75: const DEFAUT_SHOW_REDIRECT = 0;
76:
77: 78: 79: 80:
81: private static $instance = false;
82:
83: 84: 85: 86:
87: protected $destinations = array();
88:
89: protected $mode_back_office = false;
90: protected $level = self::MUET;
91: protected $prefixe = "";
92: protected $files = array();
93: protected $all_files = false;
94: protected $show_redirect = false;
95:
96: private $linecount = 0;
97:
98: protected static $done = false;
99:
100:
101: public $dir_destinations = array();
102:
103: 104: 105:
106: private function __construct(){}
107:
108: 109: 110: 111:
112: public static function getInstance() {
113: if (self::$instance == false) {
114: self::$instance = new Tlog();
115:
116:
117:
118:
119: self::$instance->init();
120: }
121:
122: return self::$instance;
123: }
124:
125: 126: 127:
128: protected function init()
129: {
130:
131: $this->setLevel(ConfigQuery::read(self::VAR_LEVEL, self::DEFAULT_LEVEL));
132:
133: $this->dir_destinations = array(
134: __DIR__.'/Destination'
135:
136: );
137:
138: $this->setPrefix(ConfigQuery::read(self::VAR_PREFIXE, self::DEFAUT_PREFIXE));
139: $this->setFiles(ConfigQuery::read(self::VAR_FILES, self::DEFAUT_FILES));
140: $this->setIp(ConfigQuery::read(self::VAR_IP, self::DEFAUT_IP));
141: $this->setDestinations(ConfigQuery::read(self::VAR_DESTINATIONS, self::DEFAUT_DESTINATIONS));
142: $this->setShowRedirect(ConfigQuery::read(self::VAR_SHOW_REDIRECT, self::DEFAUT_SHOW_REDIRECT));
143:
144:
145: register_shutdown_function(array($this, 'writeOnExit'));
146: }
147:
148:
149:
150:
151: 152: 153: 154:
155: public function setDestinations($destinations)
156: {
157: if (! empty($destinations)) {
158:
159: $this->destinations = array();
160:
161: $classes_destinations = explode(';', $destinations);
162: $this->loadDestinations($this->destinations, $classes_destinations);
163: }
164: }
165:
166: 167: 168: 169: 170: 171:
172: public function setLevel($level)
173: {
174: $this->level = $level;
175: }
176:
177: public function setPrefix($prefixe)
178: {
179: $this->prefixe = $prefixe;
180: }
181:
182: public function setFiles($files)
183: {
184: $this->files = explode(";", $files);
185:
186: $this->all_files = in_array('*', $this->files);
187: }
188:
189: public function setIp($ips)
190: {
191:
192: if (! empty($ips) && isset($_SERVER['REMOTE_ADDR']) && ! in_array($_SERVER['REMOTE_ADDR'], explode(";", $ips))) $this->level = self::MUET;
193: }
194:
195: public function setShowRedirect($bool)
196: {
197: $this->show_redirect = $bool;
198: }
199:
200:
201: public function setConfig($destination, $param, $valeur)
202: {
203: if (isset($this->destinations[$destination])) {
204: $this->destinations[$destination]->setConfig($param, $valeur);
205: }
206: }
207:
208:
209: public function getConfig($destination, $param)
210: {
211: if (isset($this->destinations[$destination])) {
212: return $this->destinations[$destination]->getConfig($param);
213: }
214:
215: return false;
216: }
217:
218:
219:
220:
221: 222: 223: 224: 225: 226: 227:
228: public function debug($message, array $context = array())
229: {
230: $this->log(self::DEBUG, $message, $context);
231: }
232:
233: 234: 235: 236: 237: 238: 239:
240: public function addDebug()
241: {
242: $args = func_get_args();
243:
244: foreach ($args as $arg) {
245: $this->log(self::DEBUG, $arg);
246: }
247: }
248:
249: 250: 251: 252: 253: 254: 255: 256: 257:
258: public function info($message, array $context = array())
259: {
260: $this->log(self::INFO, $message, $context);
261: }
262:
263: 264: 265: 266: 267: 268: 269:
270: public function addInfo()
271: {
272: $args = func_get_args();
273:
274: foreach ($args as $arg) {
275: $this->log(self::INFO, $arg);
276: }
277: }
278:
279: 280: 281: 282: 283: 284: 285:
286: public function notice($message, array $context = array())
287: {
288: $this->log(self::NOTICE, $message, $context);
289: }
290:
291: 292: 293: 294: 295: 296: 297:
298: public function addNotice()
299: {
300: $args = func_get_args();
301:
302: foreach ($args as $arg) {
303: $this->log(self::NOTICE, $arg);
304: }
305: }
306:
307: 308: 309: 310: 311: 312: 313: 314: 315: 316:
317: public function warning($message, array $context = array())
318: {
319: $this->log(self::WARNING, $message, $context);
320: }
321:
322: 323: 324: 325: 326: 327: 328:
329: public function addWarning()
330: {
331: $args = func_get_args();
332:
333: foreach ($args as $arg) {
334: $this->log(self::WARNING, $arg);
335: }
336: }
337:
338: 339: 340: 341: 342: 343: 344: 345:
346: public function error($message, array $context = array())
347: {
348: $this->log(self::ERROR, $message, $context);
349: }
350:
351: 352: 353: 354: 355: 356: 357:
358: public function addError()
359: {
360: $args = func_get_args();
361:
362: foreach ($args as $arg) {
363: $this->log(self::ERROR, $arg);
364: }
365: }
366:
367: 368: 369: 370:
371: public function err($message, array $context = array())
372: {
373: $this->error($message, $context);
374: }
375:
376: 377: 378: 379: 380: 381: 382: 383: 384:
385: public function critical($message, array $context = array())
386: {
387: $this->log(self::CRITICAL, $message, $context);
388: }
389:
390: 391: 392: 393: 394: 395: 396:
397: public function addCritical()
398: {
399: $args = func_get_args();
400:
401: foreach ($args as $arg) {
402: $this->log(self::CRITICAL, $arg);
403: }
404: }
405:
406: 407: 408: 409:
410: public function crit($message, array $context = array())
411: {
412: $this->critical($message, $context);
413: }
414:
415: 416: 417: 418: 419: 420: 421: 422: 423: 424:
425: public function alert($message, array $context = array())
426: {
427: $this->log(self::ALERT, $message, $context);
428: }
429:
430: 431: 432: 433: 434: 435: 436:
437: public function addAlert()
438: {
439: $args = func_get_args();
440:
441: foreach ($args as $arg) {
442: $this->log(self::ALERT, $arg);
443: }
444: }
445:
446: 447: 448: 449: 450: 451: 452:
453: public function emergency($message, array $context = array())
454: {
455: $this->log(self::EMERGENCY, $message, $context);
456: }
457:
458: 459: 460: 461: 462: 463: 464:
465: public function addEmergency()
466: {
467: $args = func_get_args();
468:
469: foreach ($args as $arg) {
470: $this->log(self::EMERGENCY, $arg);
471: }
472: }
473:
474: 475: 476: 477: 478: 479: 480: 481:
482: public function log($level, $message, array $context = array()) {
483: if($this->level > $level || array_key_exists($level, $this->levels) === false)
484: return;
485:
486: $this->out($this->levels[$level], $message, $context);
487: }
488:
489:
490:
491:
492: public static function SetBackOfficeMode($booleen)
493: {
494: foreach (Tlog::getInstance()->destinations as $dest) {
495: $dest->SetBackOfficeMode($booleen);
496: }
497: }
498:
499: 500: 501: 502: 503: 504: 505:
506: public function write(&$res)
507: {
508: self::$done = true;
509:
510:
511: if ($this->level == self::MUET) return;
512:
513: foreach ($this->destinations as $dest) {
514: $dest->write($res);
515: }
516: }
517:
518: 519: 520:
521: public function writeOnExit()
522: {
523:
524: if (self::$done === false) {
525:
526: $res = "";
527:
528: $this->write($res);
529:
530: echo $res;
531: }
532: }
533:
534: public function showRedirect($url)
535: {
536: if ($this->level != self::MUET && $this->show_redirect) {
537: echo "
538: <html>
539: <head><title>Redirection...</title></head>
540: <body>
541: <a href=\"$url\">Redirection vers $url</a>
542: </body>
543: </html>
544: ";
545:
546: return true;
547: } else {
548: return false;
549: }
550: }
551:
552: 553: 554: 555: 556: 557: 558:
559: public function isActivated($level)
560: {
561: if ($this->level <= $level) {
562:
563: $origin = $this->findOrigin();
564:
565: $file = basename($origin['file']);
566:
567: if ($this->isActivedFile($file)) {
568: return true;
569: }
570: }
571:
572: return false;
573: }
574:
575: 576: 577: 578: 579: 580: 581:
582: public function isActivedFile($file)
583: {
584: return ($this->all_files || in_array($file, $this->files)) && ! in_array("!$file", $this->files);
585: }
586:
587:
588:
589:
590: private function findOrigin()
591: {
592: $origine = array();
593:
594: if (function_exists('debug_backtrace')) {
595:
596: $trace = debug_backtrace();
597: $prevHop = null;
598:
599: $hop = array_pop($trace);
600:
601: while ($hop !== null) {
602: if (isset($hop['class'])) {
603:
604: $className = $hop['class'];
605:
606: if (! empty($className) and ($className == ltrim(__CLASS__,'\\') or strtolower(get_parent_class($className)) == ltrim(__CLASS__,'\\'))) {
607: $origine['line'] = $hop['line'];
608: $origine['file'] = $hop['file'];
609: break;
610: }
611: }
612: $prevHop = $hop;
613: $hop = array_pop($trace);
614: }
615:
616: $origine['class'] = isset($prevHop['class']) ? $prevHop['class'] : 'main';
617:
618: if(isset($prevHop['function']) and
619: $prevHop['function'] !== 'include' and
620: $prevHop['function'] !== 'include_once' and
621: $prevHop['function'] !== 'require' and
622: $prevHop['function'] !== 'require_once') {
623:
624: $origine['function'] = $prevHop['function'];
625: } else {
626: $origine['function'] = 'main';
627: }
628: }
629:
630: return $origine;
631: }
632:
633: protected function interpolate($message, array $context = array())
634: {
635:
636: $replace = array();
637: foreach ($context as $key => $val) {
638: $replace['{' . $key . '}'] = $val;
639: }
640:
641:
642: return strtr($message, $replace);
643: }
644:
645: private function out($level, $message, array $context = array())
646: {
647: $text = '';
648:
649: 650: 651: 652: 653: if (is_scalar($message) === false) {
654: $text = print_r($message, true);
655: } else {
656: $text = $message;
657: }
658:
659: $text = $this->interpolate($text, $context);
660:
661: $origine = $this->findOrigin();
662:
663: $file = basename($origine['file']);
664:
665: if ($this->isActivedFile($file)) {
666:
667: $function = $origine['function'];
668: $line = $origine['line'];
669:
670: $prefixe = str_replace(
671: array("#NUM", "#NIVEAU", "#FICHIER", "#FONCTION", "#LIGNE", "#DATE", "#HEURE"),
672: array(1+$this->linecount, $level, $file, $function, $line, date("Y-m-d"), date("G:i:s")),
673: $this->prefixe
674: );
675:
676: $trace = $prefixe . $text;
677:
678: foreach ($this->destinations as $dest) {
679: $dest->add($trace);
680: }
681:
682: $this->linecount++;
683: }
684: }
685:
686: 687: 688: 689: 690:
691: protected function loadDestinations(&$destinations, array $actives = NULL)
692: {
693: foreach ($actives as $active) {
694: if (class_exists($active)) {
695: $class = new $active();
696:
697: if (!$class instanceof AbstractTlogDestination) {
698: throw new \UnexpectedValueException($active." must extends Thelia\Tlog\AbstractTlogDestination");
699: }
700:
701: $destinations[$active] = $class;
702: }
703: }
704: }
705: }
706: