1 | <?php |
||||||
2 | /* See license terms in /license.txt */ |
||||||
3 | |||||||
4 | use Chamilo\CoreBundle\Component\Utils\ChamiloApi; |
||||||
5 | use Mpdf\Mpdf; |
||||||
6 | use Mpdf\MpdfException; |
||||||
7 | use Mpdf\Utils\UtfString; |
||||||
8 | use Symfony\Component\DomCrawler\Crawler; |
||||||
9 | |||||||
10 | /** |
||||||
11 | * Class PDF. |
||||||
12 | */ |
||||||
13 | class PDF |
||||||
14 | { |
||||||
15 | /** @var Mpdf */ |
||||||
16 | public $pdf; |
||||||
17 | public $custom_header = []; |
||||||
18 | public $custom_footer = []; |
||||||
19 | public $params = []; |
||||||
20 | public $template; |
||||||
21 | |||||||
22 | /** |
||||||
23 | * Creates the Mpdf object. |
||||||
24 | * |
||||||
25 | * @param string $pageFormat format A4 A4-L see |
||||||
26 | * http://mpdf1.com/manual/index.php?tid=184&searchstring=format |
||||||
27 | * @param string $orientation orientation "P" = Portrait "L" = Landscape |
||||||
28 | * @param array $params |
||||||
29 | * @param Template $template |
||||||
30 | * |
||||||
31 | * @throws MpdfException |
||||||
32 | */ |
||||||
33 | public function __construct( |
||||||
34 | $pageFormat = 'A4', |
||||||
35 | $orientation = 'P', |
||||||
36 | $params = [], |
||||||
37 | $template = null |
||||||
38 | ) { |
||||||
39 | $this->template = $template; |
||||||
40 | /* More info @ http://mpdf1.com/manual/index.php?tid=184&searchstring=Mpdf */ |
||||||
41 | if (!in_array($orientation, ['P', 'L'])) { |
||||||
42 | $orientation = 'P'; |
||||||
43 | } |
||||||
44 | //left, right, top, bottom, margin_header, margin footer |
||||||
45 | |||||||
46 | $params['left'] = $params['left'] ?? 15; |
||||||
47 | $params['right'] = $params['right'] ?? 15; |
||||||
48 | $params['top'] = $params['top'] ?? 30; |
||||||
49 | $params['bottom'] = $params['bottom'] ?? 30; |
||||||
50 | $params['margin_footer'] = $params['margin_footer'] ?? 8; |
||||||
51 | |||||||
52 | $this->params['filename'] = $params['filename'] ?? api_get_local_time(); |
||||||
53 | $this->params['pdf_title'] = $params['pdf_title'] ?? ''; |
||||||
54 | $this->params['pdf_description'] = $params['pdf_description'] ?? ''; |
||||||
55 | $this->params['course_info'] = $params['course_info'] ?? api_get_course_info(); |
||||||
56 | $this->params['session_info'] = $params['session_info'] ?? api_get_session_info(api_get_session_id()); |
||||||
57 | $this->params['course_code'] = $params['course_code'] ?? api_get_course_id(); |
||||||
58 | $this->params['add_signatures'] = $params['add_signatures'] ?? []; |
||||||
59 | $this->params['show_real_course_teachers'] = $params['show_real_course_teachers'] ?? false; |
||||||
60 | $this->params['student_info'] = $params['student_info'] ?? false; |
||||||
61 | $this->params['show_grade_generated_date'] = $params['show_grade_generated_date'] ?? false; |
||||||
62 | $this->params['show_teacher_as_myself'] = $params['show_teacher_as_myself'] ?? true; |
||||||
63 | $localTime = api_get_local_time(); |
||||||
64 | $this->params['pdf_date'] = $params['pdf_date'] ?? api_format_date($localTime, DATE_TIME_FORMAT_LONG); |
||||||
65 | $this->params['pdf_date_only'] = $params['pdf_date'] ?? api_format_date($localTime, DATE_FORMAT_LONG); |
||||||
66 | |||||||
67 | $this->pdf = new Mpdf( |
||||||
68 | [ |
||||||
69 | 'mode' => 'UTF-8', |
||||||
70 | 'format' => $pageFormat, |
||||||
71 | 'default_font_size' => '', |
||||||
72 | 'default_font' => '', |
||||||
73 | 'margin_left' => $params['left'], |
||||||
74 | 'margin_right' => $params['right'], |
||||||
75 | 'margin_top' => $params['top'], |
||||||
76 | 'margin_bottom' => $params['bottom'], |
||||||
77 | 'margin_header' => 8, |
||||||
78 | 'margin_footer' => 8, |
||||||
79 | 'orientation' => $orientation, |
||||||
80 | 'tempDir' => api_get_path(SYS_ARCHIVE_PATH).'mpdf/', |
||||||
81 | ] |
||||||
82 | ); |
||||||
83 | |||||||
84 | $this->pdf->margin_footer = $params['margin_footer']; |
||||||
85 | |||||||
86 | // Default value is 96 set in the mpdf library file config.php |
||||||
87 | $value = api_get_configuration_value('pdf_img_dpi'); |
||||||
88 | if (!empty($value)) { |
||||||
89 | $this->pdf->img_dpi = (int) $value; |
||||||
90 | } |
||||||
91 | } |
||||||
92 | |||||||
93 | /** |
||||||
94 | * Export the given HTML to PDF, using a global template. |
||||||
95 | * |
||||||
96 | * @uses \export/table_pdf.tpl |
||||||
97 | * |
||||||
98 | * @param string $content |
||||||
99 | * @param bool|false $saveToFile |
||||||
100 | * @param bool|false $returnHtml |
||||||
101 | * @param bool $addDefaultCss (bootstrap/default/base.css) |
||||||
102 | * @param array |
||||||
103 | * |
||||||
104 | * @throws MpdfException |
||||||
105 | * |
||||||
106 | * @return string|null |
||||||
107 | */ |
||||||
108 | public function html_to_pdf_with_template( |
||||||
109 | $content, |
||||||
110 | $saveToFile = false, |
||||||
111 | $returnHtml = false, |
||||||
112 | $addDefaultCss = false, |
||||||
113 | $extraRows = [], |
||||||
114 | $outputMode = 'D', |
||||||
115 | $fileToSave = null |
||||||
116 | ) { |
||||||
117 | if (empty($this->template)) { |
||||||
118 | $tpl = new Template('', false, false, false, false, true, false); |
||||||
119 | } else { |
||||||
120 | $tpl = $this->template; |
||||||
121 | } |
||||||
122 | |||||||
123 | // Assignments |
||||||
124 | $tpl->assign('pdf_content', $content); |
||||||
125 | |||||||
126 | // Showing only the current teacher/admin instead the all teacher list name see BT#4080 |
||||||
127 | $teacher_list = null; |
||||||
128 | if (isset($this->params['show_real_course_teachers']) && |
||||||
129 | $this->params['show_real_course_teachers'] |
||||||
130 | ) { |
||||||
131 | if (isset($this->params['session_info']) && |
||||||
132 | !empty($this->params['session_info']) |
||||||
133 | ) { |
||||||
134 | $teacher_list = SessionManager::getCoachesByCourseSessionToString( |
||||||
135 | $this->params['session_info']['id'], |
||||||
136 | $this->params['course_info']['real_id'] |
||||||
137 | ); |
||||||
138 | } else { |
||||||
139 | $teacher_list = CourseManager::getTeacherListFromCourseCodeToString( |
||||||
140 | $this->params['course_code'] |
||||||
141 | ); |
||||||
142 | } |
||||||
143 | } else { |
||||||
144 | $user_info = api_get_user_info(); |
||||||
145 | if ($this->params['show_teacher_as_myself']) { |
||||||
146 | $teacher_list = $user_info['complete_name']; |
||||||
147 | } |
||||||
148 | } |
||||||
149 | |||||||
150 | $tpl->assign('pdf_course', $this->params['course_code']); |
||||||
151 | $tpl->assign('pdf_course_info', $this->params['course_info']); |
||||||
152 | $tpl->assign('pdf_session_info', $this->params['session_info']); |
||||||
153 | $tpl->assign('pdf_date', $this->params['pdf_date']); |
||||||
154 | $tpl->assign('pdf_date_only', $this->params['pdf_date_only']); |
||||||
155 | $tpl->assign('pdf_teachers', $teacher_list); |
||||||
156 | $tpl->assign('pdf_title', $this->params['pdf_title']); |
||||||
157 | $tpl->assign('pdf_description', $this->params['pdf_description']); |
||||||
158 | $tpl->assign('pdf_student_info', $this->params['student_info']); |
||||||
159 | $tpl->assign('show_grade_generated_date', $this->params['show_grade_generated_date']); |
||||||
160 | $tpl->assign('add_signatures', $this->params['add_signatures']); |
||||||
161 | $tpl->assign('extra_rows', $extraRows); |
||||||
162 | |||||||
163 | // Getting template |
||||||
164 | $tableTemplate = $tpl->get_template('export/table_pdf.tpl'); |
||||||
165 | $html = $tpl->fetch($tableTemplate); |
||||||
166 | $html = api_utf8_encode($html); |
||||||
167 | |||||||
168 | if ($returnHtml) { |
||||||
169 | return $html; |
||||||
170 | } |
||||||
171 | |||||||
172 | $css = api_get_print_css(); |
||||||
173 | |||||||
174 | self::content_to_pdf( |
||||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||||
175 | $html, |
||||||
176 | $css, |
||||||
177 | $this->params['filename'], |
||||||
178 | $this->params['course_code'], |
||||||
179 | $outputMode, |
||||||
180 | $saveToFile, |
||||||
181 | $fileToSave, |
||||||
182 | $returnHtml, |
||||||
183 | $addDefaultCss |
||||||
184 | ); |
||||||
185 | } |
||||||
186 | |||||||
187 | /** |
||||||
188 | * Converts HTML files to PDF. |
||||||
189 | * |
||||||
190 | * @param mixed $html_file_array could be a html file path or an array |
||||||
191 | * with paths example: |
||||||
192 | * /var/www/myfile.html or array('/myfile.html','myotherfile.html') or |
||||||
193 | * even an indexed array with both 'title' and 'path' indexes |
||||||
194 | * for each element like |
||||||
195 | * array( |
||||||
196 | * 0 => array('title'=>'Hello','path'=>'file.html'), |
||||||
197 | * 1 => array('title'=>'Bye','path'=>'file2.html') |
||||||
198 | * ); |
||||||
199 | * @param string $pdf_name pdf name |
||||||
200 | * @param null $course_code (if you are using html that are located |
||||||
0 ignored issues
–
show
|
|||||||
201 | * in the document tool you must provide this) |
||||||
202 | * @param bool $print_title add title |
||||||
203 | * @param bool $complete_style show header and footer if true |
||||||
204 | * @param bool $addStyle |
||||||
205 | * @param string $mainTitle |
||||||
206 | * @param bool $generateToFile Optional. When it is TRUE, then the output file is move to app/cache |
||||||
207 | * |
||||||
208 | * @throws MpdfException |
||||||
209 | * |
||||||
210 | * @return false|null |
||||||
211 | */ |
||||||
212 | public function html_to_pdf( |
||||||
213 | $html_file_array, |
||||||
214 | $pdf_name = '', |
||||||
215 | $course_code = null, |
||||||
216 | $print_title = false, |
||||||
217 | $complete_style = true, |
||||||
218 | $addStyle = true, |
||||||
219 | $mainTitle = '', |
||||||
220 | $generateToFile = false |
||||||
221 | ) { |
||||||
222 | if (empty($html_file_array)) { |
||||||
223 | return false; |
||||||
224 | } |
||||||
225 | |||||||
226 | if (is_array($html_file_array)) { |
||||||
227 | if (count($html_file_array) == 0) { |
||||||
228 | return false; |
||||||
229 | } |
||||||
230 | } else { |
||||||
231 | if (!file_exists($html_file_array)) { |
||||||
232 | return false; |
||||||
233 | } |
||||||
234 | // Converting the string into an array |
||||||
235 | $html_file_array = [$html_file_array]; |
||||||
236 | } |
||||||
237 | |||||||
238 | if (!empty($course_code)) { |
||||||
239 | $course_data = api_get_course_info($course_code); |
||||||
240 | } else { |
||||||
241 | $course_data = api_get_course_info(); |
||||||
242 | } |
||||||
243 | |||||||
244 | // Clean styles and javascript document |
||||||
245 | $clean_search = [ |
||||||
246 | '@<script[^>]*?>.*?</script>@si', |
||||||
247 | '@<style[^>]*?>.*?</style>@si', |
||||||
248 | ]; |
||||||
249 | |||||||
250 | // Formatting the pdf |
||||||
251 | self::format_pdf($course_data, $complete_style); |
||||||
0 ignored issues
–
show
The method
PDF::format_pdf() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
252 | |||||||
253 | $counter = 1; |
||||||
254 | foreach ($html_file_array as $file) { |
||||||
255 | // Add a page break per file |
||||||
256 | $page_break = '<pagebreak>'; |
||||||
257 | if ($counter == count($html_file_array)) { |
||||||
258 | $page_break = ''; |
||||||
259 | } |
||||||
260 | |||||||
261 | // if the array provided contained subarrays with 'title' entry, |
||||||
262 | // then print the title in the PDF |
||||||
263 | if (is_array($file) && isset($file['title'])) { |
||||||
264 | $html_title = $file['title']; |
||||||
265 | $file = $file['path']; |
||||||
266 | } else { |
||||||
267 | //we suppose we've only been sent a file path |
||||||
268 | $html_title = basename($file); |
||||||
269 | } |
||||||
270 | |||||||
271 | $counter++; |
||||||
272 | |||||||
273 | if (empty($file) && !empty($html_title)) { |
||||||
274 | // this is a chapter, print title & skip the rest |
||||||
275 | if ($counter === 2 && !empty($mainTitle)) { |
||||||
276 | $this->pdf->WriteHTML( |
||||||
277 | '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>' |
||||||
278 | ); |
||||||
279 | } |
||||||
280 | if ($print_title) { |
||||||
281 | $this->pdf->WriteHTML( |
||||||
282 | '<html><body><h3>'.$html_title.'</h3></body></html>'.$page_break |
||||||
283 | ); |
||||||
284 | } |
||||||
285 | continue; |
||||||
286 | } else { |
||||||
287 | if ($counter === 2 && !empty($mainTitle)) { |
||||||
288 | $this->pdf->WriteHTML( |
||||||
289 | '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>' |
||||||
290 | ); |
||||||
291 | } |
||||||
292 | } |
||||||
293 | |||||||
294 | if (!file_exists($file)) { |
||||||
295 | continue; |
||||||
296 | } |
||||||
297 | |||||||
298 | if ($addStyle) { |
||||||
299 | $basicStyles = [ |
||||||
300 | api_get_path(SYS_PATH).'web/assets/bootstrap/dist/css/bootstrap.min.css', |
||||||
301 | api_get_path(SYS_PATH).'web/css/base.css', |
||||||
302 | api_get_path(SYS_PATH).'web/css/themes/'.api_get_visual_theme().'/default.css', |
||||||
303 | api_get_print_css(false), |
||||||
304 | ]; |
||||||
305 | foreach ($basicStyles as $style) { |
||||||
306 | if (file_exists($style)) { |
||||||
307 | $cssContent = file_get_contents($style); |
||||||
308 | try { |
||||||
309 | @$this->pdf->WriteHTML($cssContent, 1); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
WriteHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
310 | } catch (MpdfException $e) { |
||||||
311 | error_log($e); |
||||||
312 | } |
||||||
313 | } |
||||||
314 | } |
||||||
315 | } |
||||||
316 | |||||||
317 | // it's not a chapter but the file exists, print its title |
||||||
318 | if ($print_title) { |
||||||
319 | @$this->pdf->WriteHTML( |
||||||
320 | '<html><body><h3>'.$html_title.'</h3></body></html>' |
||||||
321 | ); |
||||||
322 | } |
||||||
323 | |||||||
324 | $file_info = pathinfo($file); |
||||||
325 | $extension = $file_info['extension']; |
||||||
326 | |||||||
327 | if (in_array($extension, ['html', 'htm'])) { |
||||||
328 | $dirName = $file_info['dirname']; |
||||||
329 | $filename = $file_info['basename']; |
||||||
330 | $filename = str_replace('_', ' ', $filename); |
||||||
331 | |||||||
332 | if ($extension === 'html') { |
||||||
333 | $filename = basename($filename, '.html'); |
||||||
334 | } elseif ($extension === 'htm') { |
||||||
335 | $filename = basename($filename, '.htm'); |
||||||
336 | } |
||||||
337 | |||||||
338 | $webPath = api_get_path(WEB_PATH); |
||||||
339 | |||||||
340 | $document_html = @file_get_contents($file); |
||||||
341 | $document_html = preg_replace($clean_search, '', $document_html); |
||||||
342 | |||||||
343 | $crawler = new Crawler($document_html); |
||||||
344 | $crawler |
||||||
345 | ->filter('link[rel="stylesheet"]') |
||||||
346 | ->each(function (Crawler $node) use ($webPath) { |
||||||
347 | $linkUrl = $node->link()->getUri(); |
||||||
348 | |||||||
349 | if (!str_starts_with($linkUrl, $webPath)) { |
||||||
350 | $node->getNode(0)->parentNode->removeChild($node->getNode(0)); |
||||||
351 | } |
||||||
352 | }) |
||||||
353 | ; |
||||||
354 | $document_html = $crawler->outerHtml(); |
||||||
355 | |||||||
356 | //absolute path for frames.css //TODO: necessary? |
||||||
357 | $absolute_css_path = api_get_path(WEB_CODE_PATH).'css/'.api_get_setting('stylesheets').'/frames.css'; |
||||||
358 | $document_html = str_replace('href="./css/frames.css"', $absolute_css_path, $document_html); |
||||||
359 | |||||||
360 | if (!empty($course_data['path'])) { |
||||||
361 | $document_html = str_replace('../', '', $document_html); |
||||||
362 | |||||||
363 | // Fix app/upload links convert web to system paths |
||||||
364 | $document_html = str_replace( |
||||||
365 | api_get_path(WEB_UPLOAD_PATH), |
||||||
366 | api_get_path(SYS_UPLOAD_PATH), |
||||||
367 | $document_html |
||||||
368 | ); |
||||||
369 | } |
||||||
370 | |||||||
371 | $document_html = self::fixImagesPaths($document_html, $course_data, $dirName); |
||||||
372 | |||||||
373 | // The library Mpdf expects UTF-8 encoded input data. |
||||||
374 | api_set_encoding_html($document_html, 'UTF-8'); |
||||||
375 | // TODO: Maybe it is better idea the title to be passed through |
||||||
376 | $title = api_get_title_html($document_html, 'UTF-8', 'UTF-8'); |
||||||
377 | // $_GET[] too, as it is done with file name. |
||||||
378 | // At the moment the title is retrieved from the html document itself. |
||||||
379 | if (empty($title)) { |
||||||
380 | $title = $filename; // Here file name is expected to contain ASCII symbols only. |
||||||
381 | } |
||||||
382 | if (!empty($document_html)) { |
||||||
383 | @$this->pdf->WriteHTML($document_html.$page_break); |
||||||
384 | } |
||||||
385 | } elseif (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) { |
||||||
386 | // Images |
||||||
387 | $image = Display::img($file); |
||||||
388 | @$this->pdf->WriteHTML('<html><body>'.$image.'</body></html>'.$page_break); |
||||||
389 | } |
||||||
390 | } |
||||||
391 | if (empty($pdf_name)) { |
||||||
392 | $output_file = 'pdf_'.date('Y-m-d-his').'.pdf'; |
||||||
393 | } else { |
||||||
394 | $pdf_name = api_replace_dangerous_char($pdf_name); |
||||||
395 | $output_file = $pdf_name.'.pdf'; |
||||||
396 | } |
||||||
397 | // F to save the pdf in a file |
||||||
398 | if ($generateToFile) { |
||||||
399 | @$this->pdf->Output( |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
Output() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
400 | api_get_path(SYS_ARCHIVE_PATH).$output_file, |
||||||
401 | 'F' |
||||||
402 | ); |
||||||
403 | } else { |
||||||
404 | @$this->pdf->Output($output_file, 'D'); |
||||||
405 | } |
||||||
406 | |||||||
407 | exit; |
||||||
0 ignored issues
–
show
|
|||||||
408 | } |
||||||
409 | |||||||
410 | /** |
||||||
411 | * Converts a html string to PDF. |
||||||
412 | * |
||||||
413 | * @param string $document_html valid html |
||||||
414 | * @param string $css CSS content of a CSS file |
||||||
415 | * @param string $pdf_name pdf name |
||||||
416 | * @param string $course_code course code |
||||||
417 | * (if you are using html that are located in the document tool you must provide this) |
||||||
418 | * @param string $outputMode the MPDF output mode can be: |
||||||
419 | * @param bool $saveInFile |
||||||
420 | * @param string $fileToSave |
||||||
421 | * @param bool $returnHtml |
||||||
422 | * @param bool $addDefaultCss |
||||||
423 | * @param bool $completeHeader |
||||||
424 | * |
||||||
425 | * @throws MpdfException |
||||||
426 | * |
||||||
427 | * 'I' (print on standard output), |
||||||
428 | * 'D' (download file) (this is the default value), |
||||||
429 | * 'F' (save to local file) or |
||||||
430 | * 'S' (return as a string) |
||||||
431 | * |
||||||
432 | * @return string Web path |
||||||
433 | */ |
||||||
434 | public function content_to_pdf( |
||||||
435 | $document_html, |
||||||
436 | $css = '', |
||||||
437 | $pdf_name = '', |
||||||
438 | $course_code = null, |
||||||
439 | $outputMode = 'D', |
||||||
440 | $saveInFile = false, |
||||||
441 | $fileToSave = null, |
||||||
442 | $returnHtml = false, |
||||||
443 | $addDefaultCss = false, |
||||||
444 | $completeHeader = true |
||||||
445 | ) { |
||||||
446 | $urlAppend = api_get_configuration_value('url_append'); |
||||||
447 | |||||||
448 | if (empty($document_html)) { |
||||||
449 | return false; |
||||||
450 | } |
||||||
451 | |||||||
452 | // clean styles and javascript document |
||||||
453 | $clean_search = [ |
||||||
454 | '@<script[^>]*?>.*?</script>@si', |
||||||
455 | '@<style[^>]*?>.*?</style>@siU', |
||||||
456 | ]; |
||||||
457 | |||||||
458 | // Formatting the pdf |
||||||
459 | $course_data = api_get_course_info($course_code); |
||||||
460 | self::format_pdf($course_data, $completeHeader); |
||||||
0 ignored issues
–
show
The method
PDF::format_pdf() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
461 | $document_html = preg_replace($clean_search, '', $document_html); |
||||||
462 | |||||||
463 | //absolute path for frames.css //TODO: necessary? |
||||||
464 | $absolute_css_path = api_get_path(WEB_CSS_PATH).api_get_setting('stylesheets').'/frames.css'; |
||||||
465 | $document_html = str_replace('href="./css/frames.css"', 'href="'.$absolute_css_path.'"', $document_html); |
||||||
466 | $document_html = str_replace('../../', '', $document_html); |
||||||
467 | $document_html = str_replace('../', '', $document_html); |
||||||
468 | $document_html = str_replace( |
||||||
469 | (empty($urlAppend) ? '' : $urlAppend.'/').'courses/'.$course_code.'/document/', |
||||||
470 | '', |
||||||
471 | $document_html |
||||||
472 | ); |
||||||
473 | |||||||
474 | if (!empty($course_data['path'])) { |
||||||
475 | $document_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document/'; |
||||||
476 | |||||||
477 | $doc = new DOMDocument(); |
||||||
478 | @$doc->loadHTML($document_html); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
loadHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
479 | |||||||
480 | //Fixing only images @todo do the same thing with other elements |
||||||
481 | $elements = $doc->getElementsByTagName('img'); |
||||||
482 | $protocol = api_get_protocol(); |
||||||
483 | $replaced = []; |
||||||
484 | if (!empty($elements)) { |
||||||
485 | foreach ($elements as $item) { |
||||||
486 | $old_src = $item->getAttribute('src'); |
||||||
487 | |||||||
488 | if (in_array($old_src, $replaced)) { |
||||||
489 | continue; |
||||||
490 | } |
||||||
491 | |||||||
492 | if (strpos($old_src, $protocol) === false) { |
||||||
493 | if (strpos($old_src, '/main/default_course_document') === false) { |
||||||
494 | if (strpos($old_src, '/main/inc/lib/') === false && |
||||||
495 | strpos($old_src, '/app/upload/') === false |
||||||
496 | ) { |
||||||
497 | $old_src_fixed = str_replace( |
||||||
498 | api_get_path(REL_COURSE_PATH).$course_data['path'].'/document/', |
||||||
499 | '', |
||||||
500 | $old_src |
||||||
501 | ); |
||||||
502 | $old_src_fixed = str_replace( |
||||||
503 | 'courses/'.$course_data['path'].'/document/', |
||||||
504 | '', |
||||||
505 | $old_src_fixed |
||||||
506 | ); |
||||||
507 | $new_path = $document_path.$old_src_fixed; |
||||||
508 | $document_html = str_replace($old_src, $new_path, $document_html); |
||||||
509 | $replaced[] = $old_src; |
||||||
510 | } |
||||||
511 | } |
||||||
512 | } |
||||||
513 | } |
||||||
514 | } |
||||||
515 | } |
||||||
516 | |||||||
517 | // Use sys path to correct export images |
||||||
518 | $document_html = str_replace( |
||||||
519 | api_get_path(WEB_CODE_PATH).'img/', |
||||||
520 | api_get_path(SYS_CODE_PATH).'img/', |
||||||
521 | $document_html |
||||||
522 | ); |
||||||
523 | |||||||
524 | $theme = api_get_visual_theme(); |
||||||
525 | $document_html = str_replace( |
||||||
526 | api_get_path(WEB_CSS_PATH).'themes/'.$theme, |
||||||
527 | api_get_path(SYS_PUBLIC_PATH).'css/themes/'.$theme, |
||||||
528 | $document_html |
||||||
529 | ); |
||||||
530 | |||||||
531 | $document_html = str_replace(api_get_path(WEB_UPLOAD_PATH), api_get_path(SYS_UPLOAD_PATH), $document_html); |
||||||
532 | $document_html = str_replace(api_get_path(WEB_ARCHIVE_PATH), api_get_path(SYS_ARCHIVE_PATH), $document_html); |
||||||
533 | |||||||
534 | // The library Mpdf expects UTF-8 encoded input data. |
||||||
535 | api_set_encoding_html($document_html, 'UTF-8'); |
||||||
536 | // At the moment the title is retrieved from the html document itself. |
||||||
537 | if ($returnHtml) { |
||||||
538 | return "<style>$css</style>".$document_html; |
||||||
539 | } |
||||||
540 | |||||||
541 | if (!empty($css)) { |
||||||
542 | try { |
||||||
543 | @$this->pdf->WriteHTML($css, 1); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
WriteHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
544 | } catch (MpdfException $e) { |
||||||
545 | error_log($e); |
||||||
546 | } |
||||||
547 | } |
||||||
548 | |||||||
549 | $cssBootstrap = file_get_contents(api_get_path(SYS_PATH).'web/assets/bootstrap/dist/css/bootstrap.min.css'); |
||||||
550 | if ($addDefaultCss) { |
||||||
551 | $cssContent = api_get_print_css(); |
||||||
552 | try { |
||||||
553 | @$this->pdf->WriteHTML($cssBootstrap, 1); |
||||||
554 | @$this->pdf->WriteHTML($cssContent, 1); |
||||||
555 | } catch (MpdfException $e) { |
||||||
556 | error_log($e); |
||||||
557 | } |
||||||
558 | } |
||||||
559 | |||||||
560 | try { |
||||||
561 | @$this->pdf->WriteHTML($document_html); |
||||||
562 | } catch (MpdfException $e) { |
||||||
563 | error_log($e); |
||||||
564 | } |
||||||
565 | |||||||
566 | if (empty($pdf_name)) { |
||||||
567 | $output_file = 'pdf_'.date('Y-m-d-his').'.pdf'; |
||||||
568 | } else { |
||||||
569 | $pdf_name = api_replace_dangerous_char($pdf_name); |
||||||
570 | $output_file = $pdf_name.'.pdf'; |
||||||
571 | } |
||||||
572 | |||||||
573 | if ($outputMode === 'F') { |
||||||
574 | $output_file = api_get_path(SYS_ARCHIVE_PATH).$output_file; |
||||||
575 | } |
||||||
576 | |||||||
577 | if ($saveInFile) { |
||||||
578 | $fileToSave = !empty($fileToSave) ? $fileToSave : api_get_path(SYS_ARCHIVE_PATH).uniqid(); |
||||||
579 | try { |
||||||
580 | @$this->pdf->Output( |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
Output() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
581 | $fileToSave, |
||||||
582 | $outputMode |
||||||
583 | ); // F to save the pdf in a file |
||||||
584 | } catch (MpdfException $e) { |
||||||
585 | error_log($e); |
||||||
586 | } |
||||||
587 | } else { |
||||||
588 | try { |
||||||
589 | @$this->pdf->Output( |
||||||
590 | $output_file, |
||||||
591 | $outputMode |
||||||
592 | ); // F to save the pdf in a file |
||||||
593 | } catch (MpdfException $e) { |
||||||
594 | error_log($e); |
||||||
595 | } |
||||||
596 | } |
||||||
597 | |||||||
598 | if ($outputMode != 'F') { |
||||||
599 | exit; |
||||||
0 ignored issues
–
show
|
|||||||
600 | } |
||||||
601 | |||||||
602 | return $output_file; |
||||||
603 | } |
||||||
604 | |||||||
605 | /** |
||||||
606 | * Gets the watermark from the platform or a course. |
||||||
607 | * |
||||||
608 | * @param string course code (optional) |
||||||
609 | * @param mixed web path of the watermark image, false if there is nothing to return |
||||||
610 | * |
||||||
611 | * @return string |
||||||
612 | */ |
||||||
613 | public static function get_watermark($course_code = null) |
||||||
614 | { |
||||||
615 | $web_path = false; |
||||||
616 | $urlId = api_get_current_access_url_id(); |
||||||
617 | if (!empty($course_code) && api_get_setting('pdf_export_watermark_by_course') === 'true') { |
||||||
618 | $course_info = api_get_course_info($course_code); |
||||||
619 | // course path |
||||||
620 | $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png'; |
||||||
621 | if (file_exists($store_path)) { |
||||||
622 | $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png'; |
||||||
623 | } |
||||||
624 | } else { |
||||||
625 | // course path |
||||||
626 | $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png'; |
||||||
627 | if (file_exists($store_path)) { |
||||||
628 | $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png'; |
||||||
629 | } |
||||||
630 | } |
||||||
631 | |||||||
632 | return $web_path; |
||||||
0 ignored issues
–
show
The expression
return $web_path could also return false which is incompatible with the documented return type string . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled. ![]() |
|||||||
633 | } |
||||||
634 | |||||||
635 | /** |
||||||
636 | * Deletes the watermark from the Platform or Course. |
||||||
637 | * |
||||||
638 | * @param string $course_code course code (optional) |
||||||
639 | * @param mixed web path of the watermark image, false if there is nothing to return |
||||||
640 | * |
||||||
641 | * @return bool |
||||||
642 | */ |
||||||
643 | public static function delete_watermark($course_code = null) |
||||||
644 | { |
||||||
645 | $urlId = api_get_current_access_url_id(); |
||||||
646 | if (!empty($course_code) && api_get_setting('pdf_export_watermark_by_course') == 'true') { |
||||||
647 | $course_info = api_get_course_info($course_code); |
||||||
648 | // course path |
||||||
649 | $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png'; |
||||||
650 | } else { |
||||||
651 | // course path |
||||||
652 | $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png'; |
||||||
653 | } |
||||||
654 | if (file_exists($store_path)) { |
||||||
655 | unlink($store_path); |
||||||
656 | |||||||
657 | return true; |
||||||
658 | } |
||||||
659 | |||||||
660 | return false; |
||||||
661 | } |
||||||
662 | |||||||
663 | /** |
||||||
664 | * Uploads the pdf watermark in the main/default_course_document directory or in the course directory. |
||||||
665 | * |
||||||
666 | * @param string $filename filename |
||||||
667 | * @param string $source_file path of the file |
||||||
668 | * @param string $course_code |
||||||
669 | * |
||||||
670 | * @return mixed web path of the file if sucess, false otherwise |
||||||
671 | */ |
||||||
672 | public static function upload_watermark($filename, $source_file, $course_code = null) |
||||||
673 | { |
||||||
674 | $urlId = api_get_current_access_url_id(); |
||||||
675 | if (!empty($course_code) && api_get_setting('pdf_export_watermark_by_course') == 'true') { |
||||||
676 | $course_info = api_get_course_info($course_code); |
||||||
677 | $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path']; // course path |
||||||
678 | $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/pdf_watermark.png'; |
||||||
679 | } else { |
||||||
680 | $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images'; // course path |
||||||
681 | $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png'; |
||||||
682 | } |
||||||
683 | $course_image = $store_path.'/'.$urlId.'_pdf_watermark.png'; |
||||||
684 | |||||||
685 | if (file_exists($course_image)) { |
||||||
686 | @unlink($course_image); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
unlink() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
687 | } |
||||||
688 | $my_image = new Image($source_file); |
||||||
689 | $result = $my_image->send_image($course_image, -1, 'png'); |
||||||
690 | if ($result) { |
||||||
691 | $result = $web_path; |
||||||
692 | } |
||||||
693 | |||||||
694 | return $result; |
||||||
695 | } |
||||||
696 | |||||||
697 | /** |
||||||
698 | * Returns the default header. |
||||||
699 | */ |
||||||
700 | public function get_header($course_code = null) |
||||||
701 | { |
||||||
702 | /*$header = api_get_setting('pdf_export_watermark_text'); |
||||||
703 | if (!empty($course_code) && api_get_setting('pdf_export_watermark_by_course') == 'true') { |
||||||
704 | $header = api_get_course_setting('pdf_export_watermark_text'); |
||||||
705 | } |
||||||
706 | return $header;*/ |
||||||
707 | } |
||||||
708 | |||||||
709 | /** |
||||||
710 | * Sets the PDF footer. |
||||||
711 | */ |
||||||
712 | public function set_footer() |
||||||
713 | { |
||||||
714 | $this->pdf->defaultfooterfontsize = 12; // in pts |
||||||
715 | $this->pdf->defaultfooterfontstyle = 'B'; // blank, B, I, or BI |
||||||
716 | $this->pdf->defaultfooterline = 1; // 1 to include line below header/above footer |
||||||
717 | |||||||
718 | $view = new Template('', false, false, false, true, false, false); |
||||||
719 | $template = $view->get_template('export/pdf_footer.tpl'); |
||||||
720 | $footerHTML = $view->fetch($template); |
||||||
721 | |||||||
722 | $this->pdf->SetHTMLFooter($footerHTML, 'E'); //Even pages |
||||||
723 | $this->pdf->SetHTMLFooter($footerHTML, 'O'); //Odd pages |
||||||
724 | } |
||||||
725 | |||||||
726 | public function setCertificateFooter() |
||||||
727 | { |
||||||
728 | $this->pdf->defaultfooterfontsize = 12; // in pts |
||||||
729 | $this->pdf->defaultfooterfontstyle = 'B'; // blank, B, I, or BI |
||||||
730 | $this->pdf->defaultfooterline = 1; // 1 to include line below header/above footer |
||||||
731 | |||||||
732 | $view = new Template('', false, false, false, true, false, false); |
||||||
733 | $template = $view->get_template('export/pdf_certificate_footer.tpl'); |
||||||
734 | $footerHTML = $view->fetch($template); |
||||||
735 | |||||||
736 | $this->pdf->SetHTMLFooter($footerHTML, 'E'); //Even pages |
||||||
737 | $this->pdf->SetHTMLFooter($footerHTML, 'O'); //Odd pages |
||||||
738 | } |
||||||
739 | |||||||
740 | /** |
||||||
741 | * Sets the PDF header. |
||||||
742 | * |
||||||
743 | * @param array $courseInfo |
||||||
744 | */ |
||||||
745 | public function set_header($courseInfo) |
||||||
746 | { |
||||||
747 | $this->pdf->defaultheaderfontsize = 10; // in pts |
||||||
748 | $this->pdf->defaultheaderfontstyle = 'BI'; // blank, B, I, or BI |
||||||
749 | $this->pdf->defaultheaderline = 1; // 1 to include line below header/above footer |
||||||
750 | |||||||
751 | $userId = api_get_user_id(); |
||||||
752 | if (!empty($courseInfo['code'])) { |
||||||
753 | $teacher_list = CourseManager::get_teacher_list_from_course_code($courseInfo['code']); |
||||||
754 | |||||||
755 | $teachers = ''; |
||||||
756 | if (!empty($teacher_list)) { |
||||||
757 | foreach ($teacher_list as $teacher) { |
||||||
758 | if ($teacher['user_id'] != $userId) { |
||||||
759 | continue; |
||||||
760 | } |
||||||
761 | |||||||
762 | // Do not show the teacher list see BT#4080 only the current teacher name |
||||||
763 | $teachers = api_get_person_name($teacher['firstname'], $teacher['lastname']); |
||||||
764 | } |
||||||
765 | } |
||||||
766 | |||||||
767 | $organization = null; |
||||||
768 | |||||||
769 | // try getting the course logo |
||||||
770 | if (api_get_configuration_value('mail_header_from_custom_course_logo') == true) { |
||||||
771 | $organization = CourseManager::getCourseEmailPicture($courseInfo, []); |
||||||
772 | } |
||||||
773 | // only show platform logo in mail if no course photo available |
||||||
774 | if (empty($organization)) { |
||||||
775 | $organization = ChamiloApi::getPlatformLogo('', [], false, true); |
||||||
776 | } |
||||||
777 | |||||||
778 | // Use custom logo image. |
||||||
779 | $pdfLogo = api_get_setting('pdf_logo_header'); |
||||||
780 | if ($pdfLogo === 'true') { |
||||||
781 | $visualTheme = api_get_visual_theme(); |
||||||
782 | $img = api_get_path(SYS_CSS_PATH).'themes/'.$visualTheme.'/images/pdf_logo_header.png'; |
||||||
783 | if (file_exists($img)) { |
||||||
784 | $organization = "<img src='$img'>"; |
||||||
785 | } |
||||||
786 | } |
||||||
787 | |||||||
788 | $view = new Template('', false, false, false, true, false, false); |
||||||
789 | $view->assign('teacher_name', $teachers); |
||||||
790 | $view->assign('organization', $organization); |
||||||
791 | $template = $view->get_template('export/pdf_header.tpl'); |
||||||
792 | $headerHTML = $view->fetch($template); |
||||||
793 | |||||||
794 | $this->pdf->SetHTMLHeader($headerHTML, 'E'); |
||||||
795 | $this->pdf->SetHTMLHeader($headerHTML, 'O'); |
||||||
796 | } |
||||||
797 | } |
||||||
798 | |||||||
799 | /** |
||||||
800 | * @param string $header html content |
||||||
801 | */ |
||||||
802 | public function set_custom_header($header) |
||||||
803 | { |
||||||
804 | $this->custom_header = $header; |
||||||
805 | } |
||||||
806 | |||||||
807 | /** |
||||||
808 | * @param array $footer html content |
||||||
809 | */ |
||||||
810 | public function set_custom_footer($footer) |
||||||
811 | { |
||||||
812 | $this->custom_footer = $footer; |
||||||
813 | } |
||||||
814 | |||||||
815 | /** |
||||||
816 | * Pre-formats a PDF to the right size and, if not stated otherwise, with |
||||||
817 | * header, footer and watermark (if any). |
||||||
818 | * |
||||||
819 | * @param array $courseInfo General course information (to fill headers) |
||||||
820 | * @param bool $complete Whether we want headers, footers and watermark or not |
||||||
821 | */ |
||||||
822 | public function format_pdf($courseInfo, $complete = true) |
||||||
823 | { |
||||||
824 | $courseCode = null; |
||||||
825 | if (!empty($courseInfo)) { |
||||||
826 | $courseCode = $courseInfo['code']; |
||||||
827 | } |
||||||
828 | |||||||
829 | /*$pdf->SetAuthor('Documents Chamilo'); |
||||||
830 | $pdf->SetTitle('title'); |
||||||
831 | $pdf->SetSubject('Exported from Chamilo Documents'); |
||||||
832 | $pdf->SetKeywords('Chamilo Documents'); |
||||||
833 | */ |
||||||
834 | // TODO: To be read from the html document. |
||||||
835 | $this->pdf->directionality = api_get_text_direction(); |
||||||
836 | // Use different Odd/Even headers and footers and mirror margins |
||||||
837 | $this->pdf->mirrorMargins = 1; |
||||||
838 | |||||||
839 | // Add decoration only if not stated otherwise |
||||||
840 | if ($complete) { |
||||||
841 | // Adding watermark |
||||||
842 | if (api_get_setting('pdf_export_watermark_enable') === 'true') { |
||||||
843 | $watermark_file = self::get_watermark($courseCode); |
||||||
844 | if ($watermark_file) { |
||||||
845 | //http://mpdf1.com/manual/index.php?tid=269&searchstring=watermark |
||||||
846 | $this->pdf->SetWatermarkImage($watermark_file); |
||||||
847 | $this->pdf->showWatermarkImage = true; |
||||||
848 | } else { |
||||||
849 | $watermark_file = self::get_watermark(); |
||||||
850 | |||||||
851 | if ($watermark_file) { |
||||||
852 | $this->pdf->SetWatermarkImage($watermark_file); |
||||||
853 | $this->pdf->showWatermarkImage = true; |
||||||
854 | } |
||||||
855 | } |
||||||
856 | |||||||
857 | $watermark_text = api_get_setting('pdf_export_watermark_text'); |
||||||
858 | if ($courseCode && 'true' === api_get_setting('pdf_export_watermark_by_course')) { |
||||||
859 | $courseWaterMark = api_get_course_setting('pdf_export_watermark_text'); |
||||||
860 | if (!empty($courseWaterMark) && -1 != $courseWaterMark) { |
||||||
861 | $watermark_text = $courseWaterMark; |
||||||
862 | } |
||||||
863 | } |
||||||
864 | |||||||
865 | if (!empty($watermark_text)) { |
||||||
866 | $this->pdf->SetWatermarkText( |
||||||
867 | UtfString::strcode2utf($watermark_text), |
||||||
868 | 0.1 |
||||||
869 | ); |
||||||
870 | $this->pdf->showWatermarkText = true; |
||||||
871 | } |
||||||
872 | } |
||||||
873 | |||||||
874 | if (empty($this->custom_header)) { |
||||||
875 | self::set_header($courseInfo); |
||||||
0 ignored issues
–
show
The method
PDF::set_header() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
876 | } else { |
||||||
877 | $this->pdf->SetHTMLHeader($this->custom_header, 'E'); |
||||||
878 | $this->pdf->SetHTMLHeader($this->custom_header, 'O'); |
||||||
879 | } |
||||||
880 | |||||||
881 | if (empty($this->custom_footer)) { |
||||||
882 | self::set_footer(); |
||||||
0 ignored issues
–
show
The method
PDF::set_footer() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
883 | } else { |
||||||
884 | $this->pdf->SetHTMLFooter($this->custom_footer); |
||||||
885 | } |
||||||
886 | } |
||||||
887 | } |
||||||
888 | |||||||
889 | /** |
||||||
890 | * Generate a PDF file from $html in SYS_APP_PATH. |
||||||
891 | * |
||||||
892 | * @param string $html PDF content |
||||||
893 | * @param string $fileName File name |
||||||
894 | * @param string $dest Optional. Directory to move file |
||||||
895 | * |
||||||
896 | * @return string The PDF path |
||||||
897 | */ |
||||||
898 | public function exportFromHtmlToFile($html, $fileName, $dest = null) |
||||||
899 | { |
||||||
900 | $this->template = $this->template ?: new Template('', false, false, false, false, false, false); |
||||||
901 | |||||||
902 | $pdfPath = self::content_to_pdf( |
||||||
0 ignored issues
–
show
The method
PDF::content_to_pdf() is not static, but was called statically.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
903 | $html, |
||||||
904 | api_get_print_css(), |
||||||
905 | $fileName, |
||||||
906 | $this->params['course_code'], |
||||||
907 | 'F' |
||||||
908 | ); |
||||||
909 | |||||||
910 | if (!$dest) { |
||||||
911 | return $pdfPath; |
||||||
912 | } |
||||||
913 | |||||||
914 | move($pdfPath, $dest); |
||||||
915 | |||||||
916 | return $dest.basename($pdfPath); |
||||||
917 | } |
||||||
918 | |||||||
919 | /** |
||||||
920 | * Create a PDF and save it into the documents area. |
||||||
921 | * |
||||||
922 | * @param string $htmlContent HTML Content |
||||||
923 | * @param string $fileName The file name |
||||||
924 | * @param int $courseId The course ID |
||||||
925 | * @param int $sessionId Optional. The session ID |
||||||
926 | */ |
||||||
927 | public function exportFromHtmlToDocumentsArea( |
||||||
928 | $htmlContent, |
||||||
929 | $fileName, |
||||||
930 | $courseId, |
||||||
931 | $sessionId = 0 |
||||||
932 | ) { |
||||||
933 | $userId = api_get_user_id(); |
||||||
934 | $courseInfo = api_get_course_info_by_id($courseId); |
||||||
935 | $courseDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document/'; |
||||||
936 | |||||||
937 | $docPath = $this->exportFromHtmlToFile( |
||||||
938 | $htmlContent, |
||||||
939 | $fileName, |
||||||
940 | $courseDirectory |
||||||
941 | ); |
||||||
942 | |||||||
943 | $docId = add_document( |
||||||
944 | $courseInfo, |
||||||
945 | str_replace($courseDirectory, '/', $docPath), |
||||||
946 | 'file', |
||||||
947 | filesize($docPath), |
||||||
948 | $fileName, |
||||||
949 | null, |
||||||
950 | false, |
||||||
951 | true, |
||||||
952 | null, |
||||||
953 | $sessionId, |
||||||
954 | $userId |
||||||
955 | ); |
||||||
956 | |||||||
957 | api_item_property_update( |
||||||
958 | $courseInfo, |
||||||
959 | TOOL_DOCUMENT, |
||||||
960 | $docId, |
||||||
961 | 'DocumentAdded', |
||||||
962 | $userId |
||||||
963 | ); |
||||||
964 | |||||||
965 | Display::addFlash(Display::return_message(get_lang('ItemAdded'))); |
||||||
966 | } |
||||||
967 | |||||||
968 | /** |
||||||
969 | * @param string $theme |
||||||
970 | * @param bool $fullPage |
||||||
971 | * |
||||||
972 | * @throws MpdfException |
||||||
973 | */ |
||||||
974 | public function setBackground($theme, $fullPage = false) |
||||||
975 | { |
||||||
976 | $themeName = empty($theme) ? api_get_visual_theme() : $theme; |
||||||
977 | $themeDir = Template::getThemeDir($themeName); |
||||||
978 | $customLetterhead = $themeDir.'images/letterhead.png'; |
||||||
979 | $urlPathLetterhead = api_get_path(SYS_CSS_PATH).$customLetterhead; |
||||||
980 | |||||||
981 | if (file_exists($urlPathLetterhead)) { |
||||||
982 | $urlWebLetterhead = 'url('.api_get_path(WEB_CSS_PATH).$customLetterhead.')'; |
||||||
983 | } else { |
||||||
984 | $urlWebLetterhead = 'url('.api_get_path(WEB_CSS_PATH).'themes/chamilo/images/letterhead.png)'; |
||||||
985 | } |
||||||
986 | |||||||
987 | if ($fullPage) { |
||||||
988 | $this->pdf->SetDisplayMode('fullpage'); |
||||||
989 | $this->pdf->SetDefaultBodyCSS('background', $urlWebLetterhead); |
||||||
990 | $this->pdf->SetDefaultBodyCSS('background-image-resize', '6'); |
||||||
991 | } |
||||||
992 | } |
||||||
993 | |||||||
994 | /** |
||||||
995 | * Fix images source paths to allow export to pdf. |
||||||
996 | */ |
||||||
997 | public static function fixImagesPaths(string $documentHtml, array $courseInfo, string $dirName = ''): string |
||||||
998 | { |
||||||
999 | $documentHtml = '<?xml encoding="utf-8" ?>'.$documentHtml; |
||||||
1000 | $doc = new DOMDocument(); |
||||||
1001 | @$doc->loadHTML($documentHtml); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
loadHTML() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
1002 | |||||||
1003 | $elements = $doc->getElementsByTagName('img'); |
||||||
1004 | |||||||
1005 | if (empty($elements)) { |
||||||
1006 | return $doc->saveHTML(); |
||||||
1007 | } |
||||||
1008 | |||||||
1009 | $protocol = api_get_protocol(); |
||||||
1010 | $sysCodePath = api_get_path(SYS_CODE_PATH); |
||||||
1011 | $sysCoursePath = api_get_path(SYS_COURSE_PATH); |
||||||
1012 | $sysUploadPath = api_get_path(SYS_UPLOAD_PATH); |
||||||
1013 | $sysPath = api_get_path(SYS_PATH); |
||||||
1014 | |||||||
1015 | $documentPath = $courseInfo ? $sysCoursePath.$courseInfo['path'].'/document/' : ''; |
||||||
1016 | |||||||
1017 | $notFoundImagePath = Display::return_icon( |
||||||
1018 | 'closed-circle.png', |
||||||
1019 | get_lang('FileNotFound'), |
||||||
1020 | [], |
||||||
1021 | ICON_SIZE_TINY, |
||||||
1022 | false, |
||||||
1023 | true |
||||||
1024 | ); |
||||||
1025 | |||||||
1026 | /** @var DOMElement $element */ |
||||||
1027 | foreach ($elements as $element) { |
||||||
1028 | $src = $element->getAttribute('src'); |
||||||
1029 | $src = trim($src); |
||||||
1030 | |||||||
1031 | if (api_filename_has_blacklisted_stream_wrapper($src)) { |
||||||
1032 | $element->setAttribute('src', $notFoundImagePath); |
||||||
1033 | continue; |
||||||
1034 | } |
||||||
1035 | |||||||
1036 | if (strpos($src, $protocol) !== false) { |
||||||
1037 | continue; |
||||||
1038 | } |
||||||
1039 | |||||||
1040 | // It's a reference to a file in the system, do not change it |
||||||
1041 | if (file_exists($src)) { |
||||||
1042 | continue; |
||||||
1043 | } |
||||||
1044 | |||||||
1045 | if (strpos($src, '/main/default_course_document') === 0) { |
||||||
1046 | $element->setAttribute( |
||||||
1047 | 'src', |
||||||
1048 | str_replace('/main/default_course_document', $sysCodePath.'default_course_document', $src) |
||||||
1049 | ); |
||||||
1050 | continue; |
||||||
1051 | } |
||||||
1052 | |||||||
1053 | if (strpos($src, '/main/img') === 0) { |
||||||
1054 | $element->setAttribute( |
||||||
1055 | 'src', |
||||||
1056 | str_replace('/main/img/', $sysCodePath.'img/', $src) |
||||||
1057 | ); |
||||||
1058 | continue; |
||||||
1059 | } |
||||||
1060 | |||||||
1061 | if (strpos($src, '/app/upload/') === 0) { |
||||||
1062 | $element->setAttribute( |
||||||
1063 | 'src', |
||||||
1064 | str_replace('/app/upload/', $sysUploadPath, $src) |
||||||
1065 | ); |
||||||
1066 | continue; |
||||||
1067 | } |
||||||
1068 | |||||||
1069 | if (strpos($src, '/web/css/themes/') === 0) { |
||||||
1070 | $element->setAttribute( |
||||||
1071 | 'src', |
||||||
1072 | str_replace('/web/css/themes/', $sysPath.'web/css/themes/', $src) |
||||||
1073 | ); |
||||||
1074 | |||||||
1075 | continue; |
||||||
1076 | } |
||||||
1077 | |||||||
1078 | if (empty($courseInfo)) { |
||||||
1079 | continue; |
||||||
1080 | } |
||||||
1081 | |||||||
1082 | if (api_get_path(REL_PATH) != '/') { |
||||||
1083 | $oldSrcFixed = str_replace( |
||||||
1084 | api_get_path(REL_PATH).'courses/'.$courseInfo['path'].'/document/', |
||||||
1085 | '', |
||||||
1086 | $src |
||||||
1087 | ); |
||||||
1088 | |||||||
1089 | // Try with the dirname if exists |
||||||
1090 | if ($oldSrcFixed == $src) { |
||||||
1091 | if (file_exists($dirName.'/'.$src)) { |
||||||
1092 | $documentPath = ''; |
||||||
1093 | $oldSrcFixed = $dirName.'/'.$src; |
||||||
1094 | } |
||||||
1095 | } |
||||||
1096 | } else { |
||||||
1097 | if (strpos($src, 'courses/'.$courseInfo['path'].'/document/') !== false) { |
||||||
1098 | $oldSrcFixed = str_replace('courses/'.$courseInfo['path'].'/document/', '', $src); |
||||||
1099 | } else { |
||||||
1100 | // Try with the dirname if exists |
||||||
1101 | $documentPath = ''; |
||||||
1102 | if (file_exists($dirName.'/'.$src)) { |
||||||
1103 | $oldSrcFixed = $dirName.'/'.$src; |
||||||
1104 | } else { |
||||||
1105 | $oldSrcFixed = $src; |
||||||
1106 | } |
||||||
1107 | } |
||||||
1108 | } |
||||||
1109 | |||||||
1110 | $element->setAttribute('src', $documentPath.$oldSrcFixed); |
||||||
1111 | } |
||||||
1112 | |||||||
1113 | return $doc->saveHTML(); |
||||||
1114 | } |
||||||
1115 | } |
||||||
1116 |