1: <?php
2: /**
3: * CLogFilter class file
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CLogFilter preprocesses the logged messages before they are handled by a log route.
13: *
14: * CLogFilter is meant to be used by a log route to preprocess the logged messages
15: * before they are handled by the route. The default implementation of CLogFilter
16: * prepends additional context information to the logged messages. In particular,
17: * by setting {@link logVars}, predefined PHP variables such as
18: * $_SERVER, $_POST, etc. can be saved as a log message, which may help identify/debug
19: * issues encountered.
20: *
21: * @author Qiang Xue <qiang.xue@gmail.com>
22: * @package system.logging
23: */
24: class CLogFilter extends CComponent implements ILogFilter
25: {
26: /**
27: * @var boolean whether to prefix each log message with the current user session ID.
28: * Defaults to false.
29: */
30: public $prefixSession=false;
31: /**
32: * @var boolean whether to prefix each log message with the current user
33: * {@link CWebUser::name name} and {@link CWebUser::id ID}. Defaults to false.
34: */
35: public $prefixUser=false;
36: /**
37: * @var boolean whether to log the current user name and ID. Defaults to true.
38: */
39: public $logUser=true;
40: /**
41: * @var array list of the PHP predefined variables that should be logged.
42: * Note that a variable must be accessible via $GLOBALS. Otherwise it won't be logged.
43: */
44: public $logVars=array('_GET','_POST','_FILES','_COOKIE','_SESSION','_SERVER');
45: /**
46: * @var callable or function which will be used to dump context information.
47: * Defaults to `var_export`. If you're experiencing issues with circular references
48: * problem change it to `print_r`. Any kind of callable (static methods, user defined
49: * functions, lambdas, etc.) could also be used.
50: * @since 1.1.14
51: */
52: public $dumper='var_export';
53:
54:
55: /**
56: * Filters the given log messages.
57: * This is the main method of CLogFilter. It processes the log messages
58: * by adding context information, etc.
59: * @param array $logs the log messages
60: * @return array
61: */
62: public function filter(&$logs)
63: {
64: if (!empty($logs))
65: {
66: if(($message=$this->getContext())!=='')
67: array_unshift($logs,array($message,CLogger::LEVEL_INFO,'application',YII_BEGIN_TIME));
68: $this->format($logs);
69: }
70: return $logs;
71: }
72:
73: /**
74: * Formats the log messages.
75: * The default implementation will prefix each message with session ID
76: * if {@link prefixSession} is set true. It may also prefix each message
77: * with the current user's name and ID if {@link prefixUser} is true.
78: * @param array $logs the log messages
79: */
80: protected function format(&$logs)
81: {
82: $prefix='';
83: if($this->prefixSession && ($id=session_id())!=='')
84: $prefix.="[$id]";
85: if($this->prefixUser && ($user=Yii::app()->getComponent('user',false))!==null)
86: $prefix.='['.$user->getName().']['.$user->getId().']';
87: if($prefix!=='')
88: {
89: foreach($logs as &$log)
90: $log[0]=$prefix.' '.$log[0];
91: }
92: }
93:
94: /**
95: * Generates the context information to be logged.
96: * The default implementation will dump user information, system variables, etc.
97: * @return string the context information. If an empty string, it means no context information.
98: */
99: protected function getContext()
100: {
101: $context=array();
102: if($this->logUser && ($user=Yii::app()->getComponent('user',false))!==null)
103: $context[]='User: '.$user->getName().' (ID: '.$user->getId().')';
104:
105: if($this->dumper==='var_export' || $this->dumper==='print_r')
106: {
107: foreach($this->logVars as $name)
108: if(($value=$this->getGlobalsValue($name))!==null)
109: $context[]="\${$name}=".call_user_func($this->dumper,$value,true);
110: }
111: else
112: {
113: foreach($this->logVars as $name)
114: if(($value=$this->getGlobalsValue($name))!==null)
115: $context[]="\${$name}=".call_user_func($this->dumper,$value);
116: }
117:
118: return implode("\n\n",$context);
119: }
120:
121: /**
122: * @param string[] $path
123: * @return string|null
124: */
125: private function getGlobalsValue(&$path)
126: {
127: if(is_scalar($path))
128: return !empty($GLOBALS[$path]) ? $GLOBALS[$path] : null;
129: $pathAux=$path;
130: $parts=array();
131: $value=$GLOBALS;
132: do
133: {
134: $value=$value[$parts[]=array_shift($pathAux)];
135: }
136: while(!empty($value) && !empty($pathAux) && !is_string($value));
137: $path=implode('.',$parts);
138: return $value;
139: }
140: }
141: