container = $container; $this->finder = $finder; $this->translator = $translator; } /** * Invoke the ZipHandler. * * @param \Slim\Psr7\Request $request * @param \Slim\Psr7\Response $response * * @return \Psr\Http\Message\ResponseInterface */ public function __invoke(Request $request, Response $response): ResponseInterface { $path = $request->getQueryParams()['zip']; if (! $this->container->get('zip_downloads') || ! realpath($path)) { return $response->withStatus(404, $this->translator->trans('error.file_not_found')); } $response->getBody()->write($this->createZip($path)->getContents()); return $response->withHeader('Content-Type', 'application/zip') ->withHeader('Content-Disposition', sprintf( 'attachment; filename="%s.zip"', $this->generateFileName($path) )); } /** * Create a zip file from a directory. * * @param string $path * * @return \App\TemporaryFile */ protected function createZip(string $path): TemporaryFile { $zip = new ZipArchive; $zip->open((string) $tempFile = new TemporaryFile( $this->container->get('cache_path') ), ZipArchive::CREATE | ZipArchive::OVERWRITE); foreach ($this->finder->in($path)->files() as $file) { $zip->addFile($file->getRealPath(), $this->stripPath($file, $path)); } $zip->close(); return $tempFile; } /** * Return the path to a file with the preceding root path stripped. * * @param \Symfony\Component\Finder\SplFileInfo $file * @param string $path * * @return string */ protected function stripPath(SplFileInfo $file, string $path): string { $pattern = sprintf( '/^%s%s?/', preg_quote($path, '/'), preg_quote(DIRECTORY_SEPARATOR, '/') ); return preg_replace($pattern, '', $file->getPathname()); } /** * Generate the file name for a path. * * @param string $path * * @return string */ protected function generateFileName(string $path): string { $filename = Str::explode($path, DIRECTORY_SEPARATOR)->last(); return $filename == '.' ? 'Home' : $filename; } }