Skip to content

Commit

Permalink
prevent scanning interfaces and traits (#4)
Browse files Browse the repository at this point in the history
Thanks a lot!
  • Loading branch information
mbolli authored Mar 14, 2023
1 parent dc52640 commit 537a740
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 14 deletions.
46 changes: 32 additions & 14 deletions src/Driver/AbstractClassDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,18 @@ protected function getMappingClasses(): array
/**
* Load fully qualified class name from file.
*
* @return class-string<object>
* @return class-string<object>|null
*/
protected function loadClassFromFile(string $mappingFile): string
protected function loadClassFromFile(string $mappingFile): ?string
{
$content = file_get_contents($mappingFile);
$tokens = token_get_all($content !== false ? $content : '');

$class = '';

$next = $this->findNextToken($tokens, \T_NAMESPACE);
$next = $this->findNextToken($tokens, [\T_NAMESPACE]);
if ($next !== null) {
$validTokenTypes = [\T_WHITESPACE, \T_NS_SEPARATOR, \T_STRING];
if (\PHP_VERSION_ID >= 80_000) {
$validTokenTypes[] = T_NAME_QUALIFIED;
}
$validTokenTypes = $this->getValidTokenTypes();

while (
\array_key_exists($next + 1, $tokens)
Expand All @@ -70,12 +67,19 @@ protected function loadClassFromFile(string $mappingFile): string
++$next;
}

$next = $this->findNextToken($tokens, \T_CLASS, $next + 1, \T_DOUBLE_COLON);
// Exclude traits and interfaces
if ($this->findNextToken($tokens, [\T_TRAIT, \T_INTERFACE], $next + 1) !== null) {
return null;
}

$next = $this->findNextToken($tokens, [\T_CLASS], $next + 1, \T_DOUBLE_COLON);
if ($next === null) {
return null;
}

$next = $this->findNextToken($tokens, [\T_STRING], $next + 1);
if ($next !== null) {
$next = $this->findNextToken($tokens, \T_STRING, $next + 1);
if ($next !== null) {
$class .= '\\' . $tokens[$next][1];
}
$class .= '\\' . $tokens[$next][1];
}
}

Expand All @@ -87,8 +91,9 @@ protected function loadClassFromFile(string $mappingFile): string
* Traverse token stack in search of next token.
*
* @param array<mixed|array{0: int, 1: string, 2: int}> $tokens
* @param array<int> $types
*/
private function findNextToken(array $tokens, int $type, int $start = 0, ?int $escapePreviousType = null): ?int
private function findNextToken(array $tokens, array $types, int $start = 0, ?int $escapePreviousType = null): ?int
{
$previousToken = false;

Expand All @@ -99,7 +104,7 @@ private function findNextToken(array $tokens, int $type, int $start = 0, ?int $e
}

if (
$token[0] === $type
\in_array($token[0], $types, true)
&& (
$escapePreviousType === null
|| !\is_array($previousToken)
Expand All @@ -114,4 +119,17 @@ private function findNextToken(array $tokens, int $type, int $start = 0, ?int $e

return null;
}

/**
* @return array<int>
*/
private function getValidTokenTypes(): array
{
$validTokenTypes = [\T_WHITESPACE, \T_NS_SEPARATOR, \T_STRING];
if (\PHP_VERSION_ID >= 80_000) {
$validTokenTypes[] = T_NAME_QUALIFIED;
}

return $validTokenTypes;
}
}
37 changes: 37 additions & 0 deletions tests/Mapping/Driver/AbstractClassDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* mapping (https://github.com/juliangut/mapping).
* Mapping parsing base library.
*
* @license BSD-3-Clause
* @link https://github.com/juliangut/mapping
* @author Julián Gutiérrez <[email protected]>
*/

declare(strict_types=1);

namespace Jgut\Mapping\Tests\Driver;

use Jgut\Mapping\Tests\Files\Classes\Valid\Attribute\ClassA;
use Jgut\Mapping\Tests\Stubs\AbstractClassDriverStub;
use PHPUnit\Framework\TestCase;

/**
* @internal
*/
class AbstractClassDriverTest extends TestCase
{
public function testClassLoader(): void
{
$driver = new AbstractClassDriverStub([__DIR__ . '/../Files/Classes/Valid/Attribute']);

$className = $driver->loadClassFromFile(__DIR__ . '/../Files/Classes/Valid/Attribute/ClassA.php');
$traitName = $driver->loadClassFromFile(__DIR__ . '/../Files/Classes/Invalid/Attribute/Trait.php');
$interfaceName = $driver->loadClassFromFile(__DIR__ . '/../Files/Classes/Invalid/Attribute/Interface.php');

static::assertSame(ClassA::class, $className);
static::assertNull($traitName);
static::assertNull($interfaceName);
}
}
19 changes: 19 additions & 0 deletions tests/Mapping/Files/Classes/Invalid/Attribute/Interface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/*
* mapping (https://github.com/juliangut/mapping).
* Mapping parsing base library.
*
* @license BSD-3-Clause
* @link https://github.com/juliangut/mapping
* @author Julián Gutiérrez <[email protected]>
*/

declare(strict_types=1);

namespace Jgut\Mapping\Tests\Files\Classes\Invalid\Attribute;

interface InterfaceA
{
public function methodA(): void;
}
27 changes: 27 additions & 0 deletions tests/Mapping/Files/Classes/Invalid/Attribute/Trait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* mapping (https://github.com/juliangut/mapping).
* Mapping parsing base library.
*
* @license BSD-3-Clause
* @link https://github.com/juliangut/mapping
* @author Julián Gutiérrez <[email protected]>
*/

declare(strict_types=1);

namespace Jgut\Mapping\Tests\Files\Classes\Invalid\Attribute;

trait TraitA
{
public function methodA(): void
{
}

public function methodB(): void
{
$var = new class() {};
echo \get_class($var);
}
}
35 changes: 35 additions & 0 deletions tests/Mapping/Stubs/AbstractClassDriverStub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/*
* mapping (https://github.com/juliangut/mapping).
* Mapping parsing base library.
*
* @license BSD-3-Clause
* @link https://github.com/juliangut/mapping
* @author Julián Gutiérrez <[email protected]>
*/

declare(strict_types=1);

namespace Jgut\Mapping\Tests\Stubs;

use Jgut\Mapping\Driver\AbstractClassDriver;
use Jgut\Mapping\Metadata\MetadataInterface;

class AbstractClassDriverStub extends AbstractClassDriver
{
/**
* Get mapped metadata.
*
* @return array<MetadataInterface>
*/
public function getMetadata(): array
{
return [];
}

public function loadClassFromFile(string $mappingFile, bool $uselessVariable = true): ?string
{
return parent::loadClassFromFile($mappingFile);
}
}

0 comments on commit 537a740

Please sign in to comment.