Passed
Push — master ( 4aec42...69e1de )
by Julito
17:30
created

PDF::set_footer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 0
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* See license terms in /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Masterminds\HTML5;
7
use Mpdf\Mpdf;
8
use Mpdf\Output\Destination;
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
    public function __construct(
32
        $pageFormat = 'A4',
33
        $orientation = 'P',
34
        $params = [],
35
        $template = null
36
    ) {
37
        $this->template = $template;
38
        /* More info @ http://mpdf1.com/manual/index.php?tid=184&searchstring=mPDF */
39
        if (!in_array($orientation, ['P', 'L'])) {
40
            $orientation = 'P';
41
        }
42
        //left, right, top, bottom, margin_header, margin footer
43
44
        $params['left'] = isset($params['left']) ? $params['left'] : 15;
45
        $params['right'] = isset($params['right']) ? $params['right'] : 15;
46
        $params['top'] = isset($params['top']) ? $params['top'] : 30;
47
        $params['bottom'] = isset($params['bottom']) ? $params['bottom'] : 30;
48
        $params['margin_footer'] = isset($params['margin_footer']) ? $params['margin_footer'] : 8;
49
50
        $this->params['filename'] = isset($params['filename']) ? $params['filename'] : api_get_local_time();
51
        $this->params['pdf_title'] = isset($params['pdf_title']) ? $params['pdf_title'] : '';
52
        $this->params['course_info'] = isset($params['course_info']) ? $params['course_info'] : api_get_course_info();
53
        $this->params['session_info'] = isset($params['session_info']) ? $params['session_info'] : api_get_session_info(api_get_session_id());
54
        $this->params['course_code'] = isset($params['course_code']) ? $params['course_code'] : api_get_course_id();
55
        $this->params['add_signatures'] = isset($params['add_signatures']) ? $params['add_signatures'] : [];
56
        $this->params['show_real_course_teachers'] = isset($params['show_real_course_teachers']) ? $params['show_real_course_teachers'] : false;
57
        $this->params['student_info'] = isset($params['student_info']) ? $params['student_info'] : false;
58
        $this->params['show_grade_generated_date'] = isset($params['show_grade_generated_date']) ? $params['show_grade_generated_date'] : false;
59
        $this->params['show_teacher_as_myself'] = isset($params['show_teacher_as_myself']) ? $params['show_teacher_as_myself'] : true;
60
        $localTime = api_get_local_time();
61
        $this->params['pdf_date'] = isset($params['pdf_date']) ? $params['pdf_date'] : api_format_date($localTime, DATE_TIME_FORMAT_LONG);
62
        $this->params['pdf_date_only'] = isset($params['pdf_date']) ? $params['pdf_date'] : api_format_date($localTime, DATE_FORMAT_LONG);
63
64
        $params = [
65
            'tempDir' => api_get_path(SYS_ARCHIVE_PATH).'mpdf',
66
            'mode' => 'utf-8',
67
            'format' => $pageFormat,
68
            'orientation' => $orientation,
69
            'margin_left' => $params['left'],
70
            'margin_right' => $params['right'],
71
            'margin_top' => $params['top'],
72
            'margin_bottom' => $params['bottom'],
73
            'margin_header' => 8,
74
            'margin_footer' => 8,
75
        ];
76
77
        // Default value is 96 set in the mpdf library file config.php
78
        $value = api_get_configuration_value('pdf_img_dpi');
79
        if (!empty($value)) {
80
            $params['img_dpi'] = (int) $value;
81
        }
82
83
        $this->pdf = new Mpdf($params);
84
    }
85
86
    /**
87
     * Export the given HTML to PDF, using a global template.
88
     *
89
     * @uses \export/table_pdf.tpl
90
     *
91
     * @param string     $content
92
     * @param bool|false $saveToFile
93
     * @param bool|false $returnHtml
94
     * @param bool       $addDefaultCss (bootstrap/default/base.css)
95
     * @param array
96
     *
97
     * @return string
98
     */
