igorw/file-serve-bundle
Symfony bundle for serving static files through your application, with efficient delivery and support for web-server file serving. Handy for protected downloads and streaming files without exposing real paths on disk.
Architecture fit — poor as a dependency, strong as a pattern. igorw/file-serve-bundle is a Symfony2 bundle, not a Laravel package. It ships a Bundle subclass, a DI container extension, and a kernel request listener — constructs Laravel has no equivalent for. There is no service provider, no facade, no config publish tag, and no Illuminate coupling anywhere in the source. Expect zero drop-in code reuse. What is reusable is the design: authorize the request in PHP, then hand the byte transfer to the web server via X-Sendfile (Apache + mod_xsendfile) or X-Accel-Redirect (nginx internal location), so PHP-FPM never holds the file in memory.
Integration feasibility — effectively blocked. composer require would attempt to resolve Symfony 2.x-era constraints (symfony/http-kernel, symfony/http-foundation, symfony/event-dispatcher) against Laravel's own Symfony 6/7 dependencies. The realistic outcomes are a hard resolution failure or a downgrade cascade that breaks the framework. Even in a legacy Laravel 4/5 app this is a non-starter. Treat the repository as documentation, not a dependency.
Technical risk — abandonment is the dominant risk. Last meaningful activity is the Symfony 2.0/2.1 era (~2012–2013); Symfony 2 reached EOL in November 2019. There are 0 dependents, meaning essentially no field-testing or public bug surface. No security advisories will ever be issued. Any path-traversal, header-injection, or URL-encoding defect in the original logic becomes our defect the moment we copy it. Mitigant: MIT license permits clean-room reimplementation of the ~150–250 LOC of logic with our own test suite, which is what I recommend.
Key questions for the team:
internal locations or mod_xsendfile?response()->file() or signed URLs suffice.X-Accel-Redirect, producing empty 200s.Stack fit — reference implementation only. We are not integrating the bundle; we are porting its contract into a first-party Laravel construct. The port is small: a ProtectedFileController (or middleware) that resolves an authorized path against a configured root, then returns a BinaryFileResponse-shaped response carrying the offload header.
Recommended migration path (in preference order):
URL::temporarySignedRoute() / S3 pre-signed URLs — no web-server changes, no PHP file I/O, CDN-friendly. Best fit if the assets can move.internal + X-Accel-Redirect — a driver behind an interface (FileDeliveryDriver), with the nginx location alias mapping kept in config parity with the Laravel disk root.mod_xsendfile — same interface, different header, with a startup assertion that the module is loaded.response()->file() / streamDownload() — the dev/test and small-file fallback; keeps local environments working without nginx config.Compatibility. Target PHP 8.2+ and Laravel 10/11/12. Bind the driver by environment (local → streamed response, production → nginx). The single highest-risk compatibility detail is path parity: the URI component after X-Accel-Redirect: must resolve to the same inode as the Laravel-side path, with matching trailing-slash and percent-encoding behavior. Encode that parity in a feature test, not a runbook.
Sequencing:
internal location in staging; prove a handcrafted header serves a file.Do not vendor the repository. If specific logic is useful, re-derive it with attribution in a comment; do not fork and do not depend.
Maintenance. Reimplemented natively, ongoing maintenance is near-zero: the code is ~100 lines of our own, exercised by our own tests, and depends only on stable Laravel/Symfony HTTP primitives that the framework maintains for us. Vendored or forked, it becomes permanently orphaned code with no upstream to rebase against — a guaranteed future removal project.
Support. There is no community around this package: 164 stars, no active issues triage, no documentation beyond a 2012 README. Internal ownership must be explicit (platform team for nginx config, application team for the driver). Do not let the "0 dependents" signal be read as "low risk" — it means no one has found the sharp edges yet.
Scaling. This is where the package's high opportunity score is earned. Delegating transfer to the web server removes file bytes from the PHP-FPM worker lifecycle: workers return to the pool in milliseconds instead of blocking for the duration of a large download, memory_limit no longer sizes to the largest asset, and the kernel's zero-copy sendfile path applies. For a Laravel app serving protected media or large exports, this is a genuine capacity multiplier at near-zero infrastructure cost. It scales badly only if we stop at a header shim and break Range requests, which forces clients into full re-downloads.
Failure modes to design against:
internal directive → protected files become directly and publicly fetchable. This is the catastrophic one; it deserves a deploy-time check and a CI smoke test asserting a raw public URL returns 404.X-Accel-Redirect handles Range natively; response()->file() needs BinaryFileResponse::setAutoEtag/range support verified. Add a test asserting 206 on a ranged request.mod_xsendfile, an unguarded implementation loads the whole file into PHP memory. Fail loudly at boot rather than degrade quietly..., null bytes, and double-encoded sequences.Ramp-up. One engineer, roughly 1–2 days including tests, for the driver and controller. The real organizational cost is elsewhere: the nginx internal location is platform-team-owned config, so this work crosses a team boundary and needs a coordinated change window. If that coordination is expensive, the signed-URL route is faster and removes the dependency entirely — which is my recommendation unless assets must stay on local disk.
How can I help you explore Laravel packages today?