Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wildcards in yii\log\Target::$maskVars array #20297

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Yii Framework 2 Change Log
- Bug #20140: Fix compatibility with PHP 8.4: calling `session_set_save_handler()` (Izumi-kun)
- New #20185: Add `BackedEnum` support to `AttributeTypecastBehavior` (briedis)
- Bug #17365: Fix "Trying to access array offset on null" warning (xcopy)
- Enh #20295: An ability to have wildcards in `yii\log\Target::$maskVars` array (xcopy)
samdark marked this conversation as resolved.
Show resolved Hide resolved
- Bug #20296: Fix broken enum test (briedis)

2.0.51 July 18, 2024
Expand Down
58 changes: 55 additions & 3 deletions framework/log/Target.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\StringHelper;
use yii\helpers\VarDumper;
use yii\web\Request;

Expand Down Expand Up @@ -161,6 +162,54 @@ public function collect($messages, $final)
}
}

/**
* Flattens a multidimensional array into a one-dimensional array.
*
* This method recursively traverses the input array and concatenates the keys
* to form a new key in the resulting array.
*
* Example:
*
* ```php
* $array = [
* 'A' => [1, 2],
* 'B' => [
* 'C' => 1,
* 'D' => 2,
* ],
* 'E' => 1,
* ];
* $result = \yii\log\Target::flatten($array);
* // result will be:
* // [
* // 'A.0' => 1
* // 'A.1' => 2
* // 'B.C' => 1
* // 'B.D' => 2
* // 'E' => 1
* // ]
* ```
*
* @param array $array the input array to be flattened.
* @param string $prefix the prefix to be added to each key in the resulting array.
*
* @return array the flattened array.
*/
private static function flatten($array, $prefix = ''): array
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this method should be here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good candidate for array helper.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I leave as is for now and then handle it in a separate PR? (dedicated to new ArrayHelper::flatten() method)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

{
$result = [];

foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, self::flatten($value, $prefix . $key . '.'));
} else {
$result[$prefix . $key] = $value;
}
}

return $result;
}

/**
* Generates the context information to be logged.
* The default implementation will dump user information, system variables, etc.
Expand All @@ -169,9 +218,12 @@ public function collect($messages, $final)
protected function getContextMessage()
{
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
$items = self::flatten($context);
foreach ($this->maskVars as $var) {
if (ArrayHelper::getValue($context, $var) !== null) {
ArrayHelper::setValue($context, $var, '***');
foreach ($items as $key => $value) {
if (StringHelper::matchWildcard($var, $key, ['caseSensitive' => false])) {
ArrayHelper::setValue($context, $key, '***');
}
}
}
$result = [];
Expand Down Expand Up @@ -292,7 +344,7 @@ public static function filterMessages($messages, $levels = 0, $categories = [],
*/
public function formatMessage($message)
{
list($text, $level, $category, $timestamp) = $message;
[$text, $level, $category, $timestamp] = $message;
$level = Logger::getLevelName($level);
if (!is_string($text)) {
// exceptions may not be serializable if in the call stack somewhere is a Closure
Expand Down
39 changes: 39 additions & 0 deletions tests/framework/log/TargetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,45 @@ public function testFlushingWithProfilingEnabledAndOverflow()
$logger->log('token.b', Logger::LEVEL_PROFILE_END, 'category');
$logger->log('token.a', Logger::LEVEL_PROFILE_END, 'category');
}

public function testWildcardsInMaskVars()
{
$keys = [
'PASSWORD',
'password',
'password_repeat',
'repeat_password',
'repeat_password_again',
'1password',
'password1',
];

$password = '!P@$$w0rd#';

$items = array_fill_keys($keys, $password);

$GLOBALS['_TEST'] = array_merge(
$items,
['a' => $items],
['b' => ['c' => $items]],
['d' => ['e' => ['f' => $items]]],
);

$target = new TestTarget([
'logVars' => ['_SERVER', '_TEST'],
'maskVars' => [
// option 1: exact value(s)
'_SERVER.DOCUMENT_ROOT',
// option 2: pattern(s)
'_TEST.*password*',
]
]);

$message = $target->getContextMessage();

$this->assertStringContainsString("'DOCUMENT_ROOT' => '***'", $message);
$this->assertStringNotContainsString($password, $message);
}
}

class TestTarget extends Target
Expand Down
Loading