1 | <?php |
||||||
2 | declare(strict_types = 1); |
||||||
3 | |||||||
4 | namespace Phauthentic\Presentation\Renderer; |
||||||
5 | |||||||
6 | use InvalidArgumentException; |
||||||
7 | use Phauthentic\Presentation\View\PdfViewInterface; |
||||||
8 | use Phauthentic\Presentation\View\ViewInterface; |
||||||
9 | use RuntimeException; |
||||||
10 | |||||||
11 | /** |
||||||
12 | * WkhtmlToPdf Renderer |
||||||
13 | */ |
||||||
14 | class WkhtmlToPdfRenderer |
||||||
15 | { |
||||||
16 | /** |
||||||
17 | * Binary |
||||||
18 | * |
||||||
19 | * @var string |
||||||
20 | */ |
||||||
21 | protected $binary = '/usr/bin/wkhtmltopdf'; |
||||||
22 | |||||||
23 | /** |
||||||
24 | * Is it running on windows |
||||||
25 | * |
||||||
26 | * @var bool |
||||||
27 | */ |
||||||
28 | protected $isWindowsEnvironment = false; |
||||||
29 | |||||||
30 | /** |
||||||
31 | * Cwd for phps proc_open fourth argument |
||||||
32 | * |
||||||
33 | * @var string|null |
||||||
34 | */ |
||||||
35 | protected $cwd = null; |
||||||
36 | |||||||
37 | /** |
||||||
38 | * Sets the path for the wkhtmltopdf binary |
||||||
39 | * |
||||||
40 | * @return $this |
||||||
41 | */ |
||||||
42 | public function setBinary(string $binary): self |
||||||
43 | { |
||||||
44 | if (!file_exists($binary)) { |
||||||
45 | throw new InvalidArgumentException(sprintf('Binary %s does not exist', $binary)); |
||||||
46 | } |
||||||
47 | |||||||
48 | if (!is_executable($binary)) { |
||||||
49 | throw new RuntimeException(sprintf('%s not a binary or can not be executed', $binary)); |
||||||
50 | } |
||||||
51 | |||||||
52 | $this->binary = $binary; |
||||||
53 | |||||||
54 | return $this; |
||||||
55 | } |
||||||
56 | |||||||
57 | /** |
||||||
58 | * Constructor |
||||||
59 | * |
||||||
60 | * @param array $options Options |
||||||
61 | */ |
||||||
62 | 1 | public function __construct(array $options = []) |
|||||
63 | { |
||||||
64 | 1 | $this->options = $options; |
|||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||||
65 | 1 | $this->cwd = sys_get_temp_dir(); |
|||||
66 | 1 | $this->isWindowsEnvironment = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; |
|||||
67 | |||||||
68 | 1 | if ($this->isWindowsEnvironment) { |
|||||
69 | $this->setBinary('C:/Progra~1/wkhtmltopdf/bin/wkhtmltopdf.exe'); |
||||||
70 | } |
||||||
71 | 1 | } |
|||||
72 | |||||||
73 | /** |
||||||
74 | * Generates Pdf from html |
||||||
75 | * |
||||||
76 | * @return string Raw PDF data |
||||||
77 | * @throws \Exception If no output is generated to stdout by wkhtmltopdf. |
||||||
78 | */ |
||||||
79 | 1 | public function render(PdfViewInterface $view): string |
|||||
80 | { |
||||||
81 | 1 | $command = $this->buildCommand($view); |
|||||
82 | 1 | $content = $this->exec($command, $view->getHtml()); |
|||||
0 ignored issues
–
show
The method
getHtml() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
83 | |||||||
84 | 1 | if (!empty($content['stdout'])) { |
|||||
85 | 1 | return $content['stdout']; |
|||||
86 | } |
||||||
87 | |||||||
88 | if (!empty($content['stderr'])) { |
||||||
89 | throw new RuntimeException(sprintf( |
||||||
90 | 'System error "%s" when executing command "%s". ' . |
||||||
91 | 'Try using the binary provided on http://wkhtmltopdf.org/downloads.html', |
||||||
92 | $content['stderr'], |
||||||
93 | $command |
||||||
94 | )); |
||||||
95 | } |
||||||
96 | |||||||
97 | throw new RuntimeException("WKHTMLTOPDF didn't return any data"); |
||||||
98 | } |
||||||
99 | |||||||
100 | /** |
||||||
101 | * Execute the WkHtmlToPdf commands for rendering pdfs |
||||||
102 | * |
||||||
103 | * @param string $cmd the command to execute |
||||||
104 | * @param string $input Html to pass to wkhtmltopdf |
||||||
105 | * @return array the result of running the command to generate the pdf |
||||||
106 | */ |
||||||
107 | 1 | protected function exec($cmd, $input) |
|||||
108 | { |
||||||
109 | 1 | $result = ['stdout' => '', 'stderr' => '', 'return' => '']; |
|||||
110 | |||||||
111 | 1 | $proc = proc_open($cmd, [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $this->cwd); |
|||||
112 | 1 | fwrite($pipes[0], $input); |
|||||
113 | 1 | fclose($pipes[0]); |
|||||
114 | |||||||
115 | 1 | $result['stdout'] = stream_get_contents($pipes[1]); |
|||||
116 | 1 | fclose($pipes[1]); |
|||||
117 | |||||||
118 | 1 | $result['stderr'] = stream_get_contents($pipes[2]); |
|||||
119 | 1 | fclose($pipes[2]); |
|||||
120 | |||||||
121 | 1 | $result['return'] = proc_close($proc); |
|||||
0 ignored issues
–
show
It seems like
$proc can also be of type false ; however, parameter $process of proc_close() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
122 | |||||||
123 | 1 | return $result; |
|||||
124 | } |
||||||
125 | |||||||
126 | /** |
||||||
127 | * Get the command to render a pdf |
||||||
128 | * |
||||||
129 | * |
||||||
130 | * @return string the command for generating the pdf |
||||||
131 | */ |
||||||
132 | 1 | protected function buildCommand(PdfViewInterface $pdfView): string |
|||||
133 | { |
||||||
134 | $options = [ |
||||||
135 | 1 | 'quiet' => true, |
|||||
136 | 'print-media-type' => true, |
||||||
137 | 1 | 'orientation' => $pdfView->getOrientation(), |
|||||
138 | 1 | 'page-size' => $pdfView->getPageSize(), |
|||||
139 | 1 | 'encoding' => $pdfView->getEncoding(), |
|||||
140 | 1 | 'title' => $pdfView->getTitle(), |
|||||
0 ignored issues
–
show
The method
getTitle() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
141 | 1 | 'javascript-delay' => $pdfView->getJsDelay(), |
|||||
0 ignored issues
–
show
The method
getJsDelay() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
142 | 1 | 'window-status' => $pdfView->getWindowStatus(), |
|||||
0 ignored issues
–
show
The method
getWindowStatus() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
143 | ]; |
||||||
144 | |||||||
145 | 1 | $margin = $pdfView->getMargin(); |
|||||
0 ignored issues
–
show
The method
getMargin() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
146 | 1 | foreach ($margin as $key => $value) { |
|||||
147 | 1 | if ($value !== null) { |
|||||
148 | 1 | $options['margin-' . $key] = $value . 'mm'; |
|||||
149 | } |
||||||
150 | } |
||||||
151 | 1 | $options = array_merge($options, (array)$this->options); |
|||||
152 | |||||||
153 | 1 | if ($this->isWindowsEnvironment) { |
|||||
154 | $command = '"' . $this->binary . '"'; |
||||||
155 | } else { |
||||||
156 | 1 | $command = $this->binary; |
|||||
157 | } |
||||||
158 | |||||||
159 | 1 | foreach ($options as $key => $value) { |
|||||
160 | 1 | if (empty($value)) { |
|||||
161 | 1 | continue; |
|||||
162 | 1 | } elseif (is_array($value)) { |
|||||
163 | foreach ($value as $k => $v) { |
||||||
164 | $command .= sprintf(' --%s %s %s', $key, escapeshellarg($k), escapeshellarg($v)); |
||||||
165 | } |
||||||
166 | 1 | } elseif ($value === true) { |
|||||
167 | 1 | $command .= ' --' . $key; |
|||||
168 | } else { |
||||||
169 | 1 | $command .= sprintf(' --%s %s', $key, escapeshellarg($value)); |
|||||
170 | } |
||||||
171 | } |
||||||
172 | 1 | $footer = $pdfView->footer(); |
|||||
0 ignored issues
–
show
The method
footer() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
173 | 1 | foreach ($footer as $location => $text) { |
|||||
174 | 1 | if ($text !== null) { |
|||||
175 | 1 | $command .= " --footer-$location \"" . addslashes($text) . "\""; |
|||||
176 | } |
||||||
177 | } |
||||||
178 | |||||||
179 | 1 | $header = $pdfView->header(); |
|||||
0 ignored issues
–
show
The method
header() does not exist on Phauthentic\Presentation\View\PdfViewInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
180 | 1 | foreach ($header as $location => $text) { |
|||||
181 | 1 | if ($text !== null) { |
|||||
182 | 1 | $command .= " --header-$location \"" . addslashes($text) . "\""; |
|||||
183 | } |
||||||
184 | } |
||||||
185 | 1 | $command .= " - -"; |
|||||
186 | |||||||
187 | 1 | if ($this->isWindowsEnvironment) { |
|||||
188 | $command = '"' . $command . '"'; |
||||||
189 | } |
||||||
190 | |||||||
191 | 1 | return $command; |
|||||
192 | } |
||||||
193 | } |
||||||
194 |