3 namespace BookStack\Exports\ZipExports;
5 use BookStack\App\AppVersion;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Chapter;
8 use BookStack\Entities\Models\Page;
9 use BookStack\Exceptions\ZipExportException;
10 use BookStack\Exports\ZipExports\Models\ZipExportBook;
11 use BookStack\Exports\ZipExports\Models\ZipExportChapter;
12 use BookStack\Exports\ZipExports\Models\ZipExportPage;
15 class ZipExportBuilder
17 protected array $data = [];
19 public function __construct(
20 protected ZipExportFiles $files,
21 protected ZipExportReferences $references,
26 * @throws ZipExportException
28 public function buildForPage(Page $page): string
30 $exportPage = ZipExportPage::fromModel($page, $this->files);
31 $this->data['page'] = $exportPage;
33 $this->references->addPage($exportPage);
35 return $this->build();
39 * @throws ZipExportException
41 public function buildForChapter(Chapter $chapter): string
43 $exportChapter = ZipExportChapter::fromModel($chapter, $this->files);
44 $this->data['chapter'] = $exportChapter;
46 $this->references->addChapter($exportChapter);
48 return $this->build();
52 * @throws ZipExportException
54 public function buildForBook(Book $book): string
56 $exportBook = ZipExportBook::fromModel($book, $this->files);
57 $this->data['book'] = $exportBook;
59 $this->references->addBook($exportBook);
61 return $this->build();
65 * @throws ZipExportException
67 protected function build(): string
69 $this->references->buildReferences($this->files);
71 $this->data['exported_at'] = date(DATE_ATOM);
72 $this->data['instance'] = [
73 'id' => setting('instance-id', ''),
74 'version' => AppVersion::get(),
77 $zipFile = tempnam(sys_get_temp_dir(), 'bszip-');
78 $zip = new ZipArchive();
79 $opened = $zip->open($zipFile, ZipArchive::CREATE);
80 if ($opened !== true) {
81 throw new ZipExportException('Failed to create zip file for export.');
84 $zip->addFromString('data.json', json_encode($this->data));
85 $zip->addEmptyDir('files');
91 $this->files->extractEach(function ($filePath, $fileRef) use ($zip, &$toRemove, &$addedNames) {
92 $entryName = "files/$fileRef";
93 $zip->addFile($filePath, $entryName);
94 $toRemove[] = $filePath;
95 $addedNames[] = $entryName;
97 } catch (\Exception $exception) {
98 // Cleanup the files we've processed so far and respond back with error
99 foreach ($toRemove as $file) {
102 foreach ($addedNames as $name) {
103 $zip->deleteName($name);
107 throw new ZipExportException("Failed to add files for ZIP export, received error: " . $exception->getMessage());
112 foreach ($toRemove as $file) {