MRBS 1.12.2 等保2.0二级整改完整提交
包含:登录失败锁定、90天密码有效期、30分钟会话超时、 强制改密、登录审计日志、屏幕水印、企业背景图、 备案信息固定底部、favicon、JS空集合保护、 会话过期体验优化(403 JSON)、display_errors 关闭、 固定 key 根治 Integrity check failed 等全部改动 注意:config.inc.php/.htaccess/.user.ini 含敏感信息, 通过 .gitignore 排除,勿推送到公开仓库。
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Injects Git branch and Git commit SHA in all records
|
||||
*
|
||||
* @author Nick Otter
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* @phpstan-import-type Level from \Monolog\Logger
|
||||
* @phpstan-import-type LevelName from \Monolog\Logger
|
||||
*/
|
||||
class GitProcessor implements ProcessorInterface
|
||||
{
|
||||
/** @var int */
|
||||
private $level;
|
||||
/** @var array{branch: string, commit: string}|array<never>|null */
|
||||
private static $cache = null;
|
||||
|
||||
/**
|
||||
* @param string|int $level The minimum logging level at which this Processor will be triggered
|
||||
*
|
||||
* @phpstan-param Level|LevelName|LogLevel::* $level
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG)
|
||||
{
|
||||
$this->level = Logger::toMonologLevel($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
// return if the level is not high enough
|
||||
if ($record['level'] < $this->level) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$record['extra']['git'] = self::getGitInfo();
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{branch: string, commit: string}|array<never>
|
||||
*/
|
||||
private static function getGitInfo(): array
|
||||
{
|
||||
if (self::$cache) {
|
||||
return self::$cache;
|
||||
}
|
||||
|
||||
$branches = `git branch -v --no-abbrev`;
|
||||
if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
|
||||
return self::$cache = [
|
||||
'branch' => $matches[1],
|
||||
'commit' => $matches[2],
|
||||
];
|
||||
}
|
||||
|
||||
return self::$cache = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Injects value of gethostname in all records
|
||||
*/
|
||||
class HostnameProcessor implements ProcessorInterface
|
||||
{
|
||||
/** @var string */
|
||||
private static $host;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
self::$host = (string) gethostname();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$record['extra']['hostname'] = self::$host;
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Injects line/file:class/function where the log message came from
|
||||
*
|
||||
* Warning: This only works if the handler processes the logs directly.
|
||||
* If you put the processor on a handler that is behind a FingersCrossedHandler
|
||||
* for example, the processor will only be called once the trigger level is reached,
|
||||
* and all the log records will have the same file/line/.. data from the call that
|
||||
* triggered the FingersCrossedHandler.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* @phpstan-import-type Level from \Monolog\Logger
|
||||
* @phpstan-import-type LevelName from \Monolog\Logger
|
||||
*/
|
||||
class IntrospectionProcessor implements ProcessorInterface
|
||||
{
|
||||
/** @var int */
|
||||
private $level;
|
||||
/** @var string[] */
|
||||
private $skipClassesPartials;
|
||||
/** @var int */
|
||||
private $skipStackFramesCount;
|
||||
/** @var string[] */
|
||||
private $skipFunctions = [
|
||||
'call_user_func',
|
||||
'call_user_func_array',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string|int $level The minimum logging level at which this Processor will be triggered
|
||||
* @param string[] $skipClassesPartials
|
||||
*
|
||||
* @phpstan-param Level|LevelName|LogLevel::* $level
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0)
|
||||
{
|
||||
$this->level = Logger::toMonologLevel($level);
|
||||
$this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials);
|
||||
$this->skipStackFramesCount = $skipStackFramesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
// return if the level is not high enough
|
||||
if ($record['level'] < $this->level) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
// skip first since it's always the current method
|
||||
array_shift($trace);
|
||||
// the call_user_func call is also skipped
|
||||
array_shift($trace);
|
||||
|
||||
$i = 0;
|
||||
|
||||
while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
|
||||
if (isset($trace[$i]['class'])) {
|
||||
foreach ($this->skipClassesPartials as $part) {
|
||||
if (strpos($trace[$i]['class'], $part) !== false) {
|
||||
$i++;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
} elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
|
||||
$i++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$i += $this->skipStackFramesCount;
|
||||
|
||||
// we should have the call source now
|
||||
$record['extra'] = array_merge(
|
||||
$record['extra'],
|
||||
[
|
||||
'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
|
||||
'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
|
||||
'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
|
||||
'callType' => isset($trace[$i]['type']) ? $trace[$i]['type'] : null,
|
||||
'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
|
||||
]
|
||||
);
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array[] $trace
|
||||
*/
|
||||
private function isTraceClassOrSkippedFunction(array $trace, int $index): bool
|
||||
{
|
||||
if (!isset($trace[$index])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Injects memory_get_peak_usage in all records
|
||||
*
|
||||
* @see Monolog\Processor\MemoryProcessor::__construct() for options
|
||||
* @author Rob Jensen
|
||||
*/
|
||||
class MemoryPeakUsageProcessor extends MemoryProcessor
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$usage = memory_get_peak_usage($this->realUsage);
|
||||
|
||||
if ($this->useFormatting) {
|
||||
$usage = $this->formatBytes($usage);
|
||||
}
|
||||
|
||||
$record['extra']['memory_peak_usage'] = $usage;
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Some methods that are common for all memory processors
|
||||
*
|
||||
* @author Rob Jensen
|
||||
*/
|
||||
abstract class MemoryProcessor implements ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
|
||||
*/
|
||||
protected $realUsage;
|
||||
|
||||
/**
|
||||
* @var bool If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
*/
|
||||
protected $useFormatting;
|
||||
|
||||
/**
|
||||
* @param bool $realUsage Set this to true to get the real size of memory allocated from system.
|
||||
* @param bool $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
*/
|
||||
public function __construct(bool $realUsage = true, bool $useFormatting = true)
|
||||
{
|
||||
$this->realUsage = $realUsage;
|
||||
$this->useFormatting = $useFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is
|
||||
*
|
||||
* @param int $bytes
|
||||
* @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as int
|
||||
*/
|
||||
protected function formatBytes(int $bytes)
|
||||
{
|
||||
if (!$this->useFormatting) {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
if ($bytes > 1024 * 1024) {
|
||||
return round($bytes / 1024 / 1024, 2).' MB';
|
||||
} elseif ($bytes > 1024) {
|
||||
return round($bytes / 1024, 2).' KB';
|
||||
}
|
||||
|
||||
return $bytes . ' B';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Injects memory_get_usage in all records
|
||||
*
|
||||
* @see Monolog\Processor\MemoryProcessor::__construct() for options
|
||||
* @author Rob Jensen
|
||||
*/
|
||||
class MemoryUsageProcessor extends MemoryProcessor
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$usage = memory_get_usage($this->realUsage);
|
||||
|
||||
if ($this->useFormatting) {
|
||||
$usage = $this->formatBytes($usage);
|
||||
}
|
||||
|
||||
$record['extra']['memory_usage'] = $usage;
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Injects Hg branch and Hg revision number in all records
|
||||
*
|
||||
* @author Jonathan A. Schweder <jonathanschweder@gmail.com>
|
||||
*
|
||||
* @phpstan-import-type LevelName from \Monolog\Logger
|
||||
* @phpstan-import-type Level from \Monolog\Logger
|
||||
*/
|
||||
class MercurialProcessor implements ProcessorInterface
|
||||
{
|
||||
/** @var Level */
|
||||
private $level;
|
||||
/** @var array{branch: string, revision: string}|array<never>|null */
|
||||
private static $cache = null;
|
||||
|
||||
/**
|
||||
* @param int|string $level The minimum logging level at which this Processor will be triggered
|
||||
*
|
||||
* @phpstan-param Level|LevelName|LogLevel::* $level
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG)
|
||||
{
|
||||
$this->level = Logger::toMonologLevel($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
// return if the level is not high enough
|
||||
if ($record['level'] < $this->level) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$record['extra']['hg'] = self::getMercurialInfo();
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{branch: string, revision: string}|array<never>
|
||||
*/
|
||||
private static function getMercurialInfo(): array
|
||||
{
|
||||
if (self::$cache) {
|
||||
return self::$cache;
|
||||
}
|
||||
|
||||
$result = explode(' ', trim(`hg id -nb`));
|
||||
|
||||
if (count($result) >= 3) {
|
||||
return self::$cache = [
|
||||
'branch' => $result[1],
|
||||
'revision' => $result[2],
|
||||
];
|
||||
}
|
||||
|
||||
return self::$cache = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Adds value of getmypid into records
|
||||
*
|
||||
* @author Andreas Hörnicke
|
||||
*/
|
||||
class ProcessIdProcessor implements ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$record['extra']['process_id'] = getmypid();
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* An optional interface to allow labelling Monolog processors.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @phpstan-import-type Record from \Monolog\Logger
|
||||
*/
|
||||
interface ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @return array The processed record
|
||||
*
|
||||
* @phpstan-param Record $record
|
||||
* @phpstan-return Record
|
||||
*/
|
||||
public function __invoke(array $record);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Processes a record's message according to PSR-3 rules
|
||||
*
|
||||
* It replaces {foo} with the value from $context['foo']
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class PsrLogMessageProcessor implements ProcessorInterface
|
||||
{
|
||||
public const SIMPLE_DATE = "Y-m-d\TH:i:s.uP";
|
||||
|
||||
/** @var string|null */
|
||||
private $dateFormat;
|
||||
|
||||
/** @var bool */
|
||||
private $removeUsedContextFields;
|
||||
|
||||
/**
|
||||
* @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format
|
||||
* @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset
|
||||
*/
|
||||
public function __construct(?string $dateFormat = null, bool $removeUsedContextFields = false)
|
||||
{
|
||||
$this->dateFormat = $dateFormat;
|
||||
$this->removeUsedContextFields = $removeUsedContextFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
if (false === strpos($record['message'], '{')) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$replacements = [];
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$placeholder = '{' . $key . '}';
|
||||
if (strpos($record['message'], $placeholder) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
|
||||
$replacements[$placeholder] = $val;
|
||||
} elseif ($val instanceof \DateTimeInterface) {
|
||||
if (!$this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) {
|
||||
// handle monolog dates using __toString if no specific dateFormat was asked for
|
||||
// so that it follows the useMicroseconds flag
|
||||
$replacements[$placeholder] = (string) $val;
|
||||
} else {
|
||||
$replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
|
||||
}
|
||||
} elseif ($val instanceof \UnitEnum) {
|
||||
$replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name;
|
||||
} elseif (is_object($val)) {
|
||||
$replacements[$placeholder] = '[object '.Utils::getClass($val).']';
|
||||
} elseif (is_array($val)) {
|
||||
$replacements[$placeholder] = 'array'.Utils::jsonEncode($val, null, true);
|
||||
} else {
|
||||
$replacements[$placeholder] = '['.gettype($val).']';
|
||||
}
|
||||
|
||||
if ($this->removeUsedContextFields) {
|
||||
unset($record['context'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$record['message'] = strtr($record['message'], $replacements);
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Adds a tags array into record
|
||||
*
|
||||
* @author Martijn Riemers
|
||||
*/
|
||||
class TagProcessor implements ProcessorInterface
|
||||
{
|
||||
/** @var string[] */
|
||||
private $tags;
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public function __construct(array $tags = [])
|
||||
{
|
||||
$this->setTags($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public function addTags(array $tags = []): self
|
||||
{
|
||||
$this->tags = array_merge($this->tags, $tags);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public function setTags(array $tags = []): self
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$record['extra']['tags'] = $this->tags;
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\ResettableInterface;
|
||||
|
||||
/**
|
||||
* Adds a unique identifier into records
|
||||
*
|
||||
* @author Simon Mönch <sm@webfactory.de>
|
||||
*/
|
||||
class UidProcessor implements ProcessorInterface, ResettableInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $uid;
|
||||
|
||||
public function __construct(int $length = 7)
|
||||
{
|
||||
if ($length > 32 || $length < 1) {
|
||||
throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
|
||||
}
|
||||
|
||||
$this->uid = $this->generateUid($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
$record['extra']['uid'] = $this->uid;
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
public function getUid(): string
|
||||
{
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->uid = $this->generateUid(strlen($this->uid));
|
||||
}
|
||||
|
||||
private function generateUid(int $length): string
|
||||
{
|
||||
return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
/**
|
||||
* Injects url/method and remote IP of the current web request in all records
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class WebProcessor implements ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>|\ArrayAccess<string, mixed>
|
||||
*/
|
||||
protected $serverData;
|
||||
|
||||
/**
|
||||
* Default fields
|
||||
*
|
||||
* Array is structured as [key in record.extra => key in $serverData]
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $extraFields = [
|
||||
'url' => 'REQUEST_URI',
|
||||
'ip' => 'REMOTE_ADDR',
|
||||
'http_method' => 'REQUEST_METHOD',
|
||||
'server' => 'SERVER_NAME',
|
||||
'referrer' => 'HTTP_REFERER',
|
||||
'user_agent' => 'HTTP_USER_AGENT',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|\ArrayAccess<string, mixed>|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data
|
||||
* @param array<string, string>|array<string>|null $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
|
||||
*/
|
||||
public function __construct($serverData = null, ?array $extraFields = null)
|
||||
{
|
||||
if (null === $serverData) {
|
||||
$this->serverData = &$_SERVER;
|
||||
} elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
|
||||
$this->serverData = $serverData;
|
||||
} else {
|
||||
throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
|
||||
}
|
||||
|
||||
$defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer'];
|
||||
if (isset($this->serverData['UNIQUE_ID'])) {
|
||||
$this->extraFields['unique_id'] = 'UNIQUE_ID';
|
||||
$defaultEnabled[] = 'unique_id';
|
||||
}
|
||||
|
||||
if (null === $extraFields) {
|
||||
$extraFields = $defaultEnabled;
|
||||
}
|
||||
if (isset($extraFields[0])) {
|
||||
foreach (array_keys($this->extraFields) as $fieldName) {
|
||||
if (!in_array($fieldName, $extraFields)) {
|
||||
unset($this->extraFields[$fieldName]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->extraFields = $extraFields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __invoke(array $record): array
|
||||
{
|
||||
// skip processing if for some reason request data
|
||||
// is not present (CLI or wonky SAPIs)
|
||||
if (!isset($this->serverData['REQUEST_URI'])) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$record['extra'] = $this->appendExtraFields($record['extra']);
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
public function addExtraField(string $extraName, string $serverName): self
|
||||
{
|
||||
$this->extraFields[$extraName] = $serverName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $extra
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function appendExtraFields(array $extra): array
|
||||
{
|
||||
foreach ($this->extraFields as $extraName => $serverName) {
|
||||
$extra[$extraName] = $this->serverData[$serverName] ?? null;
|
||||
}
|
||||
|
||||
return $extra;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user