diff --git a/build/kint.phar b/build/kint.phar index 8fe95d5a2..4f824bcf1 100644 Binary files a/build/kint.phar and b/build/kint.phar differ diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index 7e30eccdc..8f7ab2f0c 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -31,6 +31,7 @@ use DomainException; use Exception; use InvalidArgumentException; +use Kint\Utils; use Kint\Zval\BlobValue; use Kint\Zval\InstanceValue; use Kint\Zval\Representation\Representation; @@ -522,7 +523,7 @@ private function parseObject(&$var, Value $o): Value * We set it explicitly to string in the Value initialization * because since 7.2 casts to objects cast numeric keys too */ - if (\preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/', $child->name)) { + if (Utils::isValidPhpName($child->name)) { $child->access_path .= '->'.$child->name; } else { $child->access_path .= '->{'.\var_export($child->name, true).'}'; diff --git a/src/Utils.php b/src/Utils.php index 96597fbd3..43a194ffc 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -233,18 +233,38 @@ public static function traceFrameIsListed(array $frame, array $matches): bool return \in_array($called, $matches, true); } - public static function normalizeAliases(array &$aliases): void + public static function isValidPhpName(string $name): bool + { + return (bool) \preg_match('/^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*$/', $name); + } + + public static function isValidPhpNamespace(string $ns): bool { - static $name_regex = '[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*'; + $parts = \explode('\\', $ns); + if ('' === \reset($parts)) { + \array_shift($parts); + } + + if (!\count($parts)) { + return false; + } + foreach ($parts as $part) { + if (!self::isValidPhpName($part)) { + return false; + } + } + + return true; + } + + public static function normalizeAliases(array &$aliases): void + { foreach ($aliases as $index => &$alias) { if (\is_array($alias) && 2 === \count($alias)) { $alias = \array_values(\array_filter($alias, 'is_string')); - if (2 === \count($alias) && - \preg_match('/^'.$name_regex.'$/', $alias[1]) && - \preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias[0]) - ) { + if (2 === \count($alias) && self::isValidPhpName($alias[1]) && self::isValidPhpNamespace($alias[0])) { $alias = [ \strtolower(\ltrim($alias[0], '\\')), \strtolower($alias[1]), @@ -254,7 +274,7 @@ public static function normalizeAliases(array &$aliases): void continue; } } elseif (\is_string($alias)) { - if (\preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias)) { + if (self::isValidPhpNamespace($alias)) { $alias = \explode('\\', \strtolower($alias)); $alias = \end($alias); } else { diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php index 1220b0905..b00cbccc7 100644 --- a/tests/UtilsTest.php +++ b/tests/UtilsTest.php @@ -522,4 +522,80 @@ public function testGetTypeString() $this->assertSame('X&Y', Utils::getTypeString($param->getType())); } } + + public function phpNameProvider() + { + return [ + 'valid name' => [ + 'input' => 'asdf1234__asdf', + 'expect' => true, + ], + 'invalid name starts with number' => [ + 'input' => '1asdf1234__asdf', + 'expect' => false, + ], + 'invalid name contains dash' => [ + 'input' => 'asdf1234--asdf', + 'expect' => false, + ], + 'invalid name empty' => [ + 'input' => '', + 'expect' => false, + ], + 'invalid name space' => [ + 'input' => ' ', + 'expect' => false, + ], + ]; + } + + public function phpNamespaceProvider() + { + return [ + 'valid namespace' => [ + 'input' => 'asdf1234__asdf\\asdf1234__asdf\\asdf1234__asdf', + 'expect' => true, + ], + 'valid namespace leading backslash' => [ + 'input' => '\\asdf1234__asdf\\asdf1234__asdf\\asdf1234__asdf', + 'expect' => true, + ], + 'invalid namespace part starts with number' => [ + 'input' => 'asdf1234__asdf\\1asdf1234__asdf\\asdf1234__asdf', + 'expect' => false, + ], + 'invalid namespace part contains dash' => [ + 'input' => 'asdf1234__asdf\\asdf1234--asdf\\asdf1234__asdf', + 'expect' => false, + ], + 'invalid namespace empty' => [ + 'input' => '', + 'expect' => false, + ], + 'invalid namespace space' => [ + 'input' => ' ', + 'expect' => false, + ], + ]; + } + + /** + * @dataProvider phpNameProvider + * + * @covers \Kint\Utils::isValidPhpName + */ + public function testIsValidPhpName(string $input, bool $expect) + { + $this->assertSame($expect, Utils::isValidPhpName($input)); + } + + /** + * @dataProvider phpNamespaceProvider + * + * @covers \Kint\Utils::isValidPhpNamespace + */ + public function testIsValidPhpNamespace(string $input, bool $expect) + { + $this->assertSame($expect, Utils::isValidPhpNamespace($input)); + } }