rekalogika/file-server
A file server for Laravel that streams files from local or remote storage through controlled HTTP endpoints, with access control, range requests, caching headers, and clean URLs. Deliver private downloads, images, and media without exposing storage paths.
Install alongside the core file package. rekalogika/file-server is a companion to rekalogika/file (and almost certainly rekalogika/file-bundle / rekalogika/temporary-url). Install it with the rest of the stack, not in isolation:
composer require rekalogika/file-server
Because the package is a subtree split ([READ-ONLY]), pin to a known-good tag and expect the real docs to live in the monorepo, not in this repository's README.
Confirm the bundle and routes. With Symfony Flex the bundle should auto-register in config/bundles.php. Check that the package ships a routing file and that it is loaded (either via Flex recipe or config/routes/rekalogika_file_server.yaml). If nothing is served, this is the first place to look.
Find the config. Inspect vendor/rekalogika/file-server/ for DependencyInjection/Configuration.php and the bundle class. That file is the authoritative reference for the signing secret, default TTL, route prefix, and controller/service aliases — more reliable than any online doc for a 1-star package.
First use case: hand out a temporary URL for a private file. The whole point of the package is to turn a FileInterface (stored outside the webroot, on S3, or in any storage adapter) into an HTTP URL the browser can fetch without exposing storage credentials:
public function download(FileInterface $file, FileServerInterface $fileServer): JsonResponse
{
$url = $fileServer->createTemporaryUrl($file, new \DateInterval('PT15M'));
return $this->json(['url' => (string) $url]);
}
Exact method names may differ — verify against vendor/ before committing to an interface in your own code.
$this->generateUrl('...')) skips the signature and will 403 at the resource controller.FileUrlProvider interface in your domain and adapt the package service inside it. Given the package's maturity, this is cheap insurance if you need to swap it out later.DateInterval (or TTL seconds) at call time rather than relying on a global default. Different use cases want different windows: inline previews minutes, email links hours/days.file_url(file, ttl) filter/twig extension that calls your provider. This keeps templates away from the package API and lets you add logging or metrics in one place.url, expiresAt) from your provider so callers can put expiresAt in API responses and let clients refresh proactively.FileInterface as the input and the URL as the output. Your application code should not know or care whether the backing storage is local, S3, or something else — that's the value of layering this over rekalogika/file.GET /files/{id}/url that remints a URL for an authenticated user; the browser calls it when a previously issued URL is close to expiry. This is the most common real-world pattern for long sessions.security.yaml firewall. Keep those two concerns in separate route prefixes.StreamedResponse / BinaryFileResponse from the file-server controller, not something your app buffers. If you need custom headers (Content-Disposition filename, cache-control), check whether the package exposes options or whether you need to wrap the response.[READ-ONLY] is literal. Do not open issues or PRs against this repository; the canonical source is in the rekalogika/file monorepo. Any patches you make locally need to be reapplied after upgrades — prefer configuration over forking.X-Forwarded-Proto/Host are trusted in Symfony, otherwise generated URLs will be http:// behind an https:// front end.dump() output. Set short TTLs for anything that could end up pasted into chat.text/html is an XSS vector. Prefer Content-Disposition: attachment for untrusted files, and set X-Content-Type-Options: nosniff. Check what the package sets by default and override only where you can prove it's safe.Response body will break scrubbing in media players.file_get_contents() on a 2 GB file will kill the request. Confirm the served response is streaming, and check PHP-FPM memory_limit and nginx proxy_buffering / fastcgi_buffering settings.Cache-Control: private, max-age=<short> or no-store. A public CDN caching a signed URL serves it to whoever asks — effectively bypassing expiry.FileInterface is looked up from the URL), and the response factory. Register a decorator for those services in services.yaml rather than modifying vendor code.composer.json, add a smoke test that mints a URL and fetches it, and read the source before each upgrade.How can I help you explore Laravel packages today?