Skip to content

Commit

Permalink
Always treat stream wrappers as absolute paths (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianHenryIE authored Feb 5, 2025
1 parent 4b0a223 commit ffe442c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 4 deletions.
15 changes: 12 additions & 3 deletions src/ClassMapGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,19 @@ class ClassMapGenerator
*/
private $classMap;

/**
* @var non-empty-string
*/
private $streamWrappersRegex;

/**
* @param list<string> $extensions File extensions to scan for classes in the given paths
*/
public function __construct(array $extensions = ['php', 'inc'])
{
$this->extensions = $extensions;
$this->classMap = new ClassMap;
$this->streamWrappersRegex = sprintf('{^(?:%s)://}', implode('|', array_map('preg_quote', stream_get_wrappers())));
}

/**
Expand Down Expand Up @@ -142,18 +148,21 @@ public function scanPaths($path, ?string $excluded = null, string $autoloadType
continue;
}

if (!self::isAbsolutePath($filePath)) {
$isStreamWrapperPath = Preg::isMatch($this->streamWrappersRegex, $filePath);
if (!self::isAbsolutePath($filePath) && !$isStreamWrapperPath) {
$filePath = $cwd . '/' . $filePath;
$filePath = self::normalizePath($filePath);
} else {
$filePath = Preg::replace('{[\\\\/]{2,}}', '/', $filePath);
$filePath = Preg::replace('{(?<!:)[\\\\/]{2,}}', '/', $filePath);
}

if ('' === $filePath) {
throw new \LogicException('Got an empty $filePath for '.$file->getPathname());
}

$realPath = realpath($filePath);
$realPath = $isStreamWrapperPath
? $filePath
: realpath($filePath);

// fallback just in case but this really should not happen
if (false === $realPath) {
Expand Down
81 changes: 80 additions & 1 deletion tests/ClassMapGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

namespace Composer\ClassMapGenerator;

use Composer\ClassMapGenerator\ClassMapGenerator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Filesystem\Filesystem;
Expand Down Expand Up @@ -150,6 +149,86 @@ public function testCreateMapFinderSupport(): void
), ClassMapGenerator::createMap($finder));
}

/**
* @see ClassMapGenerator::isStreamWrapper()
*/
public function testStreamWrapperSupport(): void {

/**
* A stream wrapper that given `test://myfile.php` will read `test://path/to/myfile.php` where `path/to` is
* set on the `$rootPath` static variable.
*/
$testProxyStreamWrapper = new class() {
/**
* @var string
*/
public static $rootPath;

/**
* @var string
*/
protected $real;

/**
* @var resource|false
*/
protected $resource;

/**
* @param string $path
* @param string $mode
* @param int $options
* @param ?string $opened_path
*
* @return bool
*/
public function stream_open($path, $mode, $options, &$opened_path) {
$scheme = parse_url($path, PHP_URL_SCHEME);
$varname = str_replace($scheme . '://', '', $path);

$this->real = 'file://' . self::$rootPath . '/' . $varname;

$this->resource = fopen($this->real, $mode);

return (bool) $this->resource;
}

/**
* @param int<0, max>|null $count
*
* @return false|string
*/
public function stream_read($count) {
return $this->resource === false ? false : fgets($this->resource, (int) $count);
}

/**
* @return array<int|string, int>|false
*/
public function stream_stat() {
return $this->resource === false ? false : fstat($this->resource);
}
};

$testProxyStreamWrapper::$rootPath = realpath(__DIR__) . '/Fixtures/classmap';
stream_wrapper_register('test', get_class($testProxyStreamWrapper));

$arrayOfSplFileInfoStreamPaths = [
new \SplFileInfo('test://BackslashLineEndingString.php'),
new \SplFileInfo('test://InvalidUnicode.php'),
];

self::assertSame(
[
'Foo\\SlashedA' => 'test://BackslashLineEndingString.php',
'Foo\\SlashedB' => 'test://BackslashLineEndingString.php',
'Smarty_Internal_Compile_Block' => 'test://InvalidUnicode.php',
'Smarty_Internal_Compile_Blockclose' => 'test://InvalidUnicode.php',
],
ClassMapGenerator::createMap($arrayOfSplFileInfoStreamPaths)
);
}

public function testAmbiguousReference(): void
{
$tempDir = self::getUniqueTmpDirectory();
Expand Down

0 comments on commit ffe442c

Please sign in to comment.