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 | /** |
||
3 | * Created by PhpStorm. |
||
4 | * User: lenovo |
||
5 | * Date: 6/18/2018 |
||
6 | * Time: 1:44 PM |
||
7 | */ |
||
8 | |||
9 | namespace TimSDK\Foundation\Log; |
||
10 | |||
11 | use TimSDK\Support\Arr; |
||
12 | use Psr\Log\LoggerInterface; |
||
13 | use Monolog\Logger as Monolog; |
||
14 | use Monolog\Handler\SyslogHandler; |
||
15 | use Monolog\Handler\StreamHandler; |
||
16 | use Monolog\Formatter\LineFormatter; |
||
17 | use Monolog\Handler\ErrorLogHandler; |
||
18 | use Monolog\Handler\HandlerInterface; |
||
19 | use TimSDK\Container\ServiceContainer; |
||
20 | use Monolog\Handler\RotatingFileHandler; |
||
21 | use Monolog\Handler\SlackWebhookHandler; |
||
22 | |||
23 | class LogManager implements LoggerInterface |
||
24 | { |
||
25 | /** |
||
26 | * @var \TimSDK\Container\ServiceContainer $app |
||
27 | */ |
||
28 | protected $app; |
||
29 | |||
30 | /** |
||
31 | * The array of resolved channels. |
||
32 | * |
||
33 | * @var array |
||
34 | */ |
||
35 | protected $channels = []; |
||
36 | |||
37 | /** |
||
38 | * The registered custom driver creators. |
||
39 | * |
||
40 | * @var array |
||
41 | */ |
||
42 | protected $customCreators = []; |
||
43 | |||
44 | /** |
||
45 | * The Log levels. |
||
46 | * |
||
47 | * @var array |
||
48 | */ |
||
49 | protected $levels = [ |
||
50 | 'debug' => Monolog::DEBUG, |
||
51 | 'info' => Monolog::INFO, |
||
52 | 'notice' => Monolog::NOTICE, |
||
53 | 'warning' => Monolog::WARNING, |
||
54 | 'error' => Monolog::ERROR, |
||
55 | 'critical' => Monolog::CRITICAL, |
||
56 | 'alert' => Monolog::ALERT, |
||
57 | 'emergency' => Monolog::EMERGENCY, |
||
58 | ]; |
||
59 | |||
60 | /** |
||
61 | * LogManager constructor. |
||
62 | * |
||
63 | * @param \TimSDK\Container\ServiceContainer $app |
||
64 | */ |
||
65 | 19 | public function __construct(ServiceContainer $app) |
|
66 | { |
||
67 | 19 | $this->app = $app; |
|
68 | 19 | } |
|
69 | |||
70 | /** |
||
71 | * Create a new, on-demand aggregate logger instance. |
||
72 | * |
||
73 | * @param array $channels |
||
74 | * @param string|null $channel |
||
75 | * |
||
76 | * @return \Psr\Log\LoggerInterface |
||
77 | */ |
||
78 | 1 | public function stack(array $channels, $channel = null) |
|
79 | { |
||
80 | 1 | return $this->createStackDriver(compact('channels', 'channel')); |
|
81 | } |
||
82 | |||
83 | /** |
||
84 | * Get a log channel instance. |
||
85 | * |
||
86 | * @param string|null $channel |
||
87 | * |
||
88 | * @return mixed |
||
89 | */ |
||
90 | 2 | public function channel($channel = null) |
|
91 | { |
||
92 | 2 | return $this->get($channel); |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * Get a log driver instance. |
||
97 | * |
||
98 | * @param null $driver |
||
99 | * @return \Psr\Log\LoggerInterface |
||
100 | */ |
||
101 | 15 | public function driver($driver = null) |
|
102 | { |
||
103 | 15 | return $this->get(isset($driver) ? $driver : $this->getDefaultDriver()); |
|
104 | } |
||
105 | |||
106 | /** |
||
107 | * Attempt to get the log from the local cache. |
||
108 | * |
||
109 | * @param string $name |
||
110 | * |
||
111 | * @return \Psr\Log\LoggerInterface |
||
112 | */ |
||
113 | 16 | protected function get($name) |
|
114 | { |
||
115 | try { |
||
116 | 16 | return Arr::get($this->channels, $name, $this->channels[$name] = $this->resolve($name)); |
|
117 | } |
||
118 | // 兼容低于PHP7.0,不使用\Throwable |
||
119 | 3 | catch (\InvalidArgumentException $e) { |
|
120 | 3 | $logger = $this->createEmergencyLogger(); |
|
121 | 3 | $logger->emergency('Unable to create configured logger. Using emergency logger.', [ |
|
122 | 3 | 'exception' => $e, |
|
123 | ]); |
||
124 | |||
125 | 3 | return $logger; |
|
126 | } |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Resolve the given log instance by name. |
||
131 | * |
||
132 | * @param string $name |
||
133 | * |
||
134 | * @return \Psr\Log\LoggerInterface |
||
135 | * |
||
136 | * @throws \InvalidArgumentException |
||
137 | */ |
||
138 | 16 | protected function resolve($name) |
|
139 | { |
||
140 | 16 | $config = $this->app['config']->get(\sprintf('log.channels.%s', $name)); |
|
141 | 16 | if (is_null($config)) { |
|
142 | 2 | throw new \InvalidArgumentException(\sprintf('Log [%s] is not defined.', $name)); |
|
143 | } |
||
144 | 14 | if (isset($this->customCreators[$config['driver']])) { |
|
145 | 1 | return $this->callCustomCreator($config); |
|
146 | } |
||
147 | 13 | $driverMethod = 'create' . ucfirst($config['driver']) . 'Driver'; |
|
148 | 13 | if (method_exists($this, $driverMethod)) { |
|
149 | 12 | return $this->{$driverMethod}($config); |
|
150 | } |
||
151 | 1 | throw new \InvalidArgumentException(\sprintf('Driver [%s] is not supported.', $config['driver'])); |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Create an emergency log handler to avoid white screens of death. |
||
156 | * |
||
157 | * @return \Monolog\Logger |
||
158 | */ |
||
159 | 1 | protected function createEmergencyLogger() |
|
160 | { |
||
161 | 1 | return new Monolog('TimSDK', $this->prepareHandlers([ |
|
162 | 1 | new StreamHandler( |
|
163 | 1 | \sys_get_temp_dir() . '/tim-sdk/tim-sdk.log', $this->level(['level' => 'debug']) |
|
164 | ), |
||
165 | ])); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Call a custom driver creator. |
||
170 | * |
||
171 | * @param array $config |
||
172 | * |
||
173 | * @return mixed |
||
174 | */ |
||
175 | 1 | protected function callCustomCreator(array $config) |
|
176 | { |
||
177 | 1 | return $this->customCreators[$config['driver']]($this->app, $config); |
|
178 | } |
||
179 | |||
180 | /** |
||
181 | * Create an aggregate log driver instance. |
||
182 | * |
||
183 | * @param array $config |
||
184 | * |
||
185 | * @return \Monolog\Logger |
||
186 | */ |
||
187 | 2 | protected function createStackDriver(array $config) |
|
188 | { |
||
189 | 2 | $handlers = []; |
|
190 | 2 | foreach (Arr::get($config, 'channels', []) as $channel) { |
|
191 | 2 | $handlers = \array_merge($handlers, $this->channel($channel)->getHandlers()); |
|
0 ignored issues
–
show
|
|||
192 | } |
||
193 | |||
194 | 2 | return new Monolog($this->parseChannel($config), $handlers); |
|
195 | } |
||
196 | |||
197 | /** |
||
198 | * Create an instance of the single file log driver. |
||
199 | * |
||
200 | * @param array $config |
||
201 | * |
||
202 | * @return \Psr\Log\LoggerInterface |
||
203 | * |
||
204 | * @throws \InvalidArgumentException |
||
205 | */ |
||
206 | 5 | View Code Duplication | protected function createSingleDriver(array $config) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
207 | { |
||
208 | 5 | if (!isset($config['path'])) { |
|
209 | 1 | throw new \InvalidArgumentException('Invalid log file path.'); |
|
210 | } |
||
211 | |||
212 | 4 | return new Monolog($this->parseChannel($config), [ |
|
213 | 4 | $this->prepareHandler( |
|
214 | 4 | new StreamHandler($config['path'], $this->level($config)) |
|
215 | ), |
||
216 | ]); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Create an instance of the daily file log driver. |
||
221 | * |
||
222 | * @param array $config |
||
223 | * |
||
224 | * @return \Psr\Log\LoggerInterface |
||
225 | * |
||
226 | * @throws \InvalidArgumentException |
||
227 | */ |
||
228 | 2 | View Code Duplication | protected function createDailyDriver(array $config) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
229 | { |
||
230 | 2 | if (!isset($config['path'])) { |
|
231 | 1 | throw new \InvalidArgumentException('Invalid log file path.'); |
|
232 | } |
||
233 | |||
234 | 1 | return new Monolog($this->parseChannel($config), [ |
|
235 | 1 | $this->prepareHandler(new RotatingFileHandler( |
|
236 | 1 | $config['path'], Arr::get($config, 'days', 7), $this->level($config) |
|
237 | )), |
||
238 | ]); |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Create an instance of the Slack log driver. |
||
243 | * |
||
244 | * @param array $config |
||
245 | * |
||
246 | * @return \Psr\Log\LoggerInterface |
||
247 | */ |
||
248 | 1 | protected function createSlackDriver(array $config) |
|
249 | { |
||
250 | 1 | return new Monolog($this->parseChannel($config), [ |
|
251 | 1 | $this->prepareHandler(new SlackWebhookHandler( |
|
252 | 1 | $config['url'], |
|
253 | 1 | Arr::get($config, 'channel', null), |
|
254 | 1 | Arr::get($config ,'username', 'TimSDK'), |
|
255 | 1 | Arr::get($config ,'attachment', true), |
|
256 | 1 | Arr::get($config ,'emoji', ':boom:'), |
|
257 | 1 | Arr::get($config ,'short', false), |
|
258 | 1 | Arr::get($config ,'context', true), |
|
259 | 1 | $this->level($config) |
|
260 | )), |
||
261 | ]); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Create an instance of the syslog log driver. |
||
266 | * |
||
267 | * @param array $config |
||
268 | * |
||
269 | * @return \Psr\Log\LoggerInterface |
||
270 | */ |
||
271 | 1 | View Code Duplication | protected function createSyslogDriver(array $config) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
272 | { |
||
273 | 1 | return new Monolog($this->parseChannel($config), [ |
|
274 | 1 | $this->prepareHandler(new SyslogHandler( |
|
275 | 1 | 'TimSDK', Arr::get($config, 'facility', LOG_USER), $this->level($config)) |
|
276 | ), |
||
277 | ]); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Create an instance of the "error log" log driver. |
||
282 | * |
||
283 | * @param array $config |
||
284 | * |
||
285 | * @return \Psr\Log\LoggerInterface |
||
286 | */ |
||
287 | 7 | View Code Duplication | protected function createErrorlogDriver(array $config) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
288 | { |
||
289 | 7 | return new Monolog($this->parseChannel($config), [ |
|
290 | 7 | $this->prepareHandler(new ErrorLogHandler( |
|
291 | 7 | Arr::get($config, 'type', ErrorLogHandler::OPERATING_SYSTEM), $this->level($config)) |
|
292 | ), |
||
293 | ]); |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Prepare the handlers for usage by Monolog. |
||
298 | * |
||
299 | * @param array $handlers |
||
300 | * |
||
301 | * @return array |
||
302 | */ |
||
303 | 1 | protected function prepareHandlers(array $handlers) |
|
304 | { |
||
305 | 1 | foreach ($handlers as $key => $handler) { |
|
306 | 1 | $handlers[$key] = $this->prepareHandler($handler); |
|
307 | } |
||
308 | |||
309 | 1 | return $handlers; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * Prepare the handler for usage by Monolog. |
||
314 | * |
||
315 | * @param \Monolog\Handler\HandlerInterface $handler |
||
316 | * |
||
317 | * @return \Monolog\Handler\HandlerInterface |
||
318 | */ |
||
319 | 10 | protected function prepareHandler(HandlerInterface $handler) |
|
320 | { |
||
321 | 10 | return $handler->setFormatter($this->formatter()); |
|
322 | } |
||
323 | |||
324 | /** |
||
325 | * Get a Monolog formatter instance. |
||
326 | * |
||
327 | * @return \Monolog\Formatter\FormatterInterface |
||
328 | */ |
||
329 | 10 | protected function formatter() |
|
330 | { |
||
331 | 10 | $formatter = new LineFormatter(null, null, true, true); |
|
332 | 10 | $formatter->includeStacktraces(); |
|
333 | |||
334 | 10 | return $formatter; |
|
335 | } |
||
336 | |||
337 | /** |
||
338 | * Extract the log channel from the given configuration. |
||
339 | * |
||
340 | * @param array $config |
||
341 | * |
||
342 | * @return string |
||
343 | */ |
||
344 | 9 | protected function parseChannel(array $config) |
|
345 | { |
||
346 | 9 | return Arr::get($config, 'name', $this->getDefaultDriver()); |
|
347 | } |
||
348 | |||
349 | /** |
||
350 | * Parse the string level into a Monolog constant. |
||
351 | * |
||
352 | * @param array $config |
||
353 | * |
||
354 | * @return int |
||
355 | * |
||
356 | * @throws \InvalidArgumentException |
||
357 | */ |
||
358 | 11 | protected function level(array $config) |
|
359 | { |
||
360 | 11 | $level = Arr::get($config, 'level', 'debug'); |
|
361 | |||
362 | 11 | if (isset($this->levels[$level])) { |
|
363 | 10 | return $this->levels[$level]; |
|
364 | } |
||
365 | |||
366 | 1 | throw new \InvalidArgumentException('Invalid log level.'); |
|
367 | } |
||
368 | |||
369 | /** |
||
370 | * Get the default log driver name. |
||
371 | * |
||
372 | * @return string |
||
373 | */ |
||
374 | 13 | public function getDefaultDriver() |
|
375 | { |
||
376 | 13 | return $this->app['config']['log.default']; |
|
377 | } |
||
378 | |||
379 | /** |
||
380 | * Set the default log driver name. |
||
381 | * |
||
382 | * @param string $name |
||
383 | * @return LogManager |
||
384 | */ |
||
385 | 1 | public function setDefaultDriver($name) |
|
386 | { |
||
387 | 1 | $this->app['config']['log.default'] = $name; |
|
388 | |||
389 | 1 | return $this; |
|
390 | } |
||
391 | |||
392 | /** |
||
393 | * Add more channels |
||
394 | * |
||
395 | * @param array $channels |
||
396 | * @return LogManager |
||
397 | */ |
||
398 | public function addChannels(array $channels) |
||
399 | { |
||
400 | $original = $this->app['config']->get('log.channels', []); |
||
401 | |||
402 | if (is_array($channels)) { |
||
403 | $this->app['config']->set('log.channels', array_merge($original, $channels)); |
||
404 | } |
||
405 | |||
406 | return $this; |
||
407 | } |
||
408 | |||
409 | /** |
||
410 | * Register a custom driver creator Closure. |
||
411 | * |
||
412 | * @param string $driver |
||
413 | * @param \Closure $callback |
||
414 | * |
||
415 | * @return $this |
||
416 | */ |
||
417 | 1 | public function extend($driver, \Closure $callback) |
|
418 | { |
||
419 | 1 | $this->customCreators[$driver] = $callback->bindTo($this, $this); |
|
420 | |||
421 | 1 | return $this; |
|
422 | } |
||
423 | |||
424 | /** |
||
425 | * System is unusable. |
||
426 | * |
||
427 | * @param string $message |
||
428 | * @param array $context |
||
429 | * |
||
430 | * @return mixed |
||
431 | */ |
||
432 | 1 | public function emergency($message, array $context = []) |
|
433 | { |
||
434 | 1 | return $this->log(__FUNCTION__, $message, $context); |
|
435 | } |
||
436 | |||
437 | /** |
||
438 | * Action must be taken immediately. |
||
439 | * |
||
440 | * Example: Entire website down, database unavailable, etc. This should |
||
441 | * trigger the SMS alerts and wake you up. |
||
442 | * |
||
443 | * @param string $message |
||
444 | * @param array $context |
||
445 | * |
||
446 | * @return void |
||
447 | */ |
||
448 | 1 | public function alert($message, array $context = []) |
|
449 | { |
||
450 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
451 | 1 | } |
|
452 | |||
453 | /** |
||
454 | * Critical conditions. |
||
455 | * |
||
456 | * Example: Application component unavailable, unexpected exception. |
||
457 | * |
||
458 | * @param string $message |
||
459 | * @param array $context |
||
460 | * |
||
461 | * @return void |
||
462 | */ |
||
463 | 1 | public function critical($message, array $context = []) |
|
464 | { |
||
465 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
466 | 1 | } |
|
467 | |||
468 | /** |
||
469 | * Runtime errors that do not require immediate action but should typically |
||
470 | * be logged and monitored. |
||
471 | * |
||
472 | * @param string $message |
||
473 | * @param array $context |
||
474 | * |
||
475 | * @return void |
||
476 | */ |
||
477 | 1 | public function error($message, array $context = []) |
|
478 | { |
||
479 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
480 | 1 | } |
|
481 | |||
482 | /** |
||
483 | * Exceptional occurrences that are not errors. |
||
484 | * |
||
485 | * Example: Use of deprecated APIs, poor use of an API, undesirable things |
||
486 | * that are not necessarily wrong. |
||
487 | * |
||
488 | * @param string $message |
||
489 | * @param array $context |
||
490 | * |
||
491 | * @return void |
||
492 | */ |
||
493 | 1 | public function warning($message, array $context = []) |
|
494 | { |
||
495 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
496 | 1 | } |
|
497 | |||
498 | /** |
||
499 | * Normal but significant events. |
||
500 | * |
||
501 | * @param string $message |
||
502 | * @param array $context |
||
503 | * |
||
504 | * @return void |
||
505 | */ |
||
506 | 1 | public function notice($message, array $context = []) |
|
507 | { |
||
508 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
509 | 1 | } |
|
510 | |||
511 | /** |
||
512 | * Interesting events. |
||
513 | * |
||
514 | * Example: User logs in, SQL logs. |
||
515 | * |
||
516 | * @param string $message |
||
517 | * @param array $context |
||
518 | * |
||
519 | * @return void |
||
520 | */ |
||
521 | 1 | public function info($message, array $context = []) |
|
522 | { |
||
523 | 1 | $this->log(__FUNCTION__, $message, $context); |
|
524 | 1 | } |
|
525 | |||
526 | /** |
||
527 | * Detailed debug information. |
||
528 | * |
||
529 | * @param string $message |
||
530 | * @param array $context |
||
531 | * |
||
532 | * @return void |
||
533 | */ |
||
534 | 8 | public function debug($message, array $context = []) |
|
535 | { |
||
536 | 8 | $this->log(__FUNCTION__, $message, $context); |
|
537 | 8 | } |
|
538 | |||
539 | /** |
||
540 | * Logs with an arbitrary level. |
||
541 | * |
||
542 | * @param mixed $level |
||
543 | * @param string $message |
||
544 | * @param array $context |
||
545 | * |
||
546 | * @return void |
||
547 | */ |
||
548 | 9 | public function log($level, $message, array $context = []) |
|
549 | { |
||
550 | 9 | $this->driver()->log($level, $message, $context); |
|
551 | 9 | } |
|
552 | |||
553 | /** |
||
554 | * Dynamically call the default driver instance. |
||
555 | * |
||
556 | * @param string $method |
||
557 | * @param array $parameters |
||
558 | * |
||
559 | * @return mixed |
||
560 | */ |
||
561 | 1 | public function __call($method, $parameters) |
|
562 | { |
||
563 | // return $this->driver()->$method(...$parameters); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
80% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
564 | 1 | return call_user_func_array([$this->driver(), $method], $parameters); |
|
565 | } |
||
566 | } |
||
567 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: