19declare(strict_types=1);
37 protected \ZipArchive
$zip;
53 if (
$options->getZipOutputPath() !==
null &&
$options->getZipOutputName() !==
null) {
54 $this->zip_output_file = $this->ensureDirectorySeperator(
63 $system_limit = (
int) shell_exec(
'ulimit -n') ?: 0;
65 $this->iteration_limit = $system_limit < 10 ? 100 : min(
70 $this->zip = new \ZipArchive();
71 if (!file_exists($this->zip_output_file)) {
72 touch($this->zip_output_file);
76 foreach (
$streams as $path_inside_zip => $stream) {
77 $path_inside_zip = is_int($path_inside_zip) ? basename((
string) $stream->getMetadata(
'uri')) : $path_inside_zip;
78 $this->
addStream($stream, basename($path_inside_zip));
84 if (!$this->zip_opened) {
86 $this->zip_opened = $this->zip->open($this->zip_output_file) ===
true;
88 $this->zip_opened = $this->zip->open($this->zip_output_file, $flags) ===
true;
91 if (!$this->zip_opened) {
92 throw new \Exception(
"cannot open <$this->zip_output_file>\n");
98 $directory = defined(
'CLIENT_DATA_DIR') ?
\CLIENT_DATA_DIR .
'/temp' : sys_get_temp_dir();
99 $tempnam = tempnam($directory,
'zip');
100 if (is_file($tempnam)) {
103 if (is_dir($tempnam)) {
112 register_shutdown_function(
$c);
117 foreach ($this->streams as $path_inside_zip => $stream) {
118 $path = $stream->getMetadata(
'uri');
119 if ($this->store_counter === 0) {
122 if (is_int($path_inside_zip)) {
123 $path_inside_zip = basename((
string)
$path);
126 if (
$path ===
'php://memory') {
127 $this->zip->addFromString($path_inside_zip, (
string) $stream);
129 } elseif (is_file(
$path)) {
130 $this->zip->addFile(
$path, $path_inside_zip);
137 $this->store_counter === $this->iteration_limit
138 || count(get_resources(
'stream')) > ($this->iteration_limit * self::ITERATION_FACTOR)
141 $this->zip_opened =
false;
142 $this->store_counter = 0;
144 $this->store_counter++;
155 $this->zip_opened =
false;
167 if (file_exists($this->zip_output_file)) {
168 unlink($this->zip_output_file);
178 public function addPath(
string $path, ?
string $path_inside_zip =
null): void
180 $path_inside_zip ??= basename(
$path);
185 $this->zip->addEmptyDir(rtrim(dirname($path_inside_zip),
'/') .
'/');
196 if (isset($this->streams[self::DOT_EMPTY])) {
197 unset($this->streams[self::DOT_EMPTY]);
201 $this->streams[$path_inside_zip] = $stream;
204 $this->path_counter === $this->iteration_limit
205 || count(get_resources(
'stream')) > ($this->iteration_limit * self::ITERATION_FACTOR)
209 $this->path_counter = 0;
211 $this->path_counter++;
221 public function addDirectory(
string $directory_to_zip): void
223 $directory_to_zip = $this->normalizePath(rtrim($directory_to_zip,
'/'));
225 $files = new \RecursiveIteratorIterator(
226 new \RecursiveDirectoryIterator($directory_to_zip),
227 \RecursiveIteratorIterator::SELF_FIRST
230 switch ($this->options->getDirectoryHandling()) {
231 case ZipDirectoryHandling::KEEP_STRUCTURE:
235 case ZipDirectoryHandling::ENSURE_SINGLE_TOP_DIR:
236 $prefix = basename($directory_to_zip) .
'/';
237 $pattern =
'/^' . preg_quote($prefix,
'/') .
'/';
241 foreach ($files as $file) {
242 $pathname = $file->getPathname();
243 $path_inside_zip = str_replace($directory_to_zip .
'/',
'', $pathname);
244 if ($pattern !==
null) {
245 $path_inside_zip = $prefix . preg_replace($pattern,
'', $path_inside_zip);
249 if ($file->isDir()) {
251 $sub_items = array_filter(scandir($pathname),
static fn(
$d):
bool => !str_contains(
$d,
'.DS_Store'));
252 if (count($sub_items) === 2) {
253 $this->zip->addEmptyDir($path_inside_zip);
258 if ($this->isPathIgnored($pathname, $this->options)) {
262 $this->
addPath(realpath($pathname), $path_inside_zip);
Stream factory which enables the user to create streams without the knowledge of the concrete class.
static ofResource($resource)
Wraps an already created resource with the stream abstraction.
__construct(protected ZipOptions $options, FileStream ... $streams)
addPath(string $path, ?string $path_inside_zip=null)
destroy()
@description Explicitly close the zip file and remove the file from the filesystem.
maybeOpenZip(int $flags=0)
registerShutdownFunction(\Closure $c)
addStream(FileStream $stream, string $path_inside_zip)
The base interface for all filesystem streams.