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