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; |
||
0 ignored issues
–
show
|
|||
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 |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Adding a
@return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.
Adding a Please refer to the PHP core documentation on constructors. ![]() |
|||
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
case statements should be defined using a colon.
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 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. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
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)) { |
||
0 ignored issues
–
show
The variable
$adapter does not exist. Did you mean $adapters ?
This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name. The variable may have been renamed without also renaming all references. ![]() |
|||
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); |
||
0 ignored issues
–
show
Consider using a different name than the imported variable
$context , or did you forget to import by reference?
It seems like you are assigning to a variable which was imported through a For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope. Change not visible in outer-scope$x = 1;
$callable = function() use ($x) {
$x = 2; // Not visible in outer scope. If you would like this, how
// about using a different variable name than $x?
};
$callable();
var_dump($x); // integer(1)
Change visible in outer-scope$x = 1;
$callable = function() use (&$x) {
$x = 2;
};
$callable();
var_dump($x); // integer(2)
![]() |
|||
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; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
242 | case 'date': |
||
243 | return $match[0] = date($date_format); |
||
244 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
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; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
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 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: