terah /
colourlog
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 declare(strict_types=1); |
||
| 2 | |||
| 3 | namespace Terah\ColourLog; |
||
| 4 | |||
| 5 | use Psr\Log\AbstractLogger; |
||
| 6 | use Psr\Log\LoggerInterface; |
||
| 7 | use Psr\Log\LogLevel; |
||
| 8 | |||
| 9 | class Logger extends AbstractLogger |
||
| 10 | { |
||
| 11 | const BLACK = 'black'; |
||
| 12 | const DARK_GRAY = 'dark_gray'; |
||
| 13 | const BLUE = 'blue'; |
||
| 14 | const LIGHT_BLUE = 'light_blue'; |
||
| 15 | const GREEN = 'green'; |
||
| 16 | const LIGHT_GREEN = 'light_green'; |
||
| 17 | const CYAN = 'cyan'; |
||
| 18 | const LIGHT_CYAN = 'light_cyan'; |
||
| 19 | const RED = 'red'; |
||
| 20 | const LIGHT_RED = 'light_red'; |
||
| 21 | const PURPLE = 'purple'; |
||
| 22 | const LIGHT_PURPLE = 'light_purple'; |
||
| 23 | const BROWN = 'brown'; |
||
| 24 | const YELLOW = 'yellow'; |
||
| 25 | const MAGENTA = 'magenta'; |
||
| 26 | const LIGHT_GRAY = 'light_gray'; |
||
| 27 | const WHITE = 'white'; |
||
| 28 | const DEFAULT = 'default'; |
||
| 29 | const BOLD = 'bold'; |
||
| 30 | |||
| 31 | /** @var resource $resource The file handle */ |
||
| 32 | protected $resource = null; |
||
| 33 | |||
| 34 | /** @var string $level */ |
||
| 35 | protected $level = LogLevel::INFO; |
||
| 36 | |||
| 37 | /** @var bool $closeLocally */ |
||
| 38 | protected $closeLocally = false; |
||
| 39 | |||
| 40 | /** @var bool */ |
||
| 41 | protected $addDate = true; |
||
| 42 | |||
| 43 | /** @var string */ |
||
| 44 | protected $separator = ' | '; |
||
| 45 | |||
| 46 | /** @var \Closure */ |
||
| 47 | protected $formatter = null; |
||
| 48 | |||
| 49 | /** @var string */ |
||
| 50 | protected $lastLogEntry = ''; |
||
| 51 | |||
| 52 | /** @var bool|null */ |
||
| 53 | protected $gzipFile = null; |
||
| 54 | |||
| 55 | /** @var bool */ |
||
| 56 | protected $useLocking = false; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var array $logLevels List of supported levels |
||
| 60 | */ |
||
| 61 | static protected $logLevels = [ |
||
| 62 | LogLevel::EMERGENCY => [1, self::WHITE, self::RED, self::DEFAULT, 'EMERG'], |
||
| 63 | LogLevel::ALERT => [2, self::WHITE, self::YELLOW, self::DEFAULT, 'ALERT'], |
||
| 64 | LogLevel::CRITICAL => [3, self::RED, self::DEFAULT, self::BOLD , 'CRIT'], |
||
| 65 | LogLevel::ERROR => [4, self::RED, self::DEFAULT, self::DEFAULT, 'ERROR'], |
||
| 66 | LogLevel::WARNING => [5, self::YELLOW, self::DEFAULT, self::DEFAULT, 'WARN'], |
||
| 67 | LogLevel::NOTICE => [6, self::CYAN, self::DEFAULT, self::DEFAULT, 'NOTE'], |
||
| 68 | LogLevel::INFO => [7, self::GREEN, self::DEFAULT, self::DEFAULT, 'INFO'], |
||
| 69 | LogLevel::DEBUG => [8, self::LIGHT_GRAY, self::DEFAULT, self::DEFAULT, 'DEBUG'], |
||
| 70 | ]; |
||
| 71 | |||
| 72 | /** |
||
| 73 | * @var array |
||
| 74 | */ |
||
| 75 | static protected $colours = [ |
||
| 76 | 'fore' => [ |
||
| 77 | self::BLACK => '0;30', |
||
| 78 | self::DARK_GRAY => '1;30', |
||
| 79 | self::BLUE => '0;34', |
||
| 80 | self::LIGHT_BLUE => '1;34', |
||
| 81 | self::GREEN => '0;32', |
||
| 82 | self::LIGHT_GREEN => '1;32', |
||
| 83 | self::CYAN => '0;36', |
||
| 84 | self::LIGHT_CYAN => '1;36', |
||
| 85 | self::RED => '0;31', |
||
| 86 | self::LIGHT_RED => '1;31', |
||
| 87 | self::PURPLE => '0;35', |
||
| 88 | self::LIGHT_PURPLE => '1;35', |
||
| 89 | self::BROWN => '0;33', |
||
| 90 | self::YELLOW => '1;33', |
||
| 91 | self::MAGENTA => '0;35', |
||
| 92 | self::LIGHT_GRAY => '0;37', |
||
| 93 | self::WHITE => '1;37', |
||
| 94 | ], |
||
| 95 | 33 | 'back' => [ |
|
| 96 | self::DEFAULT => '49', |
||
| 97 | 33 | self::BLACK => '40', |
|
| 98 | 33 | self::RED => '41', |
|
| 99 | 33 | self::GREEN => '42', |
|
| 100 | 33 | self::YELLOW => '43', |
|
| 101 | 33 | self::BLUE => '44', |
|
| 102 | 33 | self::MAGENTA => '45', |
|
| 103 | self::CYAN => '46', |
||
| 104 | self::LIGHT_GRAY => '47', |
||
| 105 | ], |
||
| 106 | self::BOLD => [], |
||
| 107 | ]; |
||
| 108 | |||
| 109 | /** |
||
| 110 | * @param mixed $resource |
||
| 111 | * @param string $level |
||
| 112 | * @param bool $useLocking |
||
| 113 | * @param bool $gzipFile |
||
| 114 | * @param bool $addDate |
||
| 115 | */ |
||
| 116 | public function __construct($resource, string $level=LogLevel::INFO, bool $useLocking=false, bool $gzipFile=false, bool $addDate=true) |
||
| 117 | { |
||
| 118 | $this->resource = $resource; |
||
| 119 | $this->setLogLevel($level); |
||
| 120 | $this->useLocking = $useLocking; |
||
| 121 | 27 | $this->gzipFile = $gzipFile; |
|
| 122 | $this->addDate = $addDate; |
||
| 123 | } |
||
| 124 | 27 | ||
| 125 | 27 | /** |
|
| 126 | * @param $resource |
||
| 127 | 27 | * @return LoggerInterface |
|
| 128 | 18 | */ |
|
| 129 | 24 | public function setLogFile($resource) : LoggerInterface |
|
| 130 | 16 | { |
|
| 131 | $this->resource = $resource; |
||
| 132 | 27 | ||
| 133 | 18 | return $this; |
|
| 134 | 24 | } |
|
| 135 | 16 | ||
| 136 | /** |
||
| 137 | 27 | * @param string $string |
|
| 138 | 27 | * @param string $foregroundColor |
|
| 139 | * @param string $backgroundColor |
||
| 140 | * @param bool $bold |
||
| 141 | * @return string |
||
| 142 | */ |
||
| 143 | public static function addColour(string $string, string $foregroundColor='', string $backgroundColor='', bool $bold=false) : string |
||
| 144 | { |
||
| 145 | // todo: support bold |
||
| 146 | unset($bold); |
||
| 147 | $coloredString = ''; |
||
| 148 | 27 | // Check if given foreground color found |
|
| 149 | if ( isset(static::$colours['fore'][$foregroundColor]) ) |
||
| 150 | 27 | { |
|
| 151 | $coloredString .= "\033[" . static::$colours['fore'][$foregroundColor] . "m"; |
||
| 152 | } |
||
| 153 | // Check if given background color found |
||
| 154 | if ( isset(static::$colours['back'][$backgroundColor]) ) |
||
| 155 | { |
||
| 156 | $coloredString .= "\033[" . static::$colours['back'][$backgroundColor] . "m"; |
||
| 157 | 33 | } |
|
| 158 | // Add string and end coloring |
||
| 159 | 33 | $coloredString .= $string . "\033[0m"; |
|
| 160 | 22 | ||
| 161 | return $coloredString; |
||
| 162 | } |
||
| 163 | 33 | ||
| 164 | 33 | /** |
|
| 165 | * @param string $string |
||
| 166 | * @param string $foregroundColor |
||
| 167 | * @param string $backgroundColor |
||
| 168 | * @param bool $bold |
||
| 169 | * @return string |
||
| 170 | */ |
||
| 171 | public function colourize(string $string, string $foregroundColor='', string $backgroundColor='', bool $bold=false) : string |
||
| 172 | { |
||
| 173 | return static::addColour($string, $foregroundColor, $backgroundColor, $bold); |
||
| 174 | } |
||
| 175 | |||
| 176 | /** |
||
| 177 | * @param string $level Ignore logging attempts at a level less the $level |
||
| 178 | * @return LoggerInterface |
||
| 179 | 3 | */ |
|
| 180 | public function setLogLevel(string $level) : LoggerInterface |
||
| 181 | 3 | { |
|
| 182 | 3 | if ( ! isset(static::$logLevels[$level]) ) |
|
| 183 | { |
||
| 184 | throw new \InvalidArgumentException("Log level is invalid"); |
||
| 185 | } |
||
| 186 | $this->level = static::$logLevels[$level][0]; |
||
| 187 | |||
| 188 | return $this; |
||
| 189 | } |
||
| 190 | |||
| 191 | /** |
||
| 192 | * @return LoggerInterface |
||
| 193 | */ |
||
| 194 | public function lock() : LoggerInterface |
||
| 195 | { |
||
| 196 | $this->useLocking = true; |
||
| 197 | |||
| 198 | return $this; |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * @return LoggerInterface |
||
| 203 | */ |
||
| 204 | public function gzipped() : LoggerInterface |
||
| 205 | 24 | { |
|
| 206 | $this->gzipFile = true; |
||
| 207 | 24 | ||
| 208 | 24 | return $this; |
|
| 209 | 24 | } |
|
| 210 | 16 | ||
| 211 | 18 | /** |
|
| 212 | * @param callable $fnFormatter |
||
| 213 | 24 | * |
|
| 214 | 16 | * @return LoggerInterface |
|
| 215 | */ |
||
| 216 | public function formatter(callable $fnFormatter) : LoggerInterface |
||
| 217 | { |
||
| 218 | $this->formatter = $fnFormatter; |
||
|
0 ignored issues
–
show
|
|||
| 219 | 24 | ||
| 220 | return $this; |
||
| 221 | 24 | } |
|
| 222 | 24 | ||
| 223 | 24 | /** |
|
| 224 | * Log messages to resource |
||
| 225 | * |
||
| 226 | * @param mixed $level The level of the log message |
||
| 227 | * @param string|object $message If an object is passed it must implement __toString() |
||
| 228 | * @param array $context Placeholders to be substituted in the message |
||
| 229 | * |
||
| 230 | * @return LoggerInterface |
||
| 231 | */ |
||
| 232 | 24 | public function log($level, $message, array $context=[]) : LoggerInterface |
|
| 233 | { |
||
| 234 | $level = isset(static::$logLevels[$level]) ? $level : LogLevel::INFO; |
||
| 235 | 24 | list($logLevel, $fore, $back, $style) = static::$logLevels[$level]; |
|
| 236 | 24 | unset($style); |
|
| 237 | 24 | if ( $logLevel > $this->level ) |
|
| 238 | 24 | { |
|
| 239 | 24 | return $this; |
|
| 240 | 24 | } |
|
| 241 | if ( is_callable($this->formatter) ) |
||
| 242 | { |
||
| 243 | $message = $this->formatter->__invoke(static::$logLevels[$level][4], $message, $context); |
||
| 244 | } |
||
| 245 | else |
||
| 246 | { |
||
| 247 | $message = $this->formatMessage($level, $message, $context); |
||
|
0 ignored issues
–
show
It seems like
$message can also be of type object; however, Terah\ColourLog\Logger::formatMessage() does only seem to accept string, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 248 | 27 | } |
|
| 249 | $this->lastLogEntry = $message; |
||
| 250 | 27 | $this->write($this->colourize($message, $fore, $back) . PHP_EOL); |
|
| 251 | 27 | ||
| 252 | 18 | return $this; |
|
| 253 | } |
||
| 254 | |||
| 255 | 27 | /** |
|
| 256 | 27 | * @param string $style |
|
| 257 | 18 | * @param string $message |
|
| 258 | * @return string |
||
| 259 | */ |
||
| 260 | 27 | public static function style(string $style, string $message) : string |
|
| 261 | { |
||
| 262 | $style = isset(static::$logLevels[$style]) ? $style : LogLevel::INFO; |
||
| 263 | list($logLevel, $fore, $back, $style) = static::$logLevels[$style]; |
||
| 264 | unset($logLevel, $style); |
||
| 265 | |||
| 266 | 27 | return static::addColour($message, $fore, $back); |
|
| 267 | } |
||
| 268 | 27 | ||
| 269 | 18 | /** |
|
| 270 | 27 | * @param string $level |
|
| 271 | * @param string $message |
||
| 272 | * @param array $context |
||
| 273 | * @return string |
||
| 274 | */ |
||
| 275 | protected function formatMessage(string $level, string $message, array $context=[]) : string |
||
| 276 | { |
||
| 277 | # Handle objects implementing __toString |
||
| 278 | $message = (string) $message; |
||
| 279 | $message .= empty($context) ? '' : PHP_EOL . json_encode($context, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); |
||
| 280 | $data = $this->addDate ? ['date' => date('Y-m-d H:i:s')] : []; |
||
| 281 | $data['level'] = strtoupper(str_pad(static::$logLevels[$level][4], 5, ' ', STR_PAD_RIGHT)); |
||
| 282 | $data['message'] = $message; |
||
| 283 | |||
| 284 | return implode($this->separator, $data); |
||
| 285 | } |
||
| 286 | |||
| 287 | /** |
||
| 288 | * Write the content to the stream |
||
| 289 | * |
||
| 290 | * @param string $content |
||
| 291 | */ |
||
| 292 | public function write(string $content) |
||
| 293 | { |
||
| 294 | $resource = $this->getResource(); |
||
| 295 | if ( $this->useLocking ) |
||
| 296 | { |
||
| 297 | flock($resource, LOCK_EX); |
||
| 298 | } |
||
| 299 | gzwrite($resource, $content); |
||
| 300 | if ( $this->useLocking ) |
||
| 301 | { |
||
| 302 | flock($resource, LOCK_UN); |
||
| 303 | } |
||
| 304 | } |
||
| 305 | |||
| 306 | /** |
||
| 307 | * @return mixed|resource |
||
| 308 | * @throws \Exception |
||
| 309 | */ |
||
| 310 | protected function getResource() |
||
| 311 | { |
||
| 312 | if ( is_resource($this->resource) ) |
||
| 313 | { |
||
| 314 | return $this->resource; |
||
| 315 | } |
||
| 316 | $fileName = $this->resource; |
||
| 317 | $this->closeLocally = true; |
||
| 318 | $this->resource = $this->openResource(); |
||
| 319 | if ( ! is_resource($this->resource) ) |
||
| 320 | { |
||
| 321 | throw new \Exception("The resource ({$fileName}) could not be opened"); |
||
| 322 | } |
||
| 323 | |||
| 324 | return $this->resource; |
||
| 325 | } |
||
| 326 | |||
| 327 | /** |
||
| 328 | * @return string |
||
| 329 | */ |
||
| 330 | public function getLastLogEntry() : string |
||
| 331 | { |
||
| 332 | return $this->lastLogEntry; |
||
| 333 | } |
||
| 334 | |||
| 335 | /** |
||
| 336 | * @return resource |
||
| 337 | */ |
||
| 338 | protected function openResource() |
||
| 339 | { |
||
| 340 | if ( $this->gzipFile ) |
||
| 341 | { |
||
| 342 | return gzopen($this->resource, 'a'); |
||
| 343 | } |
||
| 344 | |||
| 345 | return fopen($this->resource, 'a'); |
||
| 346 | } |
||
| 347 | |||
| 348 | public function __destruct() |
||
| 349 | { |
||
| 350 | if ($this->closeLocally) |
||
| 351 | { |
||
| 352 | gzclose($this->getResource()); |
||
| 353 | } |
||
| 354 | } |
||
| 355 | } |
||
| 356 | |||
| 357 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..