Skip to content
11 changes: 6 additions & 5 deletions src/support/src/FileinfoMimeTypeGuesser.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Exception;
use finfo;
use Hypervel\Context\CoroutineContext;
use InvalidArgumentException;
use LogicException;
use RuntimeException;
Expand All @@ -24,10 +25,7 @@
*/
class FileinfoMimeTypeGuesser
{
/**
* @var array<string, finfo>
*/
private static $finfoCache = [];
public const FINFO_CONTEXT_KEY_PREFIX = '__support.finfo_mime_type_guesser.';

/**
* @param null|string $magicFile A magic file to use with the finfo instance
Expand Down Expand Up @@ -55,7 +53,10 @@ public function guessMimeType(string $path): ?string
}

try {
$finfo = self::$finfoCache[$this->magicFile] ??= new finfo(FILEINFO_MIME_TYPE, $this->magicFile);
$finfo = CoroutineContext::getOrSet(
self::FINFO_CONTEXT_KEY_PREFIX . ($this->magicFile ?? ''),
fn () => new finfo(FILEINFO_MIME_TYPE, $this->magicFile)
);
} catch (Exception $e) {
throw new RuntimeException($e->getMessage());
}
Expand Down
57 changes: 57 additions & 0 deletions tests/Support/FileinfoMimeTypeGuesserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Hypervel\Tests\Support;

use finfo;
use Hypervel\Context\CoroutineContext;
use Hypervel\Support\FileinfoMimeTypeGuesser;
use Hypervel\Tests\TestCase;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;

use function Hypervel\Coroutine\parallel;

#[RequiresPhpExtension('fileinfo')]
class FileinfoMimeTypeGuesserTest extends TestCase
{
public function testGuessMimeTypeWithInvalidFile()
{
$this->expectException(InvalidArgumentException::class);

(new FileinfoMimeTypeGuesser)
->guessMimeType(__DIR__ . '/unknown');
}

public function testGuessMimeType()
{
$mimeType = (new FileinfoMimeTypeGuesser)
->guessMimeType(__DIR__ . '/Fixtures/test.gif');

$this->assertEquals('image/gif', $mimeType);
}

public function testGuessMimeTypeIsCoroutineScoped()
{
$guesser = new FileinfoMimeTypeGuesser;
$key = FileinfoMimeTypeGuesser::FINFO_CONTEXT_KEY_PREFIX;

$results = parallel(array_fill(0, 5, function () use ($guesser, $key) {
return [
'mimeType' => $guesser->guessMimeType(__DIR__ . '/Fixtures/test.gif'),
'finfo' => CoroutineContext::get($key),
];
}));

$this->assertCount(5, $results);
foreach ($results as $result) {
$this->assertSame('image/gif', $result['mimeType']);
}

$finfoInstances = array_column($results, 'finfo');

$this->assertContainsOnlyInstancesOf(finfo::class, $finfoInstances);
$this->assertCount(5, array_unique(array_map(spl_object_id(...), $finfoInstances)));
}
}
Binary file added tests/Support/Fixtures/test.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.