phpro/resource-stream
phpro/resource-stream is a lightweight PHP library for wrapping resource handles in a consistent stream API. It simplifies reading, writing, seeking, and inspecting file, socket, or in-memory resources, making resource-based I/O easier to abstract and test.
Architecture fit. phpro/resource-stream is a thin PHP resource/stream abstraction layer, not a framework-coupled package. It slots underneath application code rather than replacing Laravel's filesystem stack, so it composes with Illuminate\Filesystem/Flysystem rather than competing with it. Version 1.4.0 adds a ZipStream factory for reading individual zip entries as streams. That is the first genuinely capability-expanding feature in this line and it maps cleanly onto the class of problem a TPM usually owns: large archive ingestion where full extraction to disk or file_get_contents on an entry is not acceptable.
Integration feasibility. Low-to-moderate. The change is additive and minor-versioned (1.3.0 → 1.4.0), so adoption is opt-in per call site. The realistic integration surface is narrow: a service-provider binding or a small wrapper around the factory, consumed inside queued jobs, console commands, or import pipelines. No Laravel version constraint changes are implied by the notes. The main feasibility gate is environmental, not architectural — zip entry streaming will depend on ext-zip (or an equivalent) being present in every runtime that executes the code path, including queue workers and any container images that differ from the web image.
Technical risk. Predominantly low, with two concentrated areas:
ext-zip presence and version parity across web, queue, scheduler, and CI images. This is the most common cause of "works locally, fails in the worker" incidents for this feature class.../), archive bombs (high compression ratio, nested archives), and non-UTF-8 entry name encoding are all caller-side concerns unless the factory documents otherwise. A TPM should assume these are not handled and budget for explicit guards.Everything else — the dependabot actions/checkout 5→6 bump — is CI-only and carries no runtime, API, or deployment consequence.
Key questions for the maintainer/team:
ZipStream factory stream entry contents incrementally, or does it materialise the entry (and/or central directory) in memory? The answer determines whether this solves the large-file problem or merely relocates it.ext-zip versions are in the supported matrix, and is that enforced in composer.json?Stack fit. Good. The package is framework-agnostic and therefore Laravel-version-resilient — it will not pin us to an Illuminate major. It sits alongside, not inside, the storage abstraction: Flysystem remains the right tool for disk-level operations; resource-stream is the right tool when we need a PHP resource we can hand to a filter, a hasher, an HTTP response body, or a chunked reader.
Migration path. No migration is required for existing code — 1.4.0 changes nothing that was already there. The migration is opportunistic: identify call sites that currently do ZipArchive::extractTo() into a temp directory or getFromName() into a string, and convert them one at a time to the streaming factory. Each conversion is independently revertible, which keeps blast radius per change small.
Compatibility. Confirm three things before merging the first call site: (a) ext-zip in every runtime image, (b) the package's PHP constraint against our oldest supported runtime, (c) behaviour under our existing composer.lock — a minor bump plus its transitive tree should be reviewed as a single diff rather than assumed inert. Watch for a second zip implementation already in the dependency graph (Flysystem's zip adapter, maennchen/zipstream-php for writing, etc.); having two zip code paths is a maintainability cost worth naming early.
Sequencing.
ZipEntryReader) that wraps the factory and owns the validation guards. All application code depends on the helper, never the package directly — this is the hedge that makes a future package swap or abandonment cheap.Deliberately do not sequence this as a big-bang replacement of all zip handling.
Maintenance. Low ongoing cost. Small, focused dependency; semver-respecting releases; the only 1.4.0 maintenance item is the CI action bump, which the maintainers handled themselves. Our cost is the wrapper we own plus a periodic composer outdated review. The real maintenance question is bus factor: this is a small-maintainer package, so the wrapper abstraction is not optional hygiene — it is the exit strategy.
Support. Community-supported, no commercial backing. Internal expertise required is modest (one engineer comfortable with PHP streams can own it), but that person should be named. Document the wrapper's contract internally so support does not depend on reading package source during an incident.
Scaling. This is where the feature earns its place. Streaming zip entries converts a peak-memory profile proportional to archive size into one proportional to chunk size. On queue workers with fixed memory limits, that is the difference between a concurrency setting of 1 and a concurrency setting of N, and it removes temp-disk pressure as a scaling constraint. Note the counterweight: streaming is I/O-bound on the source file, so if the archive lives on object storage, per-entry ranged reads may be slower than a single bulk download. Benchmark against the actual storage backend, not local disk.
Failure modes to plan for.
ext-zip in a worker image — fails at runtime, not deploy time. Mitigate with a startup/health check, not just CI.Ramp-up. Low — a competent PHP engineer is productive in under a day, and the wrapper means most of the team never touches the package API directly. Budget instead for the non-obvious learning: the team needs to internalise that streaming changes the error model (failures arrive mid-iteration, partial output is possible) and the security model (untrusted archives are now our problem). Those two shifts, not the API, are what cause production incidents after adoption.
TPM recommendation. Adopt, gated on the spike in step 1 and on answers to key questions 1 and 3. The feature is genuinely useful, the release is low-risk, and the wrapper strategy caps the downside. Do not adopt on the strength of the release note alone — the memory characteristics and the sanitisation posture are the two facts that determine whether this delivers value or merely moves the problem.
How can I help you explore Laravel packages today?