Entry Options
What can be set on a single entry, whatever it was added from.
Customizing Files
You can pass a callback as the last argument to any of the from* methods to customize file-specific options.
use ExeQue\ZipStream\Content\LocalFile;
Zip::fromLocal('/path/file.txt', 'file.txt', function (LocalFile $file) {
$file->comment('This is a important file')
->deflate()
->deflateLevel(9);
});Skipping Verification
Every entry that can be checked is, as it is added: fromDisk() asks the disk whether the file is there, and fromLocal() stats it. That is one request per entry on a remote disk - a HEAD against S3 for every file, paid before a byte is streamed - and it is what turns a missing file into a FileNotFoundException at composition time rather than a broken archive later.
For an archive of hundreds of entries you already trust, that is the difference between hundreds of requests and none.
Zip::withoutVerification()->fromDisk('s3', 'huge/listing.csv');fromDiskDirectory() and fromLocalDirectory() skip it on their own, since the listing they walk is already proof. An entry that disappears between verification and streaming still raises FileUnavailableException - see Handling errors.
Entry Sizes
Telling the package how large an entry is turns a silently truncated file into a catchable error. When a remote body (S3, HTTP) dies mid-read, fread() returns '' rather than false, the read loop simply ends, and the entry is closed as if it were complete. With exactSize() set, zipstream-php throws FileSizeIncorrectException instead, which is routed to ProcessError (see Handling errors).
Zip::store()
->fromDisk('s3', $media->path, $media->name, function (DiskFile $file) use ($media) {
$file->exactSize($media->size);
});RawdefaultsexactSizetostrlen()when the content is a string.LocalFiledefaults it tofilesize().DiskFilehas no default — resolving it would cost aHEADrequest per entry. Supply it from your own metadata, as above.maxSize()caps how much is read from an entry.- Pass
nullto opt out (e.g. a log file that legitimately grows while it is being streamed).
Size limits only apply to stored entries.
zipstream-phpends its read loop as soon asexactSize/maxSizeis reached, which happens beforefeof(), sodeflate_add()is never called withZLIB_FINISHand the buffered compressed tail is dropped. To avoid producing empty entries, both values are ignored unless the entry's effective compression method isCompressionMethod::STORE. Use->store()when you want short-read detection — which is the right choice for already-compressed media anyway.
Entry Sizes
Telling the package how large an entry is turns a silently truncated file into a catchable error. When a remote body (S3, HTTP) dies mid-read, fread() returns '' rather than false, the read loop simply ends, and the entry is closed as if it were complete. With exactSize() set, zipstream-php throws FileSizeIncorrectException instead, which is routed to ProcessError (see Handling errors).
Zip::store()
->fromDisk('s3', $media->path, $media->name, function (DiskFile $file) use ($media) {
$file->exactSize($media->size);
});RawdefaultsexactSizetostrlen()when the content is a string.LocalFiledefaults it tofilesize().DiskFilehas no default — resolving it would cost aHEADrequest per entry. Supply it from your own metadata, as above.maxSize()caps how much is read from an entry.- Pass
nullto opt out (e.g. a log file that legitimately grows while it is being streamed).
Size limits only apply to stored entries.
zipstream-phpends its read loop as soon asexactSize/maxSizeis reached, which happens beforefeof(), sodeflate_add()is never called withZLIB_FINISHand the buffered compressed tail is dropped. To avoid producing empty entries, both values are ignored unless the entry's effective compression method isCompressionMethod::STORE. Use->store()when you want short-read detection — which is the right choice for already-compressed media anyway.
Recognising an Entry Again
An entry can carry whatever the application needs to identify it, handed back on every event about it - which saves keeping a map from the path inside the archive back to a record:
Zip::fromDisk('s3', $media->path, $media->name, fn (DiskFile $file) => $file->context(['media' => $media->id]));
Zip::on(fn (ProcessError $event) => Log::error('Entry failed', $event->context->entryData()));Raw, LocalFile, DiskFile and Directory all take one. An entry of your own does too, by implementing HasContext - or using the InteractsWithContext trait. See Context.
Skipping Verification
Every entry that can be checked is, as it is added: fromDisk() asks the disk whether the file is there, and fromLocal() stats it. That is one request per entry on a remote disk - a HEAD against S3 for every file, paid before a byte is streamed - and it is what turns a missing file into a FileNotFoundException at composition time rather than a broken archive later.
For an archive of hundreds of entries you already trust, that is the difference between hundreds of requests and none.
Zip::withoutVerification()->fromDisk('s3', 'huge/listing.csv');fromDiskDirectory() and fromLocalDirectory() skip it on their own, since the listing they walk is already proof. An entry that disappears between verification and streaming still raises FileUnavailableException - see Handling errors.
Stream Ownership
The package closes the stream an entry hands it, as soon as that entry has been written to the archive. zipstream-php never calls fclose(), and entries are held for the lifetime of the archive — so an entry that memoises its own handle would otherwise keep it open for every remaining entry. An archive of N files would hold N concurrent file handles or S3 connections.
That means the common implementation is safe to write:
class Media extends Model implements StreamableToZip
{
private $handle = null;
public function stream()
{
return $this->handle ??= Storage::disk($this->disk)->readStream($this->path);
}
}If stream() returns a resource that was opened elsewhere and is still needed afterwards, implement RetainsStream to keep it open:
use ExeQue\ZipStream\Contracts\RetainsStream;
class BorrowedHandle implements StreamableToZip, RetainsStream
{
// ...
}Raw implements it already — its content is supplied by the caller, so the caller keeps ownership:
$handle = fopen('report.csv', 'rb');
Zip::fromRaw('report.csv', $handle)->saveToLocal($path);
fclose($handle); // still yours to closeNext: Output - where the archive goes, and Events - what it reports while it works.
Back to the documentation index.
Next: Output - where the archive goes.
Back to the documentation index.