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 | * This file is part of the Monolog package. |
||
5 | * |
||
6 | * (c) Jordi Boggiano <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | namespace Yapeal\Log; |
||
12 | |||
13 | use Monolog\Handler\AbstractProcessingHandler; |
||
14 | use Monolog\Logger; |
||
0 ignored issues
–
show
|
|||
15 | |||
16 | /** |
||
17 | * Stores to any stream resource |
||
18 | * |
||
19 | * Can be used to store into php://stderr, remote and local files, etc. |
||
20 | * |
||
21 | * @author Jordi Boggiano <[email protected]> |
||
22 | */ |
||
23 | class StreamHandler extends AbstractProcessingHandler |
||
24 | { |
||
25 | /** |
||
26 | * @param resource|string $stream |
||
27 | * @param int $level The minimum logging level at which this handler will be triggered |
||
28 | * @param bool $bubble Whether the messages that are handled can bubble up the stack or not |
||
29 | * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) |
||
30 | * @param bool $useLocking Try to lock log file before doing any writes |
||
31 | * |
||
32 | * @throws \Exception If a missing directory is not buildable |
||
33 | * @throws \InvalidArgumentException If stream is not a resource or string |
||
34 | */ |
||
35 | public function __construct( |
||
36 | $stream, |
||
37 | int $level = Logger::DEBUG, |
||
38 | bool $bubble = true, |
||
39 | int $filePermission = null, |
||
40 | bool $useLocking = false |
||
41 | ) { |
||
42 | parent::__construct($level, $bubble); |
||
43 | if (is_resource($stream)) { |
||
44 | $this->stream = $stream; |
||
45 | } elseif (is_string($stream)) { |
||
46 | $this->url = $stream; |
||
47 | } else { |
||
48 | throw new \InvalidArgumentException('A stream must either be a resource or a string.'); |
||
49 | } |
||
50 | $this->filePermission = $filePermission; |
||
51 | $this->useLocking = $useLocking; |
||
52 | } |
||
53 | /** |
||
54 | * Closes the handler. |
||
55 | * |
||
56 | * This will be called automatically when the object is destroyed |
||
57 | */ |
||
58 | public function close() |
||
59 | { |
||
60 | if ($this->url && is_resource($this->stream)) { |
||
61 | fclose($this->stream); |
||
62 | } |
||
63 | $this->stream = null; |
||
64 | } |
||
65 | /** |
||
66 | * Return the currently active stream if it is open. |
||
67 | * |
||
68 | * @return resource|null |
||
69 | */ |
||
70 | public function getStream() |
||
71 | { |
||
72 | return $this->stream; |
||
73 | } |
||
74 | /** |
||
75 | * Return the stream URL if it was configured with a URL and not an active resource. |
||
76 | * |
||
77 | * @return string|null |
||
78 | */ |
||
79 | public function getUrl() |
||
80 | { |
||
81 | return $this->url; |
||
82 | } |
||
83 | /** |
||
84 | * Checks whether the given record will be handled by this handler. |
||
85 | * |
||
86 | * This is mostly done for performance reasons, to avoid calling processors for nothing. |
||
87 | * |
||
88 | * Handlers should still check the record levels within handle(), returning false in isHandling() |
||
89 | * is no guarantee that handle() will not be called, and isHandling() might not be called |
||
90 | * for a given record. |
||
91 | * |
||
92 | * @param array $record Partial log record containing only a level key |
||
93 | * |
||
94 | * @return bool |
||
95 | */ |
||
96 | public function isHandling(array $record): bool |
||
97 | { |
||
98 | if ($this->preserve) { |
||
99 | return parent::isHandling($record); |
||
100 | } |
||
101 | return false; |
||
102 | } |
||
103 | /** |
||
104 | * Turn on or off preserving(logging) of messages with this handler. |
||
105 | * |
||
106 | * Allows class to stay registered for messages but be enabled or disabled during runtime. |
||
107 | * |
||
108 | * @param bool $value |
||
109 | * |
||
110 | * @return self Fluent interface. |
||
111 | */ |
||
112 | public function setPreserve(bool $value = true): self |
||
113 | { |
||
114 | $this->preserve = $value; |
||
115 | return $this; |
||
116 | } |
||
117 | /** |
||
118 | * Writes the record down to the log of the implementing handler. |
||
119 | * |
||
120 | * @param array $record |
||
121 | * |
||
122 | * @throws \LogicException |
||
123 | * @throws \UnexpectedValueException |
||
124 | */ |
||
125 | protected function write(array $record) |
||
126 | { |
||
127 | if (!is_resource($this->stream)) { |
||
128 | if (null === $this->url || '' === $this->url) { |
||
129 | throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); |
||
0 ignored issues
–
show
|
|||
130 | } |
||
131 | $this->createDir(); |
||
132 | $this->errorMessage = null; |
||
133 | set_error_handler([$this, 'customErrorHandler']); |
||
134 | $this->stream = fopen($this->url, 'a'); |
||
135 | if (null !== $this->filePermission) { |
||
136 | /** @noinspection PhpUsageOfSilenceOperatorInspection */ |
||
137 | @chmod($this->url, $this->filePermission); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
138 | } |
||
139 | restore_error_handler(); |
||
140 | if (!is_resource($this->stream)) { |
||
141 | $this->stream = null; |
||
142 | $mess = 'The stream or file "%s" could not be opened: ' . $this->errorMessage; |
||
143 | throw new \UnexpectedValueException(sprintf($mess, $this->url)); |
||
144 | } |
||
145 | } |
||
146 | if ($this->useLocking) { |
||
147 | // Ignoring errors here, there's not much we can do about them and no use blocking either. |
||
148 | flock($this->stream, LOCK_EX | LOCK_NB); |
||
149 | } |
||
150 | fwrite($this->stream, (string)$record['formatted']); |
||
151 | if ($this->useLocking) { |
||
152 | flock($this->stream, LOCK_UN); |
||
153 | } |
||
154 | } |
||
155 | /** |
||
156 | * @var int|null $filePermission |
||
157 | */ |
||
158 | protected $filePermission; |
||
159 | /** |
||
160 | * @var resource $stream |
||
161 | */ |
||
162 | protected $stream; |
||
163 | /** |
||
164 | * @var string $url |
||
165 | */ |
||
166 | protected $url; |
||
167 | /** |
||
168 | * @var bool $useLocking |
||
169 | */ |
||
170 | protected $useLocking; |
||
171 | /** |
||
172 | * Tries to create the required directory once. |
||
173 | * |
||
174 | * @throws \UnexpectedValueException |
||
175 | */ |
||
176 | private function createDir() |
||
177 | { |
||
178 | // Do not try to create dir if it has already been tried. |
||
179 | if ($this->dirCreated) { |
||
180 | return; |
||
181 | } |
||
182 | $dir = $this->getDirFromStream($this->url); |
||
183 | if (null !== $dir && !is_dir($dir)) { |
||
184 | $this->errorMessage = null; |
||
185 | set_error_handler([$this, 'customErrorHandler']); |
||
186 | $status = mkdir($dir, 0777, true); |
||
187 | restore_error_handler(); |
||
188 | if (false === $status) { |
||
189 | $mess = 'There is no existing directory at "%s" and its not buildable: ' . $this->errorMessage; |
||
190 | throw new \UnexpectedValueException(sprintf($mess, $dir)); |
||
191 | } |
||
192 | } |
||
193 | $this->dirCreated = true; |
||
194 | } |
||
195 | /** |
||
196 | * @param int $code |
||
197 | * @param string $msg |
||
198 | */ |
||
199 | private function customErrorHandler(int $code, string $msg) |
||
200 | { |
||
201 | $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); |
||
202 | } |
||
203 | /** |
||
204 | * @param string $stream |
||
205 | * |
||
206 | * @return string|null |
||
207 | */ |
||
208 | private function getDirFromStream(string $stream) |
||
209 | { |
||
210 | if (false === strpos($stream, '://')) { |
||
211 | return dirname($stream); |
||
212 | } |
||
213 | if (0 === strpos($stream, 'file://')) { |
||
214 | return dirname(substr($stream, 7)); |
||
215 | } |
||
216 | return null; |
||
217 | } |
||
218 | /** |
||
219 | * @var bool $dirCreated |
||
220 | */ |
||
221 | private $dirCreated; |
||
222 | /** |
||
223 | * @var string $errorMessage |
||
224 | */ |
||
225 | private $errorMessage; |
||
226 | /** |
||
227 | * @var bool $preserve |
||
228 | */ |
||
229 | private $preserve = true; |
||
230 | } |
||
231 |
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: