*/ final class FileSystemCache implements Cache { private const GENERATED_MESSAGE = 'Generated by ' . self::class; public function __construct( private string $cacheDir, ) {} /** @internal */ public function get(string $key, mixed ...$arguments): mixed { $filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php'; if (! file_exists($filename)) { return null; } try { return (require $filename)(...$arguments); // @phpstan-ignore callable.nonCallable } catch (Error) { throw new CorruptedCompiledPhpCacheFile($filename); } } /** @internal */ public function set(string $key, CacheEntry $entry): void { $tmpDir = $this->cacheDir . DIRECTORY_SEPARATOR . '.valinor.tmp'; $filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php'; if (! is_dir($tmpDir) && ! @mkdir($tmpDir, 0777, true)) { throw new CacheDirectoryNotWritable($this->cacheDir); } /** @infection-ignore-all */ $tmpFilename = $tmpDir . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)); try { $code = 'code;" . PHP_EOL; if (! @file_put_contents($tmpFilename, $code)) { throw new CompiledPhpCacheFileNotWritten($tmpFilename); } if (! @rename($tmpFilename, $filename)) { throw new CompiledPhpCacheFileNotWritten($filename); } @chmod($filename, 0666 & ~umask()); } finally { if (file_exists($tmpFilename)) { unlink($tmpFilename); } } } public function clear(): void { if (! is_dir($this->cacheDir)) { return; } $shouldDeleteRootDir = true; /** @var FilesystemIterator $file */ foreach (new FilesystemIterator($this->cacheDir) as $file) { if ($file->getFilename() === '.valinor.tmp') { @rmdir($file->getPathname()); continue; } if (! $file->isFile()) { $shouldDeleteRootDir = false; continue; } $line = $file->openFile()->getCurrentLine(); if (! $line || ! str_contains($line, self::GENERATED_MESSAGE)) { $shouldDeleteRootDir = false; continue; } @unlink($file->getPathname()); } if ($shouldDeleteRootDir) { @rmdir($this->cacheDir); } } }