Passed
Push — master ( 271415...ff556a )
by Julito
09:26
created

PDF::fixImagesPaths()   C

Complexity

Conditions 15
Paths 27

Size

Total Lines 93
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 55
nc 27
nop 3
dl 0
loc 93
rs 5.9166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

232
        self::/** @scrutinizer ignore-call */ 
233
              format_pdf($courseInfo, $complete_style);
Loading history...
233
234
        $counter = 1;
235
        foreach ($htmlFileArray as $file) {
236
            //Add a page break per file
237
            $pageBreak = '<pagebreak>';
238
            if ($counter == count($htmlFileArray)) {
239
                $pageBreak = '';
240
            }
241
242
            //if the array provided contained subarrays with 'title' entry,
243
            // then print the title in the PDF
244
            if (is_array($file) && isset($file['title'])) {
245
                $htmlTitle = $file['title'];
246
                $file = $file['path'];
247
            } else {
248
                //we suppose we've only been sent a file path
249
                $htmlTitle = basename($file);
250
            }
251
252
            $counter++;
253
254
            if (empty($file) && !empty($htmlTitle)) {
255
                // this is a chapter, print title & skip the rest
256
                if ($counter === 2 && !empty($mainTitle)) {
257
                    $this->pdf->WriteHTML(
258
                        '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>'
259
                    );
260
                }
261
                if ($printTitle) {
262
                    $this->pdf->WriteHTML(
263
                        '<html><body><h3>'.$html_title.'</h3></body></html>'.$page_break
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $html_title does not exist. Did you maybe mean $htmlTitle?
Loading history...
Comprehensibility Best Practice introduced by
The variable $page_break does not exist. Did you maybe mean $pageBreak?
Loading history...
264
                    );
265
                }
266
                continue;
267
            } else {
268
                if ($counter === 2 && !empty($mainTitle)) {
269
                    $this->pdf->WriteHTML(
270
                        '<html><body><h2 style="text-align: center">'.$mainTitle.'</h2></body></html>'
271
                    );
272
                }
273
            }
274
275
            if (!file_exists($file)) {
276
                // the file doesn't exist, skip
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 ($extension === 'html') {
300
                    $filename = basename($filename, '.html');
301
                } elseif ($extension === 'htm') {
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
                //echo $documentHtml;exit;
330
                if (empty($title)) {
331
                    $title = $filename; // Here file name is expected to contain ASCII symbols only.
332
                }
333
334
                if (!empty($documentHtml)) {
335
                    $this->pdf->WriteHTML($documentHtml.$pageBreak, 2);
336
                }
337
            } elseif (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) {
338
                // Images
339
                $image = Display::img($file);
340
                $this->pdf->WriteHTML('<html><body>'.$image.'</body></html>'.$pageBreak, 2);
341
            }
342
        }
343
344
        $outputFile = 'pdf_'.api_get_local_time().'.pdf';
345
        if (!empty($pdfName)) {
346
            $outputFile = $pdfName.'.pdf';
347
        }
348
349
        $outputFile = api_replace_dangerous_char($outputFile);
350
351
        // F to save the pdf in a file
352
        $this->pdf->Output($outputFile, Destination::DOWNLOAD);
353
        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...
354
    }
355
356
    /**
357
     * Converts an html string to PDF.
358
     *
359
     * @param string $document_html  valid html
360
     * @param string $css            CSS content of a CSS file
361
     * @param string $pdf_name       pdf name
362
     * @param string $courseCode     course code
363
     *                               (if you are using html that are located in the document tool you must provide this)
364
     * @param string $outputMode     the MPDF output mode can be:
365
     * @param bool   $saveInFile
366
     * @param string $fileToSave
367
     * @param bool   $returnHtml
368
     * @param bool   $addDefaultCss
369
     * @param bool   $completeHeader
370
     *
371
     * 'I' (print on standard output),
372
     * 'D' (download file) (this is the default value),
373
     * 'F' (save to local file) or
374
     * 'S' (return as a string)
375
     *
376
     * @return string Web path
377
     */
378
    public function content_to_pdf(
379
        $document_html,
380
        $css = '',
381
        $pdf_name = '',
382
        $courseCode = null,
383
        $outputMode = 'D',
384
        $saveInFile = false,
385
        $fileToSave = null,
386
        $returnHtml = false,
387
        $addDefaultCss = false,
388
        $completeHeader = true
389
    ) {
390
        $urlAppend = api_get_configuration_value('url_append');
391
392
        if (empty($document_html)) {
393
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
394
        }
395
396
        // clean styles and javascript document
397
        $clean_search = [
398
            '@<script[^>]*?>.*?</script>@si',
399
            '@<style[^>]*?>.*?</style>@siU',
400
        ];
401
402
        // Formatting the pdf
403
        $courseInfo = api_get_course_info($courseCode);
404
        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

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

422
            /** @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...
423
424
            //Fixing only images @todo do the same thing with other elements
425
            $elements = $doc->getElementsByTagName('img');
426
            $protocol = api_get_protocol();
427
            $replaced = [];
428
            if (!empty($elements)) {
429
                foreach ($elements as $item) {
430
                    $old_src = $item->getAttribute('src');
431
432
                    if (in_array($old_src, $replaced)) {
433
                        continue;
434
                    }
435
436
                    if (strpos($old_src, $protocol) === false) {
437
                        if (strpos($old_src, '/main/default_course_document') === false) {
438
                            if (strpos($old_src, '/main/inc/lib/') === false &&
439
                                strpos($old_src, '/app/upload/') === false
440
                            ) {
441
                                $old_src_fixed = str_replace(
442
                                    api_get_path(REL_COURSE_PATH).$courseInfo['path'].'/document/',
443
                                    '',
444
                                    $old_src
445
                                );
446
                                $old_src_fixed = str_replace(
447
                                    'courses/'.$courseInfo['path'].'/document/',
448
                                    '',
449
                                    $old_src_fixed
450
                                );
451
                                $new_path = $document_path.$old_src_fixed;
452
                                $document_html = str_replace($old_src, $new_path, $document_html);
453
                                $replaced[] = $old_src;
454
                            }
455
                        }
456
                    }
457
                }
458
            }
459
        }
460
461
        // Use sys path to correct export images
462
        $document_html = str_replace(
463
            api_get_path(WEB_CODE_PATH).'img/',
464
            api_get_path(SYS_CODE_PATH).'img/',
465
            $document_html
466
        );
467
        $document_html = str_replace(api_get_path(WEB_ARCHIVE_PATH), api_get_path(SYS_ARCHIVE_PATH), $document_html);
468
469
        // The library mPDF expects UTF-8 encoded input data.
470
        api_set_encoding_html($document_html, 'UTF-8');
471
        // At the moment the title is retrieved from the html document itself.
472
        if ($returnHtml) {
473
            return "<style>$css</style>".$document_html;
474
        }
475
476
        if (!empty($css)) {
477
            $this->pdf->WriteHTML($css, 1);
478
        }
479
480
        if ($addDefaultCss) {
481
            $basicStyles = [
482
                api_get_bootstrap_and_font_awesome(true),
483
                api_get_path(SYS_PATH).'web/css/base.css',
484
                api_get_path(SYS_PATH).'web/css/themes/'.api_get_visual_theme().'/default.css',
485
            ];
486
            foreach ($basicStyles as $style) {
487
                $cssContent = file_get_contents($style);
488
                $this->pdf->WriteHTML($cssContent, 1);
489
            }
490
        }
491
492
        $this->pdf->WriteHTML($document_html);
493
494
        if (empty($pdf_name)) {
495
            $output_file = 'pdf_'.date('Y-m-d-his').'.pdf';
496
        } else {
497
            $pdf_name = api_replace_dangerous_char($pdf_name);
498
            $output_file = $pdf_name.'.pdf';
499
        }
500
501
        if ($outputMode == 'F') {
502
            $output_file = api_get_path(SYS_ARCHIVE_PATH).$output_file;
503
        }
504
505
        if ($saveInFile) {
506
            $fileToSave = !empty($fileToSave) ? $fileToSave : api_get_path(SYS_ARCHIVE_PATH).uniqid();
507
508
            $this->pdf->Output(
509
                $fileToSave,
510
                $outputMode
511
            ); // F to save the pdf in a file
512
        } else {
513
            $this->pdf->Output(
514
                $output_file,
515
                $outputMode
516
            ); // F to save the pdf in a file
517
        }
518
519
        if ($outputMode != 'F') {
520
            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...
521
        }
522
523
        return $output_file;
524
    }
525
526
    /**
527
     * Gets the watermark from the platform or a course.
528
     *
529
     * @param   string  course code (optional)
530
     * @param   mixed   web path of the watermark image, false if there is nothing to return
531
     *
532
     * @return string
533
     */
534
    public static function get_watermark($courseCode = null)
535
    {
536
        $web_path = false;
537
        $urlId = api_get_current_access_url_id();
538
        if (!empty($courseCode) && api_get_setting('pdf_export_watermark_by_course') == 'true') {
539
            $course_info = api_get_course_info($courseCode);
540
            // course path
541
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
542
            if (file_exists($store_path)) {
543
                $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
544
            }
545
        } else {
546
            // course path
547
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
548
            if (file_exists($store_path)) {
549
                $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
550
            }
551
        }
552
553
        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...
554
    }
555
556
    /**
557
     * Deletes the watermark from the Platform or Course.
558
     *
559
     * @param string $courseCode course code (optional)
560
     * @param   mixed   web path of the watermark image, false if there is nothing to return
561
     *
562
     * @return bool
563
     */
564
    public function delete_watermark($courseCode = null)
565
    {
566
        $urlId = api_get_current_access_url_id();
567
        if (!empty($courseCode) && api_get_setting('pdf_export_watermark_by_course') == 'true') {
568
            $course_info = api_get_course_info($courseCode);
569
            // course path
570
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/'.$urlId.'_pdf_watermark.png';
571
        } else {
572
            // course path
573
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
574
        }
575
        if (file_exists($store_path)) {
576
            unlink($store_path);
577
578
            return true;
579
        }
580
581
        return false;
582
    }
583
584
    /**
585
     * Uploads the pdf watermark in the main/default_course_document directory or in the course directory.
586
     *
587
     * @param string $filename    filename
588
     * @param string $source_file path of the file
589
     * @param string $courseCode
590
     *
591
     * @return mixed web path of the file if sucess, false otherwise
592
     */
593
    public function upload_watermark($filename, $source_file, $courseCode = null)
0 ignored issues
show
Unused Code introduced by
The parameter $filename is not used and could be removed. ( Ignorable by Annotation )

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

593
    public function upload_watermark(/** @scrutinizer ignore-unused */ $filename, $source_file, $courseCode = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
594
    {
595
        $urlId = api_get_current_access_url_id();
596
        if (!empty($courseCode) && api_get_setting('pdf_export_watermark_by_course') == 'true') {
597
            $course_info = api_get_course_info($courseCode);
598
            $store_path = api_get_path(SYS_COURSE_PATH).$course_info['path']; // course path
599
            $web_path = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/pdf_watermark.png';
600
        } else {
601
            $store_path = api_get_path(SYS_CODE_PATH).'default_course_document/images'; // course path
602
            $web_path = api_get_path(WEB_CODE_PATH).'default_course_document/images/'.$urlId.'_pdf_watermark.png';
603
        }
604
        $course_image = $store_path.'/'.$urlId.'_pdf_watermark.png';
605
606
        if (file_exists($course_image)) {
607
            @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

607
            /** @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...
608
        }
609
        $my_image = new Image($source_file);
610
        $result = $my_image->send_image($course_image, -1, 'png');
611
        if ($result) {
612
            $result = $web_path;
613
        }
614
615
        return $result;
616
    }
617
618
    /**
619
     * Returns the default header.
620
     */
621
    public function get_header($courseCode = null)
0 ignored issues
show
Unused Code introduced by
The parameter $courseCode is not used and could be removed. ( Ignorable by Annotation )

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

621
    public function get_header(/** @scrutinizer ignore-unused */ $courseCode = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

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

765
                        /** @scrutinizer ignore-call */ 
766
                        strcode2utf($watermark_text),
Loading history...
766
                        0.1
767
                    );
768
                    $this->pdf->showWatermarkText = true;
769
                }
770
            }
771
772
            if (empty($this->custom_header)) {
773
                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

773
                self::/** @scrutinizer ignore-call */ 
774
                      set_header($courseInfo);
Loading history...
774
            } else {
775
                $this->pdf->SetHTMLHeader($this->custom_header, 'E');
776
                $this->pdf->SetHTMLHeader($this->custom_header, 'O');
777
            }
778
779
            if (empty($this->custom_footer)) {
780
                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

780
                self::/** @scrutinizer ignore-call */ 
781
                      set_footer();
Loading history...
781
            } else {
782
                $this->pdf->SetHTMLFooter($this->custom_footer);
783
            }
784
        }
785
    }
786
787
    /**
788
     * Generate a PDF file from $html in SYS_APP_PATH.
789
     *
790
     * @param string $html     PDF content
791
     * @param string $fileName File name
792
     * @param string $dest     Optional. Directory to move file
793
     *
794
     * @return string The PDF path
795
     */
796
    public function exportFromHtmlToFile($html, $fileName, $dest = null)
797
    {
798
        $this->template = $this->template ?: new Template('', false, false, false, false, false, false);
799
800
        $cssFile = api_get_path(SYS_CSS_PATH).'themes/'.$this->template->theme.'/print.css';
801
802
        if (!file_exists($cssFile)) {
803
            $cssFile = api_get_path(SYS_CSS_PATH).'print.css';
804
        }
805
806
        $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

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