Phauthentic /
presentation
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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 |