99
    public function html_to_pdf_with_template(
100
        $content,
101
        $saveToFile = false,
102
        $returnHtml = false,
103
        $addDefaultCss = false,
104
        $extraRows = []
105
    ) {
106
        if (empty($this->template)) {
107
            $tpl = new Template('', false, false, false, false, true, false);
108
        } else {
109
            $tpl = $this->template;
110
        }
111
112
        // Assignments
113
        $tpl->assign('pdf_content', $content);
114
115
        // Showing only the current teacher/admin instead the all teacher list name see BT#4080
116
        $teacher_list = null;
117
        if (isset($this->params['show_real_course_teachers']) &&
118
            $this->params['show_real_course_teachers']
119
        ) {
120
            if (isset($this->params['session_info']) &&
121
                !empty($this->params['session_info'])
122
            ) {
123
                $teacher_list = SessionManager::getCoachesByCourseSessionToString(
124
                    $this->params['session_info']['id'],
125
                    $this->params['course_info']['real_id']
126
                );
127
            } else {
128
                $teacher_list = CourseManager::getTeacherListFromCourseCodeToString(
129
                    $this->params['course_code']
130
                );
131
            }
132
        } else {
133
            $user_info = api_get_user_info();
134
            if ($this->params['show_teacher_as_myself']) {
135
                $teacher_list = $user_info['complete_name'];
136
            }
137
        }
138
139
        $tpl->assign('pdf_course', $this->params['course_code']);
140
        $tpl->assign('pdf_course_info', $this->params['course_info']);
141
        $tpl->assign('pdf_session_info', $this->params['session_info']);
142
        $tpl->assign('pdf_date', $this->params['pdf_date']);
143
        $tpl->assign('pdf_date_only', $this->params['pdf_date_only']);
144
        $tpl->assign('pdf_teachers', $teacher_list);
145
        $tpl->assign('pdf_title', $this->params['pdf_title']);
146
        $tpl->assign('pdf_student_info', $this->params['student_info']);
147
        $tpl->assign('show_grade_generated_date', $this->params['show_grade_generated_date']);
148
        $tpl->assign('add_signatures', $this->params['add_signatures']);
149
        $tpl->assign('extra_rows', $extraRows);
150
151
        // Getting template
152
        $tableTemplate = $tpl->get_template('export/table_pdf.tpl');
153
        $html = $tpl->fetch($tableTemplate);
154
        $html = api_utf8_encode($html);
155
156
        if ($returnHtml) {
157
            return $html;
158
        }
159
160
        $css_file = api_get_path(SYS_CSS_PATH).'themes/'.$tpl->theme.'/print.css';
161
        if (!file_exists($css_file)) {
162
            $css_file = api_get_path(SYS_CSS_PATH).'print.css';
163
        }
164
        $css = file_get_contents($css_file);
165
166
        self::content_to_pdf(
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

166
        self::/** @scrutinizer ignore-call */ 
167
              content_to_pdf(
Loading history...
167
            $html,
168
            $css,
169
            $this->params['filename'],
170
            $this->params['course_code'],
171
            'D',
172
            $saveToFile,
173
            null,
174
            $returnHtml,
175
            $addDefaultCss
176
        );
177
    }
178
179
    /**
180
     * Converts HTML files to PDF.
181
     *
182
     * @param mixed  $htmlFileArray  could be an html file path or an array
183
     *                               with paths example:
184
     *                               /var/www/myfile.html or array('/myfile.html','myotherfile.html') or
185
     *                               even an indexed array with both 'title' and 'path' indexes
186
     *                               for each element like
187
     *                               array(
188
     *                               0 => array('title'=>'Hello','path'=>'file.html'),
189
     *                               1 => array('title'=>'Bye','path'=>'file2.html')
190
     *                               );
191
     * @param string $pdfName        pdf name
192
     * @param string $courseCode     (if you are using html that are located
193
     *                               in the document tool you must provide this)
194
     * @param bool   $complete_style show header and footer if true
195
     * @param bool   $addStyle
196
     * @param string $mainTitle
197
     *
198
     * @return false|null
199
     */
200
    public function html_to_pdf(
201
        $htmlFileArray,
202
        $pdfName = '',
203
        $courseCode = null,
204
        $printTitle = false,
205
        $complete_style = true,
206
        $addStyle = true,
207
        $mainTitle = ''
208
    ) {
209
        if (empty($htmlFileArray)) {
210
            return false;
211
        }
212
213
        if (!is_array($htmlFileArray)) {
214
            if (!file_exists($htmlFileArray)) {
215
                return false;
216
            }
217
            // Converting the string into an array
218
            $htmlFileArray = [$htmlFileArray];
219
        }
220
221
        $courseInfo = api_get_course_info();
222
        if (!empty($courseCode)) {
223
            $courseInfo = api_get_course_info($courseCode);
224
        }
225
226
        // Clean styles and javascript document
227
        $clean_search = [
228
            '@<script[^>]*?>.*?</script>@si',
229
            '@<style[^>]*?>.*?</style>@si',
230
        ];
231
232
        // Formatting the pdf
233
        self::format_pdf($courseInfo, $complete_style);
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

233
        self::/** @scrutinizer ignore-call */ 
234
              format_pdf($courseInfo, $complete_style);
Loading history...
234
235
        $counter = 1;
236
        foreach ($htmlFileArray as $file) {
237
            //Add a page break per file
238
            $pageBreak = '<pagebreak>';
239
            if ($counter == count($htmlFileArray)) {
240
                $pageBreak = '';
241
            }
242
243
            //if the array provided contained subarrays with 'title' entry,
244
            // then print the title in the PDF
245
            if (is_array($file) && isset($file['title'])) {
246
                $htmlTitle = $file['title'];
247
                $file = $file['path'];
248
            } else {
249
                //we suppose we've only been sent a file path
250
                $htmlTitle = basename($file);
251
            }
252
253
            $counter++;
254
255
            if (empty($file) && !empty($htmlTitle)) {
256
                // this is a chapter, print title & skip the rest
257
                if (2 === $counter && !empty($mainTitle)) {
258
                    $this->pdf->WriteHTML(
259
                        '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>'
260
                    );
261
                }
262
                if ($printTitle) {
263
                    $this->pdf->WriteHTML(
264
                        '<html><body><h3>'.$htmlTitle.'</h3></body></html>'.$pageBreak
265
                    );
266
                }
267
                continue;
268
            } else {
269
                if (2 === $counter && !empty($mainTitle)) {
270
                    $this->pdf->WriteHTML(
271
                        '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>'
272
                    );
273
                }
274
            }
275
276
            if (!file_exists($file)) {
277
                continue;
278
            }
279
280
            if ($addStyle) {
281
                $css_file = api_get_path(SYS_CSS_PATH).'/print.css';
282
                $css = file_exists($css_file) ? @file_get_contents($css_file) : '';
283
                $this->pdf->WriteHTML($css, 1);
284
            }
285
286
            //it's not a chapter but the file exists, print its title
287
            if ($printTitle) {
288
                $this->pdf->WriteHTML('<html><body><h3>'.$htmlTitle.'</h3></body></html>', 2);
289
            }
290
291
            $file_info = pathinfo($file);
292
            $extension = $file_info['extension'];
293
294
            if (in_array($extension, ['html', 'htm'])) {
295
                $dirName = $file_info['dirname'];
296
                $filename = $file_info['basename'];
297
                $filename = str_replace('_', ' ', $filename);
298
299
                if ('html' === $extension) {
300
                    $filename = basename($filename, '.html');
301
                } elseif ('htm' === $extension) {
302
                    $filename = basename($filename, '.htm');
303
                }
304
305
                $documentHtml = @file_get_contents($file);
306
                $documentHtml = preg_replace($clean_search, '', $documentHtml);
307
308
                //absolute path for frames.css //TODO: necessary?
309
                $absolute_css_path = api_get_path(WEB_CODE_PATH).'css/'.api_get_setting('stylesheets').'/frames.css';
310
                $documentHtml = str_replace('href="./css/frames.css"', $absolute_css_path, $documentHtml);
311
                if (!empty($courseInfo['path'])) {
312
                    $documentHtml = str_replace('../', '', $documentHtml);
313
314
                    // Fix app/upload links convert web to system paths
315
                    $documentHtml = str_replace(
316
                        api_get_path(WEB_UPLOAD_PATH),
317
                        api_get_path(SYS_UPLOAD_PATH),
318
                        $documentHtml
319
                    );
320
                }
321
322
                $documentHtml = self::fixImagesPaths($documentHtml, $courseInfo, $dirName);
323
                // The library mPDF expects UTF-8 encoded input data.
324
                api_set_encoding_html($documentHtml, 'UTF-8');
325
                // TODO: Maybe it is better idea the title to be passed through
326
                $title = api_get_title_html($documentHtml, 'UTF-8', 'UTF-8');
327
                // $_GET[] too, as it is done with file name.
328
                // At the moment the title is retrieved from the html document itself.
329
                if (empty($title)) {
330
                    $title = $filename; // Here file name is expected to contain ASCII symbols only.
331
                }
332
333
                if (!empty($documentHtml)) {
334
                    $this->pdf->WriteHTML($documentHtml.$pageBreak, 2);
335
                }
336
            } elseif (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) {
337
                // Images
338
                $image = Display::img($file);
339
                $this->pdf->WriteHTML('<html><body>'.$image.'</body></html>'.$pageBreak, 2);
340
            }
341
        }
342
343
        $outputFile = 'pdf_'.api_get_local_time().'.pdf';
344
        if (!empty($pdfName)) {
345
            $outputFile = $pdfName.'.pdf';
346
        }
347
348
        $outputFile = api_replace_dangerous_char($outputFile);
349
350
        // F to save the pdf in a file
351
        $this->pdf->Output($outputFile, Destination::DOWNLOAD);
352
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
353
    }
354
355
    /**
356
     * Converts an html string to PDF.
357
     *
358
     * @param string $document_html  valid html
359
     * @param string $css            CSS content of a CSS file
360
     * @param string $pdf_name       pdf name
361
     * @param string $courseCode     course code
362
     *                               (if you are using html that are located in the document tool you must provide this)
363
     * @param string $outputMode     the MPDF output mode can be:
364
     * @param bool   $saveInFile
365
     * @param string $fileToSave
366
     * @param bool   $returnHtml
367
     * @param bool   $addDefaultCss
368
     * @param bool   $completeHeader
369
     *
370
     * 'I' (print on standard output),
371
     * 'D' (download file) (this is the default value),
372
     * 'F' (save to local file) or
373
     * 'S' (return as a string)
374
     *
375
     * @return string Web path
376
     */
377
    public function content_to_pdf(
378
        $document_html,
379
        $css = '',
380
        $pdf_name = '',
381
        $courseCode = null,
382
        $outputMode = 'D',
383
        $saveInFile = false,
384
        $fileToSave = null,
385
        $returnHtml = false,
386
        $addDefaultCss = false,
387
        $completeHeader = true
388
    ) {
389
        $urlAppend = '';
390
391
        if (empty($document_html)) {
392
            return false;
393
        }
394
395
        // clean styles and javascript document
396
        $clean_search = [
397
            '@<script[^>]*?>.*?</script>@si',
398
            '@<style[^>]*?>.*?</style>@siU',
399
        ];
400
401
        // Formatting the pdf
402
        $courseInfo = api_get_course_info($courseCode);
403
        self::format_pdf($courseInfo, $completeHeader);
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

403
        self::/** @scrutinizer ignore-call */ 
404
              format_pdf($courseInfo, $completeHeader);
Loading history...
404
        $document_html = preg_replace($clean_search, '', $document_html);
405
406
        //absolute path for frames.css //TODO: necessary?
407
        $absolute_css_path = api_get_path(WEB_CSS_PATH).api_get_setting('stylesheets').'/frames.css';
408
        $document_html = str_replace('href="./css/frames.css"', 'href="'.$absolute_css_path.'"', $document_html);
409
        $document_html = str_replace('../../', '', $document_html);
410
        $document_html = str_replace('../', '', $document_html);
411
        $document_html = str_replace(
412
            (empty($urlAppend) ? '' : $urlAppend.'/').'courses/'.$courseCode.'/document/',
413
            '',
414
            $document_html
415
        );
416
417
        if (!empty($courseInfo['path'])) {
418
            //$document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
419
420
            $doc = new DOMDocument();
421
            @$doc->loadHTML($document_html);
0 ignored issues
show
Security Best Practice introduced by
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 ignore-unhandled  annotation

421
            /** @scrutinizer ignore-unhandled */ @$doc->loadHTML($document_html);

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.');
}
Loading history...
422
423
            //Fixing only images @todo do the same thing with other elements
424
            $elements = $doc->getElementsByTagName('img');
425
            $protocol = api_get_protocol();
426
            $replaced = [];
427
            if (!empty($elements)) {
428
                foreach ($elements as $item) {
429
                    $old_src = $item->getAttribute('src');
430
431
                    if (in_array($old_src, $replaced)) {
432
                        continue;
433
                    }
434
435
                    if (false === strpos($old_src, $protocol)) {
436
                        if (false === strpos($old_src, '/main/default_course_document')) {
437
                            if (false === strpos($old_src, '/main/inc/lib/') &&
438
                                false === strpos($old_src, '/app/upload/')
439
                            ) {
440
                                /*$old_src_fixed = str_replace(
441
                                    api_get_path(REL_COURSE_PATH).$courseInfo['path'].'/document/',
442
                                    '',
443
                                    $old_src
444
                                );
445
                                $old_src_fixed = str_replace(
446
                                    'courses/'.$courseInfo['path'].'/document/',
447
                                    '',
448
                                    $old_src_fixed
449
                                );
450
                                $new_path = $document_path.$old_src_fixed;
451
                                $document_html = str_replace($old_src, $new_path, $document_html);
452
                                $replaced[] = $old_src;*/
453
                            }
454
                        }
455
                    }
456
                }
457
            }
458
        }
459
460
        // Use sys path to correct export images
461
        $document_html = str_replace(
462
            api_get_path(WEB_CODE_PATH).'img/',
463
            api_get_path(SYS_CODE_PATH).'img/',
464
            $document_html
465
        );
466
        $document_html = str_replace(api_get_path(WEB_ARCHIVE_PATH), api_get_path(SYS_ARCHIVE_PATH), $document_html);
467
468
        // The library mPDF expects UTF-8 encoded input data.
469
        api_set_encoding_html($document_html, 'UTF-8');
470
        // At the moment the title is retrieved from the html document itself.
471
        if ($returnHtml) {
472
            return "<style>$css</style>".$document_html;
473
        }
474
475
        if (!empty($css)) {
476
            $this->pdf->WriteHTML($css, 1);
477
        }
478
479
        if ($addDefaultCss) {
480
            $basicStyles = [
481
                api_get_bootstrap_and_font_awesome(true),
482
                api_get_path(SYS_PUBLIC_PATH).'build/css/app.css',
483
                api_get_path(SYS_PUBLIC_PATH).'build/css/themes/'.api_get_visual_theme().'/default.css',
484
            ];
485
            foreach ($basicStyles as $style) {
486
                $cssContent = file_get_contents($style);
487
                $this->pdf->WriteHTML($cssContent, 1);
488
            }
489
        }
490
491
        $this->pdf->WriteHTML($document_html);
492
493
        if (empty($pdf_name)) {
494
            $output_file = 'pdf_'.date('Y-m-d-his').'.pdf';
495
        } else {
496
            $pdf_name = api_replace_dangerous_char($pdf_name);
497
            $output_file = $pdf_name.'.pdf';
498
        }
499
500
        if ('F' == $outputMode) {
501
            $output_file = api_get_path(SYS_ARCHIVE_PATH).$output_file;
502
        }
503
504
        if ($saveInFile) {
505
            $fileToSave = !empty($fileToSave) ? $fileToSave : api_get_path(SYS_ARCHIVE_PATH).uniqid();
506
507
            $this->pdf->Output(
508
                $fileToSave,
509
                $outputMode
510
            ); // F to save the pdf in a file
511
        } else {
512
            $this->pdf->Output(
513
                $output_file,
514
                $outputMode
515
            ); // F to save the pdf in a file
516
        }
517
518
        if ('F' != $outputMode) {
519
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
520
        }
521
522
        return $output_file;
523
    }
