This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types = 1); |
||
3 | |||
4 | /** |
||
5 | * Micro |
||
6 | * |
||
7 | * @author Raffael Sahli <[email protected]> |
||
8 | * @copyright Copyright (c) 2017 gyselroth GmbH (https://gyselroth.com) |
||
9 | * @license MIT https://opensource.org/licenses/MIT |
||
10 | */ |
||
11 | |||
12 | namespace Micro; |
||
13 | |||
14 | use \Psr\Log\AbstractLogger; |
||
15 | use \Psr\Log\LogLevel; |
||
16 | use \Psr\Log\LoggerInterface; |
||
17 | use \Micro\Log\Adapter\AbstractAdapter; |
||
18 | use \Micro\Log\Adapter\AdapterInterface; |
||
19 | use \Micro\Config; |
||
20 | use \Micro\Log\Exception; |
||
21 | use \Micro\Container\AdapterAwareInterface; |
||
22 | |||
23 | class Log extends AbstractLogger implements LoggerInterface, AdapterAwareInterface |
||
24 | { |
||
25 | /** |
||
26 | * Priorities |
||
27 | */ |
||
28 | const PRIORITIES = [ |
||
29 | LogLevel::EMERGENCY => 0, |
||
30 | LogLevel::ALERT => 1, |
||
31 | LogLevel::CRITICAL => 2, |
||
32 | LogLevel::ERROR => 3, |
||
33 | LogLevel::WARNING => 4, |
||
34 | LogLevel::NOTICE => 5, |
||
35 | LogLevel::INFO => 6, |
||
36 | LogLevel::DEBUG => 7, |
||
37 | ]; |
||
38 | |||
39 | |||
40 | /** |
||
41 | * Adapters |
||
42 | * |
||
43 | * @var array |
||
44 | */ |
||
45 | protected $adapter = []; |
||
46 | |||
47 | |||
48 | /** |
||
49 | * static context |
||
50 | * |
||
51 | * @var array |
||
52 | */ |
||
53 | protected $context = []; |
||
54 | |||
55 | |||
56 | /** |
||
57 | * Initialize logger |
||
58 | * |
||
59 | * @param Iterable $config |
||
60 | * @return void |
||
61 | */ |
||
62 | public function __construct(? Iterable $config = null) |
||
63 | { |
||
64 | $this->setOptions($config); |
||
65 | } |
||
66 | |||
67 | |||
68 | /** |
||
69 | * Set options |
||
70 | * |
||
71 | * @param Iterable $config |
||
72 | * @return Log |
||
73 | */ |
||
74 | public function setOptions(? Iterable $config = null): Log |
||
75 | { |
||
76 | if ($config === null) { |
||
77 | return $this; |
||
78 | } |
||
79 | |||
80 | foreach ($config as $option => $value) { |
||
81 | switch($option) { |
||
82 | case 'adapter': |
||
0 ignored issues
–
show
|
|||
83 | foreach($value as $name => $adapter) { |
||
84 | $this->injectAdapter($name, $adapter); |
||
85 | } |
||
86 | break; |
||
87 | default: |
||
88 | throw new Exception('invalid option '.$option.' given'); |
||
89 | } |
||
90 | } |
||
91 | |||
92 | return $this; |
||
93 | } |
||
94 | |||
95 | |||
96 | /** |
||
97 | * {@inheritDoc} |
||
98 | */ |
||
99 | public function getDefaultAdapter(): array |
||
100 | { |
||
101 | return []; |
||
102 | } |
||
103 | |||
104 | |||
105 | /** |
||
106 | * {@inheritDoc} |
||
107 | */ |
||
108 | public function hasAdapter(string $name): bool |
||
109 | { |
||
110 | return isset($this->adapter[$name]); |
||
111 | } |
||
112 | |||
113 | |||
114 | /** |
||
115 | * {@inheritDoc} |
||
116 | */ |
||
117 | public function injectAdapter($adapter, ?string $name=null) : AdapterAwareInterface |
||
118 | { |
||
119 | if(!($adapter instanceof AdapterInterface)) { |
||
120 | throw new Exception('adapter needs to implement AdapterInterface'); |
||
121 | } |
||
122 | |||
123 | if($name === null) { |
||
124 | $name = get_class($adapter); |
||
125 | } |
||
126 | |||
127 | if ($this->hasAdapter($name)) { |
||
128 | throw new Exception('log adapter '.$name.' is already registered'); |
||
129 | } |
||
130 | |||
131 | $this->adapter[$name] = $adapter; |
||
132 | return $this; |
||
133 | } |
||
134 | |||
135 | |||
136 | /** |
||
137 | * {@inheritDoc} |
||
138 | */ |
||
139 | public function getAdapter(string $name) |
||
140 | { |
||
141 | if (!$this->hasAdapter($name)) { |
||
142 | throw new Exception('log adapter '.$name.' is not registered'); |
||
143 | } |
||
144 | |||
145 | return $this->adapter[$name]; |
||
146 | } |
||
147 | |||
148 | |||
149 | /** |
||
150 | * Get adapters |
||
151 | * |
||
152 | * @param array $adapters |
||
153 | * @return array |
||
154 | */ |
||
155 | public function getAdapters(array $adapters = []): array |
||
156 | { |
||
157 | if (empty($adapter)) { |
||
158 | return $this->adapter; |
||
159 | } else { |
||
160 | $list = []; |
||
161 | foreach ($adapter as $name) { |
||
162 | if (!$this->hasAdapter($name)) { |
||
163 | throw new Exception('log adapter '.$name.' is not registered'); |
||
164 | } |
||
165 | $list[$name] = $this->adapter[$name]; |
||
166 | } |
||
167 | |||
168 | return $list; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | |||
173 | /** |
||
174 | * Log message |
||
175 | * |
||
176 | * @param string $level |
||
177 | * @param string $message |
||
178 | * @param array $context |
||
179 | * @return bool |
||
180 | */ |
||
181 | public function log($level, $message, array $context = []): bool |
||
182 | { |
||
183 | if (!array_key_exists($level, self::PRIORITIES)) { |
||
184 | throw new Exception('log level '.$level.' is unkown'); |
||
185 | } |
||
186 | |||
187 | foreach ($this->adapter as $adapter) { |
||
188 | $prio = $adapter->getLevel(); |
||
189 | |||
190 | if (self::PRIORITIES[$level] <= $prio) { |
||
191 | $msg = $this->_format($message, $adapter->getFormat(), $adapter->getDateFormat(), $level, $context); |
||
192 | $adapter->log($level, $msg); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | return true; |
||
197 | } |
||
198 | |||
199 | |||
200 | /** |
||
201 | * Add static context |
||
202 | * |
||
203 | * @param string $name |
||
204 | * @param string $value |
||
205 | * @return Log |
||
206 | */ |
||
207 | public function addContext(string $name, string $value): Log |
||
208 | { |
||
209 | $this->context[$name] = $value; |
||
210 | return $this; |
||
211 | } |
||
212 | |||
213 | |||
214 | /** |
||
215 | * Log message |
||
216 | * |
||
217 | * @param string $message |
||
218 | * @param string $format |
||
219 | * @param string $date_format |
||
220 | * @param string $level |
||
221 | * @param array $context |
||
222 | * @return string |
||
223 | */ |
||
224 | protected function _format(string $message, string $format, string $date_format, string $level, array $context = []): string |
||
225 | { |
||
226 | $parsed = preg_replace_callback('/(\{(([a-z]\.*)+)\})/', function($match) use ($message, $level, $date_format, $context) { |
||
227 | $key = ''; |
||
228 | $context = array_merge($this->context, $context); |
||
229 | |||
230 | if ($sub_context = strpos($match[2], '.')) { |
||
231 | $parts = explode('.', $match[2]); |
||
232 | $name = $parts[0]; |
||
233 | $key = $parts[1]; |
||
234 | } else { |
||
235 | $name = $match[2]; |
||
236 | } |
||
237 | |||
238 | switch ($name) { |
||
239 | case 'level': |
||
240 | return $match[0] = $level; |
||
241 | break; |
||
242 | case 'date': |
||
243 | return $match[0] = date($date_format); |
||
244 | break; |
||
245 | case 'message': |
||
246 | $replace = []; |
||
247 | foreach ($context as $key => $val) { |
||
248 | if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { |
||
249 | $replace['{'.$key.'}'] = $val; |
||
250 | } else { |
||
251 | $replace['{'.$key.'}'] = json_encode($val); |
||
252 | } |
||
253 | } |
||
254 | |||
255 | return $match[0] = strtr($message, $replace); |
||
256 | break; |
||
257 | case 'context': |
||
258 | if ($sub_context) { |
||
259 | if (array_key_exists($key, $context)) { |
||
260 | if (!is_array($context[$key]) && (!is_object($context[$key]) || method_exists($context[$key], '__toString'))) { |
||
261 | return $match[0] = $context[$key]; |
||
262 | } else { |
||
263 | return $match[0] = json_encode($context[$key]); |
||
264 | } |
||
265 | } |
||
266 | } else { |
||
267 | return $match[0] = json_encode($context); |
||
268 | } |
||
269 | break; |
||
270 | } |
||
271 | }, $format); |
||
272 | |||
273 | return $parsed; |
||
274 | } |
||
275 | } |
||
276 |
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.