BookStackApp_BookStack/app/Exports/ZipExports/ZipExportBuilder.php

117 lines
3.2 KiB
PHP

<?php
namespace BookStack\Exports\ZipExports;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
use BookStack\Exceptions\ZipExportException;
use BookStack\Exports\ZipExports\Models\ZipExportBook;
use BookStack\Exports\ZipExports\Models\ZipExportChapter;
use BookStack\Exports\ZipExports\Models\ZipExportPage;
use ZipArchive;
class ZipExportBuilder
{
protected array $data = [];
public function __construct(
protected ZipExportFiles $files,
protected ZipExportReferences $references,
) {
}
/**
* @throws ZipExportException
*/
public function buildForPage(Page $page): string
{
$exportPage = ZipExportPage::fromModel($page, $this->files);
$this->data['page'] = $exportPage;
$this->references->addPage($exportPage);
return $this->build();
}
/**
* @throws ZipExportException
*/
public function buildForChapter(Chapter $chapter): string
{
$exportChapter = ZipExportChapter::fromModel($chapter, $this->files);
$this->data['chapter'] = $exportChapter;
$this->references->addChapter($exportChapter);
return $this->build();
}
/**
* @throws ZipExportException
*/
public function buildForBook(Book $book): string
{
$exportBook = ZipExportBook::fromModel($book, $this->files);
$this->data['book'] = $exportBook;
$this->references->addBook($exportBook);
return $this->build();
}
/**
* @throws ZipExportException
*/
protected function build(): string
{
$this->references->buildReferences($this->files);
$this->data['exported_at'] = date(DATE_ATOM);
$this->data['instance'] = [
'id' => setting('instance-id', ''),
'version' => trim(file_get_contents(base_path('version'))),
];
$zipFile = tempnam(sys_get_temp_dir(), 'bszip-');
$zip = new ZipArchive();
$opened = $zip->open($zipFile, ZipArchive::CREATE);
if ($opened !== true) {
throw new ZipExportException('Failed to create zip file for export.');
}
$zip->addFromString('data.json', json_encode($this->data));
$zip->addEmptyDir('files');
$toRemove = [];
$addedNames = [];
try {
$this->files->extractEach(function ($filePath, $fileRef) use ($zip, &$toRemove, &$addedNames) {
$entryName = "files/$fileRef";
$zip->addFile($filePath, $entryName);
$toRemove[] = $filePath;
$addedNames[] = $entryName;
});
} catch (\Exception $exception) {
// Cleanup the files we've processed so far and respond back with error
foreach ($toRemove as $file) {
unlink($file);
}
foreach ($addedNames as $name) {
$zip->deleteName($name);
}
$zip->close();
unlink($zipFile);
throw new ZipExportException("Failed to add files for ZIP export, received error: " . $exception->getMessage());
}
$zip->close();
foreach ($toRemove as $file) {
unlink($file);
}
return $zipFile;
}
}