diff --git a/src/support/src/FileinfoMimeTypeGuesser.php b/src/support/src/FileinfoMimeTypeGuesser.php index fa04a2b33..2debe0d96 100644 --- a/src/support/src/FileinfoMimeTypeGuesser.php +++ b/src/support/src/FileinfoMimeTypeGuesser.php @@ -15,6 +15,7 @@ use Exception; use finfo; +use Hypervel\Context\CoroutineContext; use InvalidArgumentException; use LogicException; use RuntimeException; @@ -24,10 +25,7 @@ */ class FileinfoMimeTypeGuesser { - /** - * @var array - */ - 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 @@ -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()); } diff --git a/tests/Support/FileinfoMimeTypeGuesserTest.php b/tests/Support/FileinfoMimeTypeGuesserTest.php new file mode 100644 index 000000000..2705661e0 --- /dev/null +++ b/tests/Support/FileinfoMimeTypeGuesserTest.php @@ -0,0 +1,57 @@ +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))); + } +} diff --git a/tests/Support/Fixtures/test.gif b/tests/Support/Fixtures/test.gif new file mode 100644 index 000000000..b506624ab Binary files /dev/null and b/tests/Support/Fixtures/test.gif differ