]> BookStack Code Mirror - bookstack/blob - app/Entities/ExportService.php
Update entities.php
[bookstack] / app / Entities / ExportService.php
1 <?php namespace BookStack\Entities;
2
3 use BookStack\Entities\Repos\EntityRepo;
4 use BookStack\Uploads\ImageService;
5
6 class ExportService
7 {
8
9     protected $entityRepo;
10     protected $imageService;
11
12     /**
13      * ExportService constructor.
14      * @param EntityRepo $entityRepo
15      * @param ImageService $imageService
16      */
17     public function __construct(EntityRepo $entityRepo, ImageService $imageService)
18     {
19         $this->entityRepo = $entityRepo;
20         $this->imageService = $imageService;
21     }
22
23     /**
24      * Convert a page to a self-contained HTML file.
25      * Includes required CSS & image content. Images are base64 encoded into the HTML.
26      * @param \BookStack\Entities\Page $page
27      * @return mixed|string
28      * @throws \Throwable
29      */
30     public function pageToContainedHtml(Page $page)
31     {
32         $this->entityRepo->renderPage($page);
33         $pageHtml = view('pages/export', [
34             'page' => $page
35         ])->render();
36         return $this->containHtml($pageHtml);
37     }
38
39     /**
40      * Convert a chapter to a self-contained HTML file.
41      * @param \BookStack\Entities\Chapter $chapter
42      * @return mixed|string
43      * @throws \Throwable
44      */
45     public function chapterToContainedHtml(Chapter $chapter)
46     {
47         $pages = $this->entityRepo->getChapterChildren($chapter);
48         $pages->each(function ($page) {
49             $page->html = $this->entityRepo->renderPage($page);
50         });
51         $html = view('chapters/export', [
52             'chapter' => $chapter,
53             'pages' => $pages
54         ])->render();
55         return $this->containHtml($html);
56     }
57
58     /**
59      * Convert a book to a self-contained HTML file.
60      * @param Book $book
61      * @return mixed|string
62      * @throws \Throwable
63      */
64     public function bookToContainedHtml(Book $book)
65     {
66         $bookTree = $this->entityRepo->getBookChildren($book, true, true);
67         $html = view('books/export', [
68             'book' => $book,
69             'bookChildren' => $bookTree
70         ])->render();
71         return $this->containHtml($html);
72     }
73
74     /**
75      * Convert a page to a PDF file.
76      * @param Page $page
77      * @return mixed|string
78      * @throws \Throwable
79      */
80     public function pageToPdf(Page $page)
81     {
82         $this->entityRepo->renderPage($page);
83         $html = view('pages/pdf', [
84             'page' => $page
85         ])->render();
86         return $this->htmlToPdf($html);
87     }
88
89     /**
90      * Convert a chapter to a PDF file.
91      * @param \BookStack\Entities\Chapter $chapter
92      * @return mixed|string
93      * @throws \Throwable
94      */
95     public function chapterToPdf(Chapter $chapter)
96     {
97         $pages = $this->entityRepo->getChapterChildren($chapter);
98         $pages->each(function ($page) {
99             $page->html = $this->entityRepo->renderPage($page);
100         });
101         $html = view('chapters/export', [
102             'chapter' => $chapter,
103             'pages' => $pages
104         ])->render();
105         return $this->htmlToPdf($html);
106     }
107
108     /**
109      * Convert a book to a PDF file
110      * @param \BookStack\Entities\Book $book
111      * @return string
112      * @throws \Throwable
113      */
114     public function bookToPdf(Book $book)
115     {
116         $bookTree = $this->entityRepo->getBookChildren($book, true, true);
117         $html = view('books/export', [
118             'book' => $book,
119             'bookChildren' => $bookTree
120         ])->render();
121         return $this->htmlToPdf($html);
122     }
123
124     /**
125      * Convert normal webpage HTML to a PDF.
126      * @param $html
127      * @return string
128      * @throws \Exception
129      */
130     protected function htmlToPdf($html)
131     {
132         $containedHtml = $this->containHtml($html);
133         $useWKHTML = config('snappy.pdf.binary') !== false;
134         if ($useWKHTML) {
135             $pdf = \SnappyPDF::loadHTML($containedHtml);
136             $pdf->setOption('print-media-type', true);
137         } else {
138             $pdf = \DomPDF::loadHTML($containedHtml);
139         }
140         return $pdf->output();
141     }
142
143     /**
144      * Bundle of the contents of a html file to be self-contained.
145      * @param $htmlContent
146      * @return mixed|string
147      * @throws \Exception
148      */
149     protected function containHtml($htmlContent)
150     {
151         $imageTagsOutput = [];
152         preg_match_all("/\<img.*src\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $imageTagsOutput);
153
154         // Replace image src with base64 encoded image strings
155         if (isset($imageTagsOutput[0]) && count($imageTagsOutput[0]) > 0) {
156             foreach ($imageTagsOutput[0] as $index => $imgMatch) {
157                 $oldImgTagString = $imgMatch;
158                 $srcString = $imageTagsOutput[2][$index];
159                 $imageEncoded = $this->imageService->imageUriToBase64($srcString);
160                 if ($imageEncoded === null) {
161                     $imageEncoded = $srcString;
162                 }
163                 $newImgTagString = str_replace($srcString, $imageEncoded, $oldImgTagString);
164                 $htmlContent = str_replace($oldImgTagString, $newImgTagString, $htmlContent);
165             }
166         }
167
168         $linksOutput = [];
169         preg_match_all("/\<a.*href\=(\'|\")(.*?)(\'|\").*?\>/i", $htmlContent, $linksOutput);
170
171         // Replace image src with base64 encoded image strings
172         if (isset($linksOutput[0]) && count($linksOutput[0]) > 0) {
173             foreach ($linksOutput[0] as $index => $linkMatch) {
174                 $oldLinkString = $linkMatch;
175                 $srcString = $linksOutput[2][$index];
176                 if (strpos(trim($srcString), 'http') !== 0) {
177                     $newSrcString = url($srcString);
178                     $newLinkString = str_replace($srcString, $newSrcString, $oldLinkString);
179                     $htmlContent = str_replace($oldLinkString, $newLinkString, $htmlContent);
180                 }
181             }
182         }
183
184         // Replace any relative links with system domain
185         return $htmlContent;
186     }
187
188     /**
189      * Converts the page contents into simple plain text.
190      * This method filters any bad looking content to provide a nice final output.
191      * @param Page $page
192      * @return mixed
193      */
194     public function pageToPlainText(Page $page)
195     {
196         $html = $this->entityRepo->renderPage($page);
197         $text = strip_tags($html);
198         // Replace multiple spaces with single spaces
199         $text = preg_replace('/\ {2,}/', ' ', $text);
200         // Reduce multiple horrid whitespace characters.
201         $text = preg_replace('/(\x0A|\xA0|\x0A|\r|\n){2,}/su', "\n\n", $text);
202         $text = html_entity_decode($text);
203         // Add title
204         $text = $page->name . "\n\n" . $text;
205         return $text;
206     }
207
208     /**
209      * Convert a chapter into a plain text string.
210      * @param \BookStack\Entities\Chapter $chapter
211      * @return string
212      */
213     public function chapterToPlainText(Chapter $chapter)
214     {
215         $text = $chapter->name . "\n\n";
216         $text .= $chapter->description . "\n\n";
217         foreach ($chapter->pages as $page) {
218             $text .= $this->pageToPlainText($page);
219         }
220         return $text;
221     }
222
223     /**
224      * Convert a book into a plain text string.
225      * @param Book $book
226      * @return string
227      */
228     public function bookToPlainText(Book $book)
229     {
230         $bookTree = $this->entityRepo->getBookChildren($book, true, true);
231         $text = $book->name . "\n\n";
232         foreach ($bookTree as $bookChild) {
233             if ($bookChild->isA('chapter')) {
234                 $text .= $this->chapterToPlainText($bookChild);
235             } else {
236                 $text .= $this->pageToPlainText($bookChild);
237             }
238         }
239         return $text;
240     }
241 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.