YetiForceCompany /
YetiForceCRM
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.
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Logger files. |
||
| 4 | * |
||
| 5 | * @package App |
||
| 6 | * |
||
| 7 | * @copyright YetiForce S.A. |
||
| 8 | * @license YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com) |
||
| 9 | * @author Mariusz Krzaczkowski <[email protected]> |
||
| 10 | */ |
||
| 11 | |||
| 12 | namespace App; |
||
| 13 | |||
| 14 | use yii\log\Logger; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * Logger class. |
||
| 18 | */ |
||
| 19 | class Log extends Logger |
||
| 20 | { |
||
| 21 | public static $logToConsole; |
||
| 22 | public static $logToFile; |
||
| 23 | public static $logToProfile; |
||
| 24 | public $logToLevels = 0; |
||
| 25 | /** |
||
| 26 | * Column mapping by table for logs owasp. |
||
| 27 | * |
||
| 28 | * @var array |
||
| 29 | */ |
||
| 30 | public static $owaspColumnMapping = [ |
||
| 31 | 'access_for_admin' => ['date', 'username', 'ip', 'module', 'url', 'agent', 'request', 'referer'], |
||
| 32 | 'access_for_api' => ['date', 'username', 'ip', 'url', 'agent', 'request'], |
||
| 33 | 'access_for_user' => ['date', 'username', 'ip', 'module', 'url', 'agent', 'request', 'referer'], |
||
| 34 | 'access_to_record' => ['date', 'username', 'ip', 'module', 'record', 'url', 'agent', 'request', 'referer'], |
||
| 35 | 'csrf' => ['date', 'username', 'ip', 'referer', 'url', 'agent'], |
||
| 36 | ]; |
||
| 37 | /** |
||
| 38 | * Column mapping by table for logs viewer. |
||
| 39 | * |
||
| 40 | * @var array |
||
| 41 | */ |
||
| 42 | public static $logsViewerColumnMapping = [ |
||
| 43 | 'magento' => [ |
||
| 44 | 'label' => 'LBL_MAGENTO', |
||
| 45 | 6388 | 'labelModule' => 'Settings:Magento', |
|
| 46 | 'table' => 'l_#__magento', |
||
| 47 | 6388 | 'icon' => 'yfi-magento', |
|
| 48 | 6388 | 'columns' => [ |
|
| 49 | 6388 | 'time' => ['type' => 'DateTime', 'label' => 'LBL_TIME'], |
|
| 50 | 'category' => ['type' => 'Text', 'label' => 'LBL_CATEGORY'], |
||
| 51 | 6388 | 'message' => ['type' => 'Text', 'label' => 'LBL_MESSAGE'], |
|
| 52 | 'code' => ['type' => 'Text', 'label' => 'LBL_CODE'], |
||
| 53 | 'trace' => ['type' => 'Text', 'label' => 'LBL_BACKTRACE'], |
||
| 54 | 6388 | ], |
|
| 55 | 6388 | 'filter' => [ |
|
| 56 | 116 | 'time' => 'DateTimeRange', |
|
| 57 | 'category' => 'Text', |
||
| 58 | 6388 | 'message' => 'Text', |
|
| 59 | 'code' => 'Text', |
||
| 60 | 'trace' => 'Text', |
||
| 61 | ], |
||
| 62 | ], |
||
| 63 | 'wapro' => [ |
||
| 64 | 'label' => 'LBL_WAPRO_ERP', |
||
| 65 | 'labelModule' => 'Settings:Wapro', |
||
| 66 | 'table' => 'l_#__wapro', |
||
| 67 | 'icon' => 'fab fa-connectdevelop', |
||
| 68 | 5890 | 'columns' => [ |
|
| 69 | 'time' => ['type' => 'DateTime', 'label' => 'LBL_TIME'], |
||
| 70 | 5890 | 'category' => ['type' => 'Text', 'label' => 'LBL_CATEGORY'], |
|
| 71 | 5890 | 'message' => ['type' => 'Text', 'label' => 'LBL_MESSAGE'], |
|
| 72 | 'error' => ['type' => 'Text', 'label' => 'LBL_CODE'], |
||
| 73 | 5890 | 'trace' => ['type' => 'Text', 'label' => 'LBL_BACKTRACE'], |
|
| 74 | ], |
||
| 75 | 'filter' => [ |
||
| 76 | 'time' => 'DateTimeRange', |
||
| 77 | 'category' => 'Text', |
||
| 78 | 'message' => 'Text', |
||
| 79 | 'code' => 'Text', |
||
| 80 | 'trace' => 'Text', |
||
| 81 | ], |
||
| 82 | ], |
||
| 83 | 7 | 'switchUsers' => [ |
|
| 84 | 'label' => 'LBL_SWITCH_USERS', |
||
| 85 | 7 | 'labelModule' => 'Settings:Users', |
|
| 86 | 7 | 'table' => 'l_#__switch_users', |
|
| 87 | 'icon' => 'yfi-users', |
||
| 88 | 7 | 'columns' => [ |
|
| 89 | 'date' => ['type' => 'DateTime', 'label' => 'LBL_TIME'], |
||
| 90 | 'status' => ['type' => 'Text', 'label' => 'LBL_STATUS'], |
||
| 91 | 'busername' => ['type' => 'Text', 'label' => 'LBL_BASE_USER'], |
||
| 92 | 'dusername' => ['type' => 'Text', 'label' => 'LBL_DEST_USER'], |
||
| 93 | 'ip' => ['type' => 'Text', 'label' => 'LBL_IP_ADDRESS'], |
||
| 94 | 'agent' => ['type' => 'Text', 'label' => 'LBL_USER_AGENT'], |
||
| 95 | ], |
||
| 96 | 'filter' => [ |
||
| 97 | 'date' => 'DateTimeRange', |
||
| 98 | 7 | 'busername' => 'Text', |
|
| 99 | 'dusername' => 'Text', |
||
| 100 | 7 | 'ip' => 'Text', |
|
| 101 | 7 | 'agent' => 'Text', |
|
| 102 | ], |
||
| 103 | 7 | ], |
|
| 104 | 'batchMethod' => [ |
||
| 105 | 'label' => 'LBL_BATCH_METHODS', |
||
| 106 | 'labelModule' => 'Settings:CronTasks', |
||
| 107 | 'table' => 'l_#__batchmethod', |
||
| 108 | 'icon' => 'fas fa-swatchbook', |
||
| 109 | 'columns' => [ |
||
| 110 | 'date' => ['type' => 'DateTime', 'label' => 'LBL_TIME'], |
||
| 111 | 'method' => ['type' => 'Text', 'label' => 'LBL_BATCH_NAME'], |
||
| 112 | 'message' => ['type' => 'Text', 'label' => 'LBL_ERROR_MASAGE'], |
||
| 113 | 22 | 'userid' => ['type' => 'Owner', 'label' => 'LBL_OWNER'], |
|
| 114 | 'params' => ['type' => 'Text', 'label' => 'LBL_PARAMS'], |
||
| 115 | 22 | ], |
|
| 116 | 22 | 'filter' => [ |
|
| 117 | 'date' => 'DateTimeRange', |
||
| 118 | 'method' => 'Text', |
||
| 119 | 'message' => 'Text', |
||
| 120 | 'params' => 'Text', |
||
| 121 | ], |
||
| 122 | ], |
||
| 123 | 'mail' => [ |
||
| 124 | 'label' => 'LBL_MAILS_NOT_SENT', |
||
| 125 | 'labelModule' => 'Settings:Log', |
||
| 126 | 'table' => 'l_#__mail', |
||
| 127 | 'icon' => 'adminIcon-mail-queue', |
||
| 128 | 'columns' => [ |
||
| 129 | 'date' => ['type' => 'DateTime', 'label' => 'LBL_TIME'], |
||
| 130 | 'subject' => ['type' => 'Text', 'label' => 'LBL_SUBJECT'], |
||
| 131 | 'from' => ['type' => 'Text', 'label' => 'LBL_FROM'], |
||
| 132 | 'to' => ['type' => 'Text', 'label' => 'LBL_TO'], |
||
| 133 | 'owner' => ['type' => 'Owner', 'label' => 'LBL_OWNER'], |
||
| 134 | ], |
||
| 135 | 'filter' => [ |
||
| 136 | 'date' => 'DateTimeRange', |
||
| 137 | 'subject' => 'Text', |
||
| 138 | 'from' => 'Text', |
||
| 139 | 'to' => 'Text', |
||
| 140 | ], |
||
| 141 | ], |
||
| 142 | 'profile' => [ |
||
| 143 | 'label' => 'LBL_PROFILING', |
||
| 144 | 'labelModule' => 'Settings:Log', |
||
| 145 | 'table' => 'l_#__profile', |
||
| 146 | 'icon' => 'fas fa-stopwatch', |
||
| 147 | 'columns' => [ |
||
| 148 | 'category' => ['type' => 'Text', 'label' => 'Category'], |
||
| 149 | 'info' => ['type' => 'Text', 'label' => 'LBL_PARAMS'], |
||
| 150 | 'log_time' => ['type' => 'Text', 'label' => 'LBL_TIME'], |
||
| 151 | 'trace' => ['type' => 'Text', 'label' => 'LBL_BACKTRACE'], |
||
| 152 | 'duration' => ['type' => 'Text', 'label' => 'LBL_DURATION'], |
||
| 153 | ], |
||
| 154 | 'filter' => [ |
||
| 155 | 'category' => 'Text', |
||
| 156 | 'subinfoject' => 'Text', |
||
| 157 | 'log_time' => 'Text', |
||
| 158 | 'trace' => 'Text', |
||
| 159 | 'duration' => 'Text', |
||
| 160 | ], |
||
| 161 | ], |
||
| 162 | ]; |
||
| 163 | public static $levelMap = [ |
||
| 164 | 'error' => Logger::LEVEL_ERROR, |
||
| 165 | 'warning' => Logger::LEVEL_WARNING, |
||
| 166 | 'info' => Logger::LEVEL_INFO, |
||
| 167 | 'trace' => Logger::LEVEL_TRACE, |
||
| 168 | 'profile' => Logger::LEVEL_PROFILE, |
||
| 169 | ]; |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Initializes the logger by registering [[flush()]] as a shutdown function. |
||
| 173 | */ |
||
| 174 | public function init() |
||
| 175 | { |
||
| 176 | parent::init(); |
||
| 177 | if (\Config\Debug::$LOG_LEVELS) { |
||
| 178 | $this->setLevels(\Config\Debug::$LOG_LEVELS); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 179 | } |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Sets the message levels that this target is interested in. |
||
| 184 | * |
||
| 185 | * @param array|int $levels message levels that this target is interested in. |
||
| 186 | */ |
||
| 187 | public function setLevels($levels) |
||
| 188 | { |
||
| 189 | if (\is_array($levels)) { |
||
| 190 | foreach ($levels as $level) { |
||
| 191 | if (isset(self::$levelMap[$level])) { |
||
| 192 | $this->logToLevels |= self::$levelMap[$level]; |
||
| 193 | } else { |
||
| 194 | throw new Exceptions\AppException("Unrecognized level: $level"); |
||
| 195 | } |
||
| 196 | } |
||
| 197 | } else { |
||
| 198 | $bitmapValues = array_reduce(self::$levelMap, fn ($carry, $item) => $carry | $item); |
||
| 199 | if (!($bitmapValues & $levels) && 0 !== $levels) { |
||
| 200 | throw new Exceptions\AppException("Incorrect $levels value"); |
||
| 201 | } |
||
| 202 | $this->logToLevels = $levels; |
||
| 203 | } |
||
| 204 | } |
||
| 205 | |||
| 206 | /** |
||
| 207 | * Logs a message with the given type and category. |
||
| 208 | * If [[traceLevel]] is greater than 0, additional call stack information about |
||
| 209 | * the application code will be logged as well. |
||
| 210 | * |
||
| 211 | * @param array|string $message the message to be logged. This can be a simple string or a more |
||
| 212 | * complex data structure that will be handled by a [[Target|log target]] |
||
| 213 | * @param int $level the level of the message. This must be one of the following: |
||
| 214 | * `Logger::LEVEL_ERROR`, `Logger::LEVEL_WARNING`, `Logger::LEVEL_INFO`, `Logger::LEVEL_TRACE`, |
||
| 215 | * `Logger::LEVEL_PROFILE_BEGIN`, `Logger::LEVEL_PROFILE_END` |
||
| 216 | * @param string $category the category of the message |
||
| 217 | */ |
||
| 218 | public function log($message, $level, $category = '') |
||
| 219 | { |
||
| 220 | if (0 !== $this->logToLevels && !($this->logToLevels & $level)) { |
||
| 221 | return; |
||
| 222 | } |
||
| 223 | $traces = ''; |
||
| 224 | if ($this->traceLevel) { |
||
| 225 | $traces = Debuger::getBacktrace(2, $this->traceLevel, ' - '); |
||
| 226 | } |
||
| 227 | if (static::$logToConsole) { |
||
| 228 | Debuger::addLogs($message, self::getLevelName($level), $traces); |
||
| 229 | } |
||
| 230 | $this->messages[] = [$message, $level, $category, microtime(true), $traces]; |
||
| 231 | if ($this->flushInterval > 0 && \count($this->messages) >= $this->flushInterval) { |
||
| 232 | $this->flush(); |
||
| 233 | } |
||
| 234 | } |
||
| 235 | |||
| 236 | /** |
||
| 237 | * Logs a trace message. |
||
| 238 | * Trace messages are logged mainly for development purpose to see |
||
| 239 | * the execution work flow of some code. |
||
| 240 | * |
||
| 241 | * @param string $message the message to be logged |
||
| 242 | * @param string $category the category of the message |
||
| 243 | */ |
||
| 244 | public static function trace($message, $category = '') |
||
| 245 | { |
||
| 246 | if (static::$logToFile) { |
||
| 247 | \Yii::getLogger()->log($message, Logger::LEVEL_TRACE, $category); |
||
| 248 | } |
||
| 249 | } |
||
| 250 | |||
| 251 | /** |
||
| 252 | * Logs an informative message. |
||
| 253 | * An informative message is typically logged by an application to keep record of |
||
| 254 | * something important (e.g. an administrator logs in). |
||
| 255 | * |
||
| 256 | * @param string $message the message to be logged |
||
| 257 | * @param string $category the category of the message |
||
| 258 | */ |
||
| 259 | public static function info($message, $category = '') |
||
| 260 | { |
||
| 261 | if (static::$logToFile) { |
||
| 262 | \Yii::getLogger()->log($message, Logger::LEVEL_INFO, $category); |
||
| 263 | } |
||
| 264 | } |
||
| 265 | |||
| 266 | /** |
||
| 267 | * Logs a warning message. |
||
| 268 | * A warning message is typically logged when an error occurs while the execution |
||
| 269 | * can still continue. |
||
| 270 | * |
||
| 271 | * @param string $message the message to be logged |
||
| 272 | * @param string $category the category of the message |
||
| 273 | */ |
||
| 274 | public static function warning($message, $category = '') |
||
| 275 | { |
||
| 276 | if (static::$logToFile) { |
||
| 277 | \Yii::getLogger()->log($message, Logger::LEVEL_WARNING, $category); |
||
| 278 | } |
||
| 279 | } |
||
| 280 | |||
| 281 | /** |
||
| 282 | * Logs an error message. |
||
| 283 | * An error message is typically logged when an unrecoverable error occurs |
||
| 284 | * during the execution of an application. |
||
| 285 | * |
||
| 286 | * @param string $message the message to be logged |
||
| 287 | * @param string $category the category of the message |
||
| 288 | */ |
||
| 289 | public static function error($message, $category = '') |
||
| 290 | { |
||
| 291 | if (static::$logToFile) { |
||
| 292 | \Yii::getLogger()->log($message, Logger::LEVEL_ERROR, $category); |
||
| 293 | } |
||
| 294 | } |
||
| 295 | |||
| 296 | /** |
||
| 297 | * Marks the beginning of a code block for profiling. |
||
| 298 | * This has to be matched with a call to [[endProfile]] with the same category name. |
||
| 299 | * The begin- and end- calls must also be properly nested. For example,. |
||
| 300 | * |
||
| 301 | * ```php |
||
| 302 | * \Yii::beginProfile('block1'); |
||
| 303 | * // some code to be profiled |
||
| 304 | * \Yii::beginProfile('block2'); |
||
| 305 | * // some other code to be profiled |
||
| 306 | * \Yii::endProfile('block2'); |
||
| 307 | * \Yii::endProfile('block1'); |
||
| 308 | * ``` |
||
| 309 | * |
||
| 310 | * @param string $token token for the code block |
||
| 311 | * @param string $category the category of this log message |
||
| 312 | * |
||
| 313 | * @see endProfile() |
||
| 314 | */ |
||
| 315 | public static function beginProfile($token, $category = '') |
||
| 316 | { |
||
| 317 | if (static::$logToProfile) { |
||
| 318 | $categories = \Config\Debug::$LOG_PROFILE_CATEGORIES ?? []; |
||
| 319 | if ($categories && !\in_array($category, $categories)) { |
||
| 320 | return; |
||
| 321 | } |
||
| 322 | \Yii::getLogger()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category); |
||
| 323 | } |
||
| 324 | } |
||
| 325 | |||
| 326 | /** |
||
| 327 | * Marks the end of a code block for profiling. |
||
| 328 | * This has to be matched with a previous call to [[beginProfile]] with the same category name. |
||
| 329 | * |
||
| 330 | * @param string $token token for the code block |
||
| 331 | * @param string $category the category of this log message |
||
| 332 | * |
||
| 333 | * @see beginProfile() |
||
| 334 | */ |
||
| 335 | public static function endProfile($token, $category = '') |
||
| 336 | { |
||
| 337 | if (static::$logToProfile) { |
||
| 338 | $categories = \Config\Debug::$LOG_PROFILE_CATEGORIES ?? []; |
||
| 339 | if ($categories && !\in_array($category, $categories)) { |
||
| 340 | return; |
||
| 341 | } |
||
| 342 | \Yii::getLogger()->log($token, Logger::LEVEL_PROFILE_END, $category); |
||
| 343 | } |
||
| 344 | } |
||
| 345 | |||
| 346 | /** |
||
| 347 | * Get user action logs. |
||
| 348 | * |
||
| 349 | * @param string $type |
||
| 350 | * @param string $mode |
||
| 351 | * @param bool $countMode |
||
| 352 | * |
||
| 353 | * @return array |
||
| 354 | */ |
||
| 355 | public static function getLogs($type, $mode, $countMode = false) |
||
| 356 | { |
||
| 357 | $db = \App\Db::getInstance('log'); |
||
| 358 | $query = (new \App\Db\Query())->from('o_#__' . $type); |
||
| 359 | if ('oneDay' === $mode) { |
||
| 360 | $query->where(['>=', 'date', date('Y-m-d H:i:s', strtotime('-1 day'))]); |
||
| 361 | } else { |
||
| 362 | $query->limit(100); |
||
| 363 | } |
||
| 364 | if ($countMode) { |
||
| 365 | return $query->count('*', $db); |
||
|
0 ignored issues
–
show
|
|||
| 366 | } |
||
| 367 | $query->orderBy(['id' => SORT_DESC]); |
||
| 368 | return $query->all($db); |
||
| 369 | } |
||
| 370 | |||
| 371 | /** |
||
| 372 | * Get last logs. |
||
| 373 | * |
||
| 374 | * @param bool|string[] $types |
||
| 375 | * |
||
| 376 | * @return string |
||
| 377 | */ |
||
| 378 | public static function getlastLogs($types = false) |
||
| 379 | { |
||
| 380 | $content = ''; |
||
| 381 | $i = 0; |
||
| 382 | foreach (\Yii::getLogger()->messages as $message) { |
||
| 383 | $level = \yii\log\Logger::getLevelName($message[1]); |
||
| 384 | if (false !== $types && !\in_array($level, $types)) { |
||
| 385 | continue; |
||
| 386 | } |
||
| 387 | $content .= "#$i [$level]"; |
||
| 388 | $category = $message[2] ?: ''; |
||
| 389 | if ($category) { |
||
| 390 | $content .= "[$category]"; |
||
| 391 | } |
||
| 392 | $content .= " {$message[0]}" . PHP_EOL; |
||
| 393 | ++$i; |
||
| 394 | } |
||
| 395 | return $content; |
||
| 396 | } |
||
| 397 | } |
||
| 398 |