524
525
    /**
526
     * Gets the watermark from the platform or a course.
527
     *
528
     * @param   string  course code (optional)
529
     * @param   mixed   web path of the watermark image, false if there is nothing to return
530
     *
531
     * @return string
532
     */
533
    public static function get_watermark($courseCode = null)
534
    {
535
        $web_path = false;
536
        $urlId = api_get_current_access_url_id();
537
        if (!empty($courseCode) && 'true' == api_get_setting('pdf_export_watermark_by_course')) {
538
            $course_info = api_get_course_info($courseCode);
539
            // course path
540
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
541
            if (file_exists($store_path)) {
542
                $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
543
            }
544
        } else {
545
            // course path
546
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
547
            if (file_exists($store_path)) {
548
                $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
549
            }
550
        }
551
552
        return $web_path;
0 ignored issues
show
Bug Best Practice introduced by
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.

Loading history...
553
    }
554
555
    /**
556
     * Deletes the watermark from the Platform or Course.
557
     *
558
     * @param string $courseCode course code (optional)
559
     * @param   mixed   web path of the watermark image, false if there is nothing to return
560
     *
561
     * @return bool
562
     */
563
    public function delete_watermark($courseCode = null)
564
    {
565
        $urlId = api_get_current_access_url_id();
566
        if (!empty($courseCode) && 'true' == api_get_setting('pdf_export_watermark_by_course')) {
567
            $course_info = api_get_course_info($courseCode);
568
            // course path
569
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
570
        } else {
571
            // course path
572
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
573
        }
574
        if (file_exists($store_path)) {
575
            unlink($store_path);
576
577
            return true;
578
        }
579
580
        return false;
581
    }
582
583
    /**
584
     * Uploads the pdf watermark in the main/default_course_document directory or in the course directory.
585
     *
586
     * @param string $filename    filename
587
     * @param string $source_file path of the file
588
     * @param string $courseCode
589
     *
590
     * @return mixed web path of the file if sucess, false otherwise
591
     */
592
    public function upload_watermark($filename, $source_file, $courseCode = null)
593
    {
594
        $urlId = api_get_current_access_url_id();
595
        if (!empty($courseCode) && 'true' == api_get_setting('pdf_export_watermark_by_course')) {
596
            $course_info = api_get_course_info($courseCode);
597
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path']; // course path
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
598
            $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/pdf_watermark.png';
599
        } else {
600
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images'; // course path
601
            $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
602
        }
603
        $course_image = $store_path.'/'.$urlId.'_pdf_watermark.png';
604
605
        if (file_exists($course_image)) {
606
            @unlink($course_image);
0 ignored issues
show
Security Best Practice introduced by
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 ignore-unhandled  annotation

606
            /** @scrutinizer ignore-unhandled */ @unlink($course_image);

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.');
}
Loading history...
607
        }
608
        $my_image = new Image($source_file);
0 ignored issues
show
Deprecated Code introduced by
The class Image has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

608
        $my_image = /** @scrutinizer ignore-deprecated */ new Image($source_file);
Loading history...
609
        $result = $my_image->send_image($course_image, -1, 'png');
610
        if ($result) {
611
            $result = $web_path;
612
        }
613
614
        return $result;
615
    }
616
617
    /**
618
     * Returns the default header.
619
     */
620
    public function get_header($courseCode = null)
621
    {
622
        /*$header = api_get_setting('pdf_export_watermark_text');
623
    	if (!empty($courseCode) && api_get_setting('pdf_export_watermark_by_course') == 'true') {
624
            $header = api_get_course_setting('pdf_export_watermark_text');
625
        }
626
        return $header;*/
627
    }
628
629
    /**
630
     * Sets the PDF footer.
631
     */
632
    public function set_footer()
633
    {
634
        $this->pdf->defaultfooterfontsize = 12; // in pts
635
        $this->pdf->defaultfooterfontstyle = 'B'; // blank, B, I, or BI
636
        $this->pdf->defaultfooterline = 1; // 1 to include line below header/above footer
637
638
        $view = new Template('', false, false, false, true, false, false);
639
        $template = $view->get_template('export/pdf_footer.tpl');
640
        $footerHTML = $view->fetch($template);
641
642
        $this->pdf->SetHTMLFooter($footerHTML, 'E'); //Even pages
643
        $this->pdf->SetHTMLFooter($footerHTML, 'O'); //Odd pages
644
    }
645
646
    public function setCertificateFooter()
647
    {
648
        $this->pdf->defaultfooterfontsize = 12; // in pts
649
        $this->pdf->defaultfooterfontstyle = 'B'; // blank, B, I, or BI
650
        $this->pdf->defaultfooterline = 1; // 1 to include line below header/above footer
651
652
        $view = new Template('', false, false, false, true, false, false);
653
        $template = $view->get_template('export/pdf_certificate_footer.tpl');
654
        $footerHTML = $view->fetch($template);
655
656
        $this->pdf->SetHTMLFooter($footerHTML, 'E'); //Even pages
657
        $this->pdf->SetHTMLFooter($footerHTML, 'O'); //Odd pages
658
    }
659
660
    /**
661
     * Sets the PDF header.
662
     *
663
     * @param array $courseInfo
664
     */
665
    public function set_header($courseInfo)
666
    {
667
        $this->pdf->defaultheaderfontsize = 10; // in pts
668
        $this->pdf->defaultheaderfontstyle = 'BI'; // blank, B, I, or BI
669
        $this->pdf->defaultheaderline = 1; // 1 to include line below header/above footer
670
671
        $userId = api_get_user_id();
672
        if (!empty($courseInfo['code'])) {
673
            $teacher_list = CourseManager::get_teacher_list_from_course_code($courseInfo['code']);
674
675
            $teachers = '';
676
            if (!empty($teacher_list)) {
677
                foreach ($teacher_list as $teacher) {
678
                    if ($teacher['user_id'] != $userId) {
679
                        continue;
680
                    }
681
682
                    // Do not show the teacher list see BT#4080 only the current teacher name
683
                    $teachers = api_get_person_name($teacher['firstname'], $teacher['lastname']);
684
                }
685
            }
686
687
            $organization = ChamiloApi::getPlatformLogo('', [], true);
688
            // Use custom logo image.
689
            $pdfLogo = api_get_setting('pdf_logo_header');
690
            if ('true' === $pdfLogo) {
691
                $visualTheme = api_get_visual_theme();
692
                $img = api_get_path(SYS_CSS_PATH).'themes/'.$visualTheme.'/images/pdf_logo_header.png';
693
                if (file_exists($img)) {
694
                    $organization = "<img src='$img'>";
695
                }
696
            }
697
698
            $view = new Template('', false, false, false, true, false, false);
699
            $view->assign('teacher_name', $teachers);
700
            $view->assign('organization', $organization);
701
            $template = $view->get_template('export/pdf_header.tpl');
702
            $headerHTML = $view->fetch($template);
703
704
            $this->pdf->SetHTMLHeader($headerHTML, 'E');
705
            $this->pdf->SetHTMLHeader($headerHTML, 'O');
706
        }
707
    }
708
709
    /**
710
     * @param string $header html content
711
     */
712
    public function set_custom_header($header)
713
    {
714
        $this->custom_header = $header;
715
    }
716
717
    /**
718
     * @param array $footer html content
719
     */
720
    public function set_custom_footer($footer)
721
    {
722
        $this->custom_footer = $footer;
723
    }
724
725
    /**
726
     * Pre-formats a PDF to the right size and, if not stated otherwise, with
727
     * header, footer and watermark (if any).
728
     *
729
     * @param array $courseInfo General course information (to fill headers)
730
     * @param bool  $complete   Whether we want headers, footers and watermark or not
731
     */
732
    public function format_pdf($courseInfo, $complete = true)
733
    {
734
        $courseCode = null;
735
        if (!empty($courseInfo)) {
736
            $courseCode = $courseInfo['code'];
737
        }
738
739
        /*$pdf->SetAuthor('Documents Chamilo');
740
        $pdf->SetTitle('title');
741
        $pdf->SetSubject('Exported from Chamilo Documents');
742
        $pdf->SetKeywords('Chamilo Documents');
743
        */
744
        // TODO: To be read from the html document.
745
        $this->pdf->directionality = api_get_text_direction();
746
        //$this->pdf->useOnlyCoreFonts = true;
747
        $this->pdf->onlyCoreFonts = true;
748
        // Use different Odd/Even headers and footers and mirror margins
749
        $this->pdf->mirrorMargins = 1;
750
751
        // Add decoration only if not stated otherwise
752
        if ($complete) {
753
            // Adding watermark
754
            if ('true' == api_get_setting('pdf_export_watermark_enable')) {
755
                $watermark_file = self::get_watermark($courseCode);
756
                if ($watermark_file) {
757
                    //http://mpdf1.com/manual/index.php?tid=269&searchstring=watermark
758
                    $this->pdf->SetWatermarkImage($watermark_file);
759
                    $this->pdf->showWatermarkImage = true;
760
                } else {
761
                    $watermark_file = self::get_watermark(null);
762
                    if ($watermark_file) {
763
                        $this->pdf->SetWatermarkImage($watermark_file);
764
                        $this->pdf->showWatermarkImage = true;
765
                    }
766
                }
767
                $watermark_text = api_get_setting('pdf_export_watermark_text');
768
                if ($courseCode && 'true' === api_get_setting('pdf_export_watermark_by_course')) {
769
                    $courseWaterMark = api_get_course_setting('pdf_export_watermark_text');
770
                    if (!empty($courseWaterMark) && -1 != $courseWaterMark) {
771
                        $watermark_text = $courseWaterMark;
772
                    }
773
                }
774
                if (!empty($watermark_text)) {
775
                    $this->pdf->SetWatermarkText(
776
                        strcode2utf($watermark_text),
0 ignored issues
show
Bug introduced by
The function strcode2utf was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

776
                        /** @scrutinizer ignore-call */ 
777
                        strcode2utf($watermark_text),
Loading history...
777
                        0.1
778
                    );
779
                    $this->pdf->showWatermarkText = true;
780
                }
781
            }
782
783
            if (empty($this->custom_header)) {
784
                self::set_header($courseInfo);
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

784
                self::/** @scrutinizer ignore-call */ 
785
                      set_header($courseInfo);
Loading history...
785
            } else {
786
                $this->pdf->SetHTMLHeader($this->custom_header, 'E');
787
                $this->pdf->SetHTMLHeader($this->custom_header, 'O');
788
            }
789
790
            if (empty($this->custom_footer)) {
791
                self::set_footer();
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

791
                self::/** @scrutinizer ignore-call */ 
792
                      set_footer();
Loading history...
792
            } else {
793
                $this->pdf->SetHTMLFooter($this->custom_footer);
794
            }
795
        }
796
    }
797
798
    /**
799
     * Generate a PDF file from $html in SYS_APP_PATH.
800
     *
801
     * @param string $html     PDF content
802
     * @param string $fileName File name
803
     * @param string $dest     Optional. Directory to move file
804
     *
805
     * @return string The PDF path
806
     */
807
    public function exportFromHtmlToFile($html, $fileName, $dest = null)
808
    {
809
        $this->template = $this->template ?: new Template('', false, false, false, false, false, false);
810
811
        $cssFile = api_get_path(SYS_CSS_PATH).'themes/'.$this->template->theme.'/print.css';
812
813
        if (!file_exists($cssFile)) {
814
            $cssFile = api_get_path(SYS_CSS_PATH).'print.css';
815
        }
816
817
        $pdfPath = self::content_to_pdf(
0 ignored issues
show
Bug Best Practice introduced by
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 ignore-call  annotation

817
        /** @scrutinizer ignore-call */ 
818
        $pdfPath = self::content_to_pdf(
Loading history...
818
            $html,
819
            file_get_contents($cssFile),
820
            $fileName,
821
            $this->params['course_code'],
822
            'F'
823
        );
824
825
        if (!$dest) {
826
            return $pdfPath;
827
        }
828
829
        move($pdfPath, $dest);
830
831
        return $dest.basename($pdfPath);
832
    }
833
834
    /**
835
     * Create a PDF and save it into the documents area.
836
     *
837
     * @param string $htmlContent HTML Content
838
     * @param string $fileName    The file name
839
     * @param int    $courseId    The course ID
840
     * @param int    $sessionId   Optional. The session ID
841
     */
842
    public function exportFromHtmlToDocumentsArea(
843
        $htmlContent,
844
        $fileName,
845
        $courseId,
846
        $sessionId = 0
847
    ) {
848
        $userId = api_get_user_id();
849
        $courseInfo = api_get_course_info_by_id($courseId);
850
        $courseDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document/';
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
851
852
        $docPath = $this->exportFromHtmlToFile(
853
            $htmlContent,
854
            $fileName,
855
            $courseDirectory
856
        );
857
858
        DocumentManager::addDocument(
859
            $courseInfo,
860
            str_replace($courseDirectory, '/', $docPath),
861
            'file',
862
            filesize($docPath),
863
            $fileName,
864
            null,
865
            false,
866
            true,
867
            null,
868
            $sessionId,
869
            $userId
870
        );
871
872
        Display::addFlash(Display::return_message(get_lang('Item added')));
873
    }
874
875
    /**
876
     * @param string $theme
877
     *
878
     * @throws MpdfException
879
     */
880
    public function setBackground($theme)
881
    {
882
        $themeName = empty($theme) ? api_get_visual_theme() : $theme;
883
        $themeDir = \Template::getThemeDir($themeName);
884
        $customLetterhead = $themeDir.'images/letterhead.png';
885
        $urlPathLetterhead = api_get_path(SYS_CSS_PATH).$customLetterhead;
886
887
        $urlWebLetterhead = '#FFFFFF';
888
        $fullPage = false;
889
        if (file_exists($urlPathLetterhead)) {
890
            $fullPage = true;
891
            $urlWebLetterhead = 'url('.api_get_path(WEB_CSS_PATH).$customLetterhead.')';
892
        }
893
894
        if ($fullPage) {
895
            $this->pdf->SetDisplayMode('fullpage');
896
            $this->pdf->SetDefaultBodyCSS('background', $urlWebLetterhead);
897
            $this->pdf->SetDefaultBodyCSS('background-image-resize', '6');
898
        }
899
    }
900
901
    /**
902
     * Fix images source paths to allow export to pdf.
903
     *
904
     * @param string $documentHtml
905
     * @param string $dirName
906
     *
907
     * @return string
908
     */
909
    private static function fixImagesPaths($documentHtml, array $courseInfo, $dirName = '')
910
    {
911
        $html = new HTML5();
912
        $doc = $html->loadHTML($documentHtml);
913
914
        $elements = $doc->getElementsByTagName('img');
915
916
        if (empty($elements)) {
917
            return $doc->saveHTML();
918
        }
919
920
        $protocol = api_get_protocol();
921
        $sysCodePath = api_get_path(SYS_CODE_PATH);
922
        $sysCoursePath = api_get_path(SYS_COURSE_PATH);
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
923
        $sysUploadPath = api_get_path(SYS_UPLOAD_PATH);
924
925
        $documentPath = $courseInfo ? $sysCoursePath.$courseInfo['path'].'/document/' : '';
926
927
        /** @var \DOMElement $element */
928
        foreach ($elements as $element) {
929
            $src = $element->getAttribute('src');
930
            $src = trim($src);
931
932
            if (false !== strpos($src, $protocol)) {
933
                continue;
934
            }
935
936
            // It's a reference to a file in the system, do not change it
937
            if (file_exists($src)) {
938
                continue;
939
            }
940
941
            if (0 === strpos($src, '/main/default_course_document')) {
942
                $element->setAttribute(
943
                    'src',
944
                    str_replace('/main/default_course_document', $sysCodePath.'default_course_document', $src)
945
                );
946
                continue;
947
            }
948
949
            if (0 === strpos($src, '/main/img')) {
950
                $element->setAttribute(
951
                    'src',
952
                    str_replace('/main/img/', $sysCodePath.'img/', $src)
953
                );
954
                continue;
955
            }
956
957
            if (0 === strpos($src, '/app/upload/')) {
958
                $element->setAttribute(
959
                    'src',
960
                    str_replace('/app/upload/', $sysUploadPath, $src)
961
                );
962
                continue;
963
            }
964
965
            if (empty($courseInfo)) {
966
                continue;
967
            }
968
969
            if ('/' != api_get_path(REL_PATH)) {
970
                $oldSrcFixed = str_replace(
971
                    api_get_path(REL_PATH).'courses/'.$courseInfo['path'].'/document/',
972
                    '',
973
                    $src
974
                );
975
976
                // Try with the dirname if exists
977
                if ($oldSrcFixed == $src) {
978
                    if (file_exists($dirName.'/'.$src)) {
979
                        $documentPath = '';
980
                        $oldSrcFixed = $dirName.'/'.$src;
981
                    }
982
                }
983
            } else {
984
                if (false !== strpos($src, 'courses/'.$courseInfo['path'].'/document/')) {
985
                    $oldSrcFixed = str_replace('courses/'.$courseInfo['path'].'/document/', '', $src);
986
                } else {
987
                    // Try with the dirname if exists
988
                    if (file_exists($dirName.'/'.$src)) {
989
                        $documentPath = '';
990
                        $oldSrcFixed = $dirName.'/'.$src;
991
                    } else {
992
                        $documentPath = '';
993
                        $oldSrcFixed = $src;
994
                    }
995
                }
996
            }
997
998
            $element->setAttribute('src', $documentPath.$oldSrcFixed);
999
        }
1000
1001
        return $doc->saveHTML();
1002
    }
1003
}
1004