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

Merged
merged 7 commits into from
Jan 1, 2025
Merged
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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refer to #20306

{
$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