1<?php
2
3require_once './Services/PDFGeneration/classes/class.ilPDFGenerationConstants.php';
4require_once './Services/PDFGeneration/interfaces/interface.ilRendererConfig.php';
5require_once './Services/PDFGeneration/interfaces/interface.ilPDFRenderer.php';
6
7class ilPhantomJSRenderer implements ilRendererConfig, ilPDFRenderer
8{
9    const PAGE = 0;
10    const VIEWPORT = 1;
11
12    /** @var ilLanguage $lng */
13    protected $lng;
14
15    /** @var string */
16    protected $path_to_rasterize = './Services/PDFGeneration/js/rasterize.js';
17
18    public function __construct($phpunit = false)
19    {
20        if (!$phpunit) {
21            global $DIC;
22            $this->setLanguage($DIC['lng']);
23        }
24    }
25
26    /**
27     * @param $lng
28     */
29    protected function setLanguage($lng)
30    {
31        $this->lng = $lng;
32    }
33
34    /**
35     * @var bool
36     */
37    protected $use_default_config;
38
39    /**
40     * @var string
41     */
42    protected $page_size;
43
44    /**
45     * @var string
46     */
47    protected $orientation;
48
49    /**
50     * @var string
51     */
52    protected $margin;
53
54    /**
55     * @var int
56     */
57    protected $javascript_delay;
58
59    /**
60     * @var string
61     */
62    protected $viewport;
63
64    /**
65     * @var int
66     */
67    protected $header_type;
68
69    /**
70     * @var int
71     */
72    protected $footer_type;
73
74    /**
75     * @var string
76     */
77    protected $header_text;
78
79    /**
80     * @var string
81     */
82    protected $header_height;
83
84    /**
85     * @var bool
86     */
87    protected $header_show_pages;
88
89    /**
90     * @var string
91     */
92    protected $footer_text;
93
94    /**
95     * @var string
96     */
97    protected $footer_height;
98
99    /**
100     * @var bool
101     */
102    protected $footer_show_pages;
103
104    /**
105     * @var string
106     */
107    protected $path;
108
109    /**
110     * @var int
111     */
112    protected $page_type = self::PAGE;
113
114    /**
115     * @return string
116     */
117    public function getPluginName()
118    {
119        return $this->lng->txt('pdfgen_renderer_dummyrender_plugname');
120    }
121
122    /**
123     * @var string
124     */
125    protected $do_not_validate_ssl = ' --ssl-protocol=any --ignore-ssl-errors=true ';
126
127    /**
128     * from ilRendererConfig
129     *
130     * @param \ilPropertyFormGUI $form
131     * @param string             $service
132     * @param string             $purpose
133     *
134     * @return \ilPropertyFormGUI|void
135     */
136    public function addConfigElementsToForm(\ilPropertyFormGUI $form, $service, $purpose)
137    {
138        $path = new ilTextInputGUI($this->lng->txt('path'), 'path');
139        $path->setValue($this->path);
140        $form->addItem($path);
141
142        $item_group = new ilRadioGroupInputGUI($this->lng->txt('page_settings'), 'page_type');
143
144        $op = new ilRadioOption($this->lng->txt('page'), self::PAGE);
145        $op->addSubItem($this->buildMarginForm());
146        $op->addSubItem($this->buildOrientationForm());
147        $op->addSubItem($this->buildPageSizesForm());
148        $header_select = new ilRadioGroupInputGUI($this->lng->txt('header_type'), 'header_select');
149        $header_select->addOption(new ilRadioOption($this->lng->txt('none'), ilPDFGenerationConstants::HEADER_NONE, ''));
150        $header_text = new ilRadioOption($this->lng->txt('text'), ilPDFGenerationConstants::HEADER_TEXT, '');
151        $header_text->addSubItem($this->buildHeaderTextForm());
152        $header_text->addSubItem($this->buildHeaderHeightForm());
153        $header_text->addSubItem($this->buildHeaderPageNumbersForm());
154        $header_select->addOption($header_text);
155        $header_select->setValue($this->header_type);
156        $op->addSubItem($header_select);
157        $footer_select = new ilRadioGroupInputGUI($this->lng->txt('footer_type'), 'footer_select');
158        $footer_select->addOption(new ilRadioOption($this->lng->txt('none'), ilPDFGenerationConstants::FOOTER_NONE, ''));
159        $footer_text = new ilRadioOption($this->lng->txt('text'), ilPDFGenerationConstants::FOOTER_TEXT, '');
160        $footer_text->addSubItem($this->buildFooterTextForm());
161        $footer_text->addSubItem($this->buildFooterHeightForm());
162        $footer_text->addSubItem($this->buildFooterPageNumbersForm());
163        $footer_select->addOption($footer_text);
164        $footer_select->setValue($this->footer_type);
165        $op->addSubItem($footer_select);
166        $item_group->addOption($op);
167
168        $op = new ilRadioOption($this->lng->txt('viewport'), self::VIEWPORT);
169        $op->addSubItem($this->buildViewPortForm());
170        $item_group->addOption($op);
171        $item_group->setValue($this->page_type);
172        $form->addItem($item_group);
173
174        $form->addItem($this->buildJavascriptDelayForm());
175    }
176
177    /**
178     * from ilRendererConfig
179     *
180     * @param \ilPropertyFormGUI $form
181     * @param string             $service
182     * @param string             $purpose
183     * @param array              $config
184     *
185     * @return void
186     */
187    public function populateConfigElementsInForm(\ilPropertyFormGUI $form, $service, $purpose, $config)
188    {
189        $form->getItemByPostVar('path')->setValue($config['path']);
190        $form->getItemByPostVar('page_size')->setValue($config['page_size']);
191        $form->getItemByPostVar('margin')->setValue($config['margin']);
192        $form->getItemByPostVar('javascript_delay')->setValue($config['javascript_delay']);
193        $form->getItemByPostVar('viewport')->setValue($config['viewport']);
194        $form->getItemByPostVar('orientation')->setValue($config['orientation']);
195        $form->getItemByPostVar('header_select')->setValue($config['header_type']);
196        $form->getItemByPostVar('header_text')->setValue($config['header_text']);
197        $form->getItemByPostVar('header_height')->setValue($config['header_height']);
198        $form->getItemByPostVar('header_show_pages')->setChecked($config['header_show_pages']);
199        $form->getItemByPostVar('footer_select')->setValue($config['footer_type']);
200        $form->getItemByPostVar('footer_text')->setValue($config['footer_text']);
201        $form->getItemByPostVar('footer_height')->setValue($config['footer_height']);
202        $form->getItemByPostVar('footer_show_pages')->setChecked($config['footer_show_pages']);
203        $form->getItemByPostVar('page_type')->setValue($config['page_type']);
204
205        ilPDFGeneratorUtils::setCheckedIfTrue($form);
206    }
207
208    /**
209     * from ilRendererConfig
210     *
211     * @param \ilPropertyFormGUI $form
212     * @param string             $service
213     * @param string             $purpose
214     *
215     * @return bool
216     */
217    public function validateConfigInForm(\ilPropertyFormGUI $form, $service, $purpose)
218    {
219        if (true) {
220            return true;
221        }
222        return false;
223    }
224
225    /**
226     * from ilRendererConfig
227     *
228     * @param \ilPropertyFormGUI $form
229     * @param string             $service
230     * @param string             $purpose
231     *
232     * @return array
233     */
234    public function getConfigFromForm(\ilPropertyFormGUI $form, $service, $purpose)
235    {
236        $config = array();
237        $config['path'] = $form->getItemByPostVar('path')->getValue();
238        $config['page_size'] = $form->getItemByPostVar('page_size')->getValue();
239        $config['margin'] = $form->getItemByPostVar('margin')->getValue();
240        $config['javascript_delay'] = $form->getItemByPostVar('javascript_delay')->getValue();
241        $config['viewport'] = $form->getItemByPostVar('viewport')->getValue();
242        $config['orientation'] = $form->getItemByPostVar('orientation')->getValue();
243        $config['header_type'] = $form->getItemByPostVar('header_select')->getValue();
244        $config['header_text'] = $form->getItemByPostVar('header_text')->getValue();
245        $config['header_height'] = $form->getItemByPostVar('header_height')->getValue();
246        $config['header_show_pages'] = $form->getItemByPostVar('header_show_pages')->getChecked();
247        $config['footer_type'] = $form->getItemByPostVar('footer_select')->getValue();
248        $config['footer_text'] = $form->getItemByPostVar('footer_text')->getValue();
249        $config['footer_height'] = $form->getItemByPostVar('footer_height')->getValue();
250        $config['footer_show_pages'] = $form->getItemByPostVar('footer_show_pages')->getChecked();
251        $config['page_type'] = $form->getItemByPostVar('page_type')->getValue();
252
253        return $config;
254    }
255
256    /**
257     * from ilRendererConfig
258     *
259     * @param string $service
260     * @param string $purpose
261     *
262     * @return array
263     */
264    public function getDefaultConfig($service, $purpose)
265    {
266        $config = array();
267        if (PATH_TO_PHANTOMJS !== '') {
268            $config['path'] = PATH_TO_PHANTOMJS;
269        } else {
270            $config['path'] = '/usr/local/bin/phantomjs';
271        }
272
273        $config['page_size'] = 'A4';
274        $config['margin'] = '1cm';
275        $config['javascript_delay'] = 200;
276        $config['viewport'] = '';
277        $config['orientation'] = 'Portrait';
278        $config['header_type'] = 0;
279        $config['header_text'] = '';
280        $config['header_height'] = '0cm';
281        $config['header_show_pages'] = 0;
282        $config['footer_type'] = 0;
283        $config['footer_text'] = '';
284        $config['footer_height'] = '0cm';
285        $config['footer_show_pages'] = 0;
286        $config['page_type'] = self::PAGE;
287
288        return $config;
289    }
290
291
292    /**
293     * Prepare the content processing at the beginning of a PDF generation request
294     * Should be used to initialize the processing of latex code
295     * The PDF renderers require different image formats generated by the MathJax service
296     *
297     * @param string              $service
298     * @param string              $purpose
299     * @return void
300     */
301    public function prepareGenerationRequest($service, $purpose)
302    {
303        ilMathJax::getInstance()
304            ->init(ilMathJax::PURPOSE_PDF)
305             ->setRendering(ilMathJax::RENDER_SVG_AS_XML_EMBED);
306    }
307
308
309    /**
310     * from ilPDFRenderer
311     *
312     * @param string              $service
313     * @param string              $purpose
314     * @param array               $config
315     * @param \ilPDFGenerationJob $job
316     *
317     * @return string|void
318     */
319    public function generatePDF($service, $purpose, $config, $job)
320    {
321        $html_file = $this->getHtmlTempName();
322        file_put_contents($html_file, implode('', $job->getPages()));
323        $this->createPDFFileFromHTMLFile($html_file, $config, $job);
324    }
325
326    /**
327     * @param $a_path_to_file
328     * @param $config
329     * @param ilPDFGenerationJob $job
330     */
331    public function createPDFFileFromHTMLFile($a_path_to_file, $config, $job)
332    {
333        /** @var ilLog $ilLog */
334        global $ilLog;
335
336        if (file_exists($a_path_to_file)) {
337            $temp_file = $this->getPdfTempName();
338
339            $args = ' ' . $a_path_to_file . ' ' . $temp_file . ' ' . $this->getCommandLineConfig($config);
340            $return_value = ilUtil::execQuoted($config['path'], $this->do_not_validate_ssl . ' ' . $this->path_to_rasterize . ' ' . $args);
341
342            $ilLog->write('ilPhantomJSRenderer command line config: ' . $args);
343            foreach ($return_value as $key => $value) {
344                $ilLog->write('ilPhantomJSRenderer return value line ' . $key . ' : ' . $value);
345            }
346
347            if (file_exists($temp_file)) {
348                $ilLog->write('ilPhantomJSRenderer file exists: ' . $temp_file . ' file size is :' . filesize($temp_file) . ' bytes, will be renamed to ' . $job->getFilename());
349                ilFileUtils::rename($temp_file, $job->getFilename());
350            } else {
351                $ilLog->write('ilPhantomJSRenderer error: ' . print_r($return_value, true));
352            }
353        }
354    }
355
356    /**
357     * @return ilTextInputGUI
358     */
359    protected function buildHeaderTextForm()
360    {
361        $header_text = new ilTextInputGUI($this->lng->txt('head_text'), 'header_text');
362        $header_text->setValue($this->header_text);
363        return $header_text;
364    }
365
366    /**
367     * @return ilTextInputGUI
368     */
369    protected function buildHeaderHeightForm()
370    {
371        $header_height = new ilTextInputGUI($this->lng->txt('header_height'), 'header_height');
372        $header_height->setValue($this->header_height);
373        return $header_height;
374    }
375
376    /**
377     * @return ilTextInputGUI
378     */
379    protected function buildViewPortForm()
380    {
381        $viewport = new ilTextInputGUI($this->lng->txt('viewport'), 'viewport');
382        $viewport->setValue($this->viewport);
383        $viewport->setInfo($this->lng->txt('viewport_info'));
384        return $viewport;
385    }
386
387    /**
388     * @return ilCheckboxInputGUI
389     */
390    protected function buildHeaderPageNumbersForm()
391    {
392        $header_show_pages = new ilCheckboxInputGUI($this->lng->txt('header_show_pages'), 'header_show_pages');
393        if ($this->header_show_pages == true || $this->header_show_pages == 1) {
394            $header_show_pages->setChecked(true);
395        }
396        return $header_show_pages;
397    }
398
399    /**
400     * @return ilTextInputGUI
401     */
402    protected function buildFooterTextForm()
403    {
404        $footer_text = new ilTextInputGUI($this->lng->txt('footer_text'), 'footer_text');
405        $footer_text->setValue($this->footer_text);
406        return $footer_text;
407    }
408
409    /**
410     * @return ilTextInputGUI
411     */
412    protected function buildFooterHeightForm()
413    {
414        $footer_height = new ilTextInputGUI($this->lng->txt('footer_height'), 'footer_height');
415        $footer_height->setValue($this->footer_height);
416        return $footer_height;
417    }
418
419    /**
420     * @return ilCheckboxInputGUI
421     */
422    protected function buildFooterPageNumbersForm()
423    {
424        $footer_show_pages = new ilCheckboxInputGUI($this->lng->txt('footer_show_pages'), 'footer_show_pages');
425        if ($this->footer_show_pages == true || $this->footer_show_pages == 1) {
426            $footer_show_pages->setChecked(true);
427        }
428        return $footer_show_pages;
429    }
430
431    /**
432     * @return ilSelectInputGUI
433     */
434    protected function buildPageSizesForm()
435    {
436        $page_size = new ilSelectInputGUI($this->lng->txt('page_size'), 'page_size');
437        $page_size->setOptions(ilPDFGenerationConstants::getPageSizesNames());
438        $page_size->setValue($this->page_size);
439        return $page_size;
440    }
441
442    /**
443     * @return ilSelectInputGUI
444     */
445    protected function buildOrientationForm()
446    {
447        $orientation = new ilSelectInputGUI($this->lng->txt('orientation'), 'orientation');
448        $orientation->setOptions(ilPDFGenerationConstants::getOrientations());
449        $orientation->setValue($this->orientation);
450        return $orientation;
451    }
452
453    /**
454     * @return ilTextInputGUI
455     */
456    protected function buildMarginForm()
457    {
458        $margin = new ilTextInputGUI($this->lng->txt('margin'), 'margin');
459        $margin->setValue($this->margin);
460        return $margin;
461    }
462
463    /**
464     * @return ilTextInputGUI
465     */
466    protected function buildJavascriptDelayForm()
467    {
468        $javascript_delay = new ilTextInputGUI($this->lng->txt('javascript_delay'), 'javascript_delay');
469        $javascript_delay->setInfo($this->lng->txt('javascript_delay_info'));
470        $javascript_delay->setValue($this->javascript_delay);
471        return $javascript_delay;
472    }
473
474    /**
475     * @return string
476     */
477    public function getPdfTempName()
478    {
479        return $this->getTempFileName('pdf');
480    }
481
482    /**
483     * @return string
484     */
485    public function getHtmlTempName()
486    {
487        return $this->getTempFileName('html');
488    }
489
490    /**
491     * @param $file_type
492     * @return string
493     */
494    protected function getTempFileName($file_type)
495    {
496        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && $file_type == 'html') {
497            return 'file:///' . str_replace(':/', '://', ilUtil::ilTempnam()) . '.' . $file_type;
498        } else {
499            return ilUtil::ilTempnam() . '.' . $file_type;
500        }
501    }
502
503    /**
504     * @param $config
505     *
506     * @return string
507     */
508    protected function getCommandLineConfig($config)
509    {
510        $r_config = array();
511
512        if ($config['header_type'] == ilPDFGenerationConstants::HEADER_TEXT) {
513            $h_config = array(
514                'text' => $config['header_text'],
515                'height' => $config['header_height'],
516                'show_pages' => $config['header_show_pages']);
517        } else {
518            $h_config = null;
519        }
520
521        if ($config['footer_type'] == ilPDFGenerationConstants::FOOTER_TEXT) {
522            $f_config = array(
523                'text' => $config['footer_text'],
524                'height' => $config['footer_height'],
525                'show_pages' => $config['footer_show_pages']);
526        } else {
527            $f_config = null;
528        }
529
530        $r_config['page_size'] = $config['page_size'];
531        $r_config['orientation'] = $config['orientation'];
532        $r_config['margin'] = $config['margin'];
533        $r_config['delay'] = $config['javascript_delay'];
534        $r_config['viewport'] = $config['viewport'];
535        $r_config['header'] = $h_config;
536        $r_config['footer'] = $f_config;
537        $r_config['page_type'] = $config['page_type'];
538
539        return json_encode(json_encode($r_config));
540    }
541}
542