0 && $size < 4 * 1000 * 1000 * 1000 && $numberOfFiles < 65536) { $this->streamerInstance = new ZipStreamer(['zip64' => false]); } elseif ($request->isUserAgent($this->preferTarFor)) { $this->streamerInstance = new TarStreamer(); } else { $this->streamerInstance = new ZipStreamer(['zip64' => PHP_INT_SIZE !== 4]); } } /** * Send HTTP headers * @param string $name */ public function sendHeaders($name) { header('X-Accel-Buffering: no'); $extension = $this->streamerInstance instanceof ZipStreamer ? '.zip' : '.tar'; $fullName = $name . $extension; $this->streamerInstance->sendHeaders($fullName); } /** * Stream directory recursively * * @throws NotFoundException * @throws NotPermittedException * @throws InvalidPathException */ public function addDirRecursive(string $dir, string $internalDir = ''): void { $dirname = basename($dir); $rootDir = $internalDir . $dirname; if (!empty($rootDir)) { $this->streamerInstance->addEmptyDir($rootDir); } $internalDir .= $dirname . '/'; // prevent absolute dirs $internalDir = ltrim($internalDir, '/'); $userFolder = \OC::$server->get(IRootFolder::class)->get(Filesystem::getRoot()); /** @var Folder $dirNode */ $dirNode = $userFolder->get($dir); $files = $dirNode->getDirectoryListing(); /** @var LoggerInterface $logger */ $logger = \OC::$server->query(LoggerInterface::class); foreach ($files as $file) { if ($file instanceof File) { try { $fh = $file->fopen('r'); if ($fh === false) { $logger->error('Unable to open file for stream: ' . print_r($file, true)); continue; } } catch (NotPermittedException $e) { continue; } $this->addFileFromStream( $fh, $internalDir . $file->getName(), $file->getSize(), $file->getMTime() ); fclose($fh); } elseif ($file instanceof Folder) { if ($file->isReadable()) { $this->addDirRecursive($dir . '/' . $file->getName(), $internalDir); } } } } /** * Add a file to the archive at the specified location and file name. * * @param resource $stream Stream to read data from * @param string $internalName Filepath and name to be used in the archive. * @param int|float $size Filesize * @param int|false $time File mtime as int, or false * @return bool $success */ public function addFileFromStream($stream, string $internalName, int|float $size, $time): bool { $options = []; if ($time) { $options = [ 'timestamp' => $time ]; } if ($this->streamerInstance instanceof ZipStreamer) { return $this->streamerInstance->addFileFromStream($stream, $internalName, $options); } else { return $this->streamerInstance->addFileFromStream($stream, $internalName, $size, $options); } } /** * Add an empty directory entry to the archive. * * @param string $dirName Directory Path and name to be added to the archive. * @return bool $success */ public function addEmptyDir($dirName) { return $this->streamerInstance->addEmptyDir($dirName); } /** * Close the archive. * A closed archive can no longer have new files added to it. After * closing, the file is completely written to the output stream. * @return bool $success */ public function finalize() { return $this->streamerInstance->finalize(); } }