947 lines
25 KiB
PHP
947 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @author Charles SANQUER <charles.sanquer@spyrit.net>
|
|
* @author Clement Herreman <clement.herreman@pictime.com>
|
|
* @copyright aur1mas <aur1mas@devnet.lt>
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
* @see Repository: https://github.com/aur1mas/Wkhtmltopdf
|
|
* @version 1.10
|
|
*/
|
|
class Wkhtmltopdf
|
|
{
|
|
/**
|
|
* Setters / Getters properties.
|
|
*/
|
|
protected $_html = null;
|
|
protected $_url = null;
|
|
protected $_orientation = null;
|
|
protected $_pageSize = null;
|
|
protected $_toc = false;
|
|
protected $_copies = 1;
|
|
protected $_grayscale = false;
|
|
protected $_title = null;
|
|
protected $_xvfb = false;
|
|
protected $_path; // path to directory where to place files
|
|
protected $_zoom = 1;
|
|
protected $_headerSpacing;
|
|
protected $_headerHtml;
|
|
protected $_footerHtml;
|
|
protected $_username;
|
|
protected $_password;
|
|
protected $_windowStatus;
|
|
protected $_viewport;
|
|
protected $_margins = array('top' => null, 'bottom' => null, 'left' => null, 'right' => null);
|
|
protected $_userStyleSheet = null; // path to user style sheet file
|
|
protected $_enableSmartShrinking = false; // boolean for smart shrinking, defaults to false
|
|
protected $_options = array();
|
|
|
|
/**
|
|
* Path to executable.
|
|
*/
|
|
protected $_bin = '/usr/local/bin/wkhtmltopdf --enable-local-file-access --footer-font-size 7 --footer-right "Page [page] of [topage]" ';
|
|
protected $_filename = null; // filename in $path directory
|
|
|
|
/**
|
|
* Available page orientations.
|
|
*/
|
|
const ORIENTATION_PORTRAIT = 'Portrait'; // vertical
|
|
const ORIENTATION_LANDSCAPE = 'Landscape'; // horizontal
|
|
|
|
/**
|
|
* Page sizes.
|
|
*/
|
|
const SIZE_A4 = 'A4';
|
|
const SIZE_LETTER = 'letter';
|
|
|
|
/**
|
|
* File get modes.
|
|
*/
|
|
const MODE_DOWNLOAD = 0;
|
|
const MODE_STRING = 1;
|
|
const MODE_EMBEDDED = 2;
|
|
const MODE_SAVE = 3;
|
|
|
|
/**
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param array $options
|
|
*/
|
|
public function __construct(array $options = array())
|
|
{
|
|
if (array_key_exists('html', $options)) {
|
|
$this->setHtml($options['html']);
|
|
}
|
|
|
|
if (array_key_exists('orientation', $options)) {
|
|
$this->setOrientation($options['orientation']);
|
|
} else {
|
|
$this->setOrientation(self::ORIENTATION_PORTRAIT);
|
|
}
|
|
|
|
if (array_key_exists('page_size', $options)) {
|
|
$this->setPageSize($options['page_size']);
|
|
} else {
|
|
$this->setPageSize(self::SIZE_A4);
|
|
}
|
|
|
|
if (array_key_exists('toc', $options)) {
|
|
$this->setTOC($options['toc']);
|
|
}
|
|
|
|
if (array_key_exists('margins', $options)) {
|
|
$this->setMargins($options['margins']);
|
|
}
|
|
|
|
if (array_key_exists('binpath', $options)) {
|
|
$this->setBinPath($options['binpath']);
|
|
}
|
|
|
|
if (array_key_exists('window-status', $options)) {
|
|
$this->setWindowStatus($options['window-status']);
|
|
}
|
|
|
|
if (array_key_exists('grayscale', $options)) {
|
|
$this->setGrayscale($options['grayscale']);
|
|
}
|
|
|
|
if (array_key_exists('title', $options)) {
|
|
$this->setTitle($options['title']);
|
|
}
|
|
|
|
if (array_key_exists('footer_html', $options)) {
|
|
$this->setFooterHtml($options['footer_html']);
|
|
}
|
|
|
|
if (array_key_exists('xvfb', $options)) {
|
|
$this->setRunInVirtualX($options['xvfb']);
|
|
}
|
|
|
|
if (array_key_exists('user-style-sheet', $options)) {
|
|
$this->setUserStyleSheet($options['user-style-sheet']);
|
|
}
|
|
|
|
if (array_key_exists('enable-smart-shrinking', $options)) {
|
|
$this->setEnableSmartShrinking($options['enable-smart-shrinking']);
|
|
}
|
|
|
|
if (!array_key_exists('path', $options)) {
|
|
throw new Exception("Path to directory where to store files is not set");
|
|
}
|
|
|
|
if (!is_writable($options['path']))
|
|
{
|
|
throw new Exception("Path to directory where to store files is not writable");
|
|
}
|
|
|
|
$this->setPath($options['path']);
|
|
|
|
$this->_createFile();
|
|
}
|
|
|
|
/**
|
|
* Creates file to which will be writen HTML content.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
protected function _createFile()
|
|
{
|
|
do {
|
|
$this->_filename = $this->getPath() . mt_rand() . '.html';
|
|
} while(file_exists($this->_filename));
|
|
|
|
/**
|
|
* create an empty file
|
|
*/
|
|
file_put_contents($this->_filename, $this->getHtml());
|
|
chmod($this->_filename, 0777);
|
|
|
|
return $this->_filename;
|
|
}
|
|
|
|
/**
|
|
* Returns file path where HTML content is saved.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
public function getFilePath()
|
|
{
|
|
return $this->_filename;
|
|
}
|
|
|
|
/**
|
|
* Executes command.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param string $cmd command to execute
|
|
* @param string $input other input (not arguments)
|
|
* @return array
|
|
*/
|
|
protected function _exec($cmd, $input = "")
|
|
{
|
|
$result = array('stdout' => '', 'stderr' => '', 'return' => '');
|
|
|
|
$proc = proc_open($cmd, array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
|
|
/**
|
|
* We need to asynchronously process streams, as simple sequential stream_get_contents() risks deadlocking if the 2nd pipe's OS pipe buffer fills up before the 1st is fully consumed.
|
|
* The input is probably subject to the same risk.
|
|
*/
|
|
foreach ($pipes as $pipe) {
|
|
stream_set_blocking($pipe, 0);
|
|
}
|
|
|
|
$indexPipes = function(array $pipes) { return array_combine(array_map('intval', $pipes), $pipes); };
|
|
$allWritables = $indexPipes(array($pipes[0]));
|
|
$allReadables = $indexPipes(array($pipes[1], $pipes[2]));
|
|
$readablesNames = array((int)$pipes[1] => 'stdout', (int)$pipes[2] => 'stderr');
|
|
do {
|
|
$readables = $allReadables;
|
|
$writables = $allWritables;
|
|
$exceptables = null;
|
|
$selectTime = microtime(true);
|
|
$nStreams = stream_select($readables, $writables, $exceptables, null, null);
|
|
$selectTime = microtime(true) - $selectTime;
|
|
if ($nStreams === false) {
|
|
throw new \Exception('Error reading/writing to WKHTMLTOPDF');
|
|
}
|
|
|
|
foreach ($writables as $writable) {
|
|
$nBytes = fwrite($writable, $input);
|
|
if ($nBytes === false) {
|
|
throw new \Exception('Error writing to WKHTMLTOPDF');
|
|
}
|
|
|
|
if ($nBytes == strlen($input)) {
|
|
fclose($writable);
|
|
unset($allWritables[(int)$writable]);
|
|
$input = '';
|
|
} else {
|
|
$input = substr($input, $nBytes);
|
|
}
|
|
}
|
|
|
|
if (count($readables) > 0) {
|
|
if ($selectTime < 30e3) {
|
|
usleep(30e3 - $selectTime); // up to 30ms padding, so we don't burn so much time/CPU reading just 1 byte at a time.
|
|
}
|
|
foreach ($readables as $readable) {
|
|
$in = fread($readable, 0x10000);
|
|
if ($in === false) {
|
|
throw new \Exception('Error reading from WKHTMLTOPDF '.$readablesNames[$readable]);
|
|
}
|
|
$result[$readablesNames[(int)$readable]] .= $in;
|
|
|
|
if (feof($readable)) {
|
|
fclose($readable);
|
|
unset($allReadables[(int)$readable]);
|
|
}
|
|
}
|
|
}
|
|
} while (count($allReadables) > 0 || count($allWritables) > 0);
|
|
|
|
$result['return'] = proc_close($proc);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Returns help info.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
public function getHelp()
|
|
{
|
|
$r = $this->_exec($this->_bin . " --extended-help");
|
|
return $r['stdout'];
|
|
}
|
|
|
|
/**
|
|
* Sets the PDF margins.
|
|
*
|
|
* @author Clement Herreman <clement.herreman[at]gmail>
|
|
* @param $margins array<position => value> The margins.
|
|
* * Possible <position> :
|
|
* * top : sets the margin on the top of the PDF
|
|
* * bottom : sets the margin on the bottom of the PDF
|
|
* * left : sets the margin on the left of the PDF
|
|
* * right : sets the margin on the right of the PDF
|
|
* * Value : size of the margin (positive integer). Null to leave the default one.
|
|
* @return Wkhtmltopdf $this
|
|
*/
|
|
public function setMargins($margins)
|
|
{
|
|
$this->_margins = array_merge($this->_margins, $margins);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Gets the PDF margins.
|
|
*
|
|
* @author Clement Herreman <clement.herreman[at]gmail>
|
|
* @return array See $this->setMargins()
|
|
* @see $this->setMargins()
|
|
*/
|
|
public function getMargins()
|
|
{
|
|
return $this->_margins;
|
|
}
|
|
|
|
/**
|
|
* Enables the use of an user style sheet.
|
|
*
|
|
* @author Leo Zandvliet
|
|
* @param string $path
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setUserStyleSheet($path)
|
|
{
|
|
$this->_userStyleSheet = (string)$path;
|
|
return $this;
|
|
}
|
|
|
|
public function getUserStyleSheet()
|
|
{
|
|
return $this->_userStyleSheet;
|
|
}
|
|
|
|
/**
|
|
* Adds the 'enable-smart-shrinking' option, especially in case it's true.
|
|
*
|
|
* @author Leo Zandvliet
|
|
* @param boolean $value
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setEnableSmartShrinking($value)
|
|
{
|
|
$this->_enableSmartShrinking = (bool)$value;
|
|
return $this;
|
|
}
|
|
|
|
public function getEnableSmartShrinking()
|
|
{
|
|
return $this->_enableSmartShrinking;
|
|
}
|
|
|
|
/**
|
|
* Sets additional command line options.
|
|
*
|
|
* @param $options array<option => value> The additional options to set.
|
|
* For command line options with no value, set $options value to NULL.
|
|
* @return Wkhtmltopdf $this
|
|
*/
|
|
public function setOptions($options)
|
|
{
|
|
$this->_options = array_merge($this->_options, $options);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Gets the custom command line options.
|
|
*
|
|
* @return array See $this->setOptions()
|
|
* @see $this->setOptions()
|
|
*/
|
|
public function getOptions()
|
|
{
|
|
return $this->_options;
|
|
}
|
|
|
|
/**
|
|
* Set wkhtmltopdf to wait when `window.status` on selected page changes to setted status, and after that render PDF.
|
|
*
|
|
* @author Roman M. Kos <roman[at]c-o-s.name>
|
|
* @param string $windowStatus
|
|
* we add a `--window-status {$windowStatus}` for execution to `$this->_bin`
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setWindowStatus($windowStatus)
|
|
{
|
|
$this->_windowStatus = (string) $windowStatus;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the window status.
|
|
*
|
|
* @author Roman M. Kos <roman[at]c-o-s.name>
|
|
* @return string See $this->setWindowStatus()
|
|
* @see $this->setWindowStatus()
|
|
*/
|
|
public function getWindowStatus()
|
|
{
|
|
return $this->_windowStatus;
|
|
}
|
|
|
|
/**
|
|
* Set HTML content to render.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param string $html
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setHtml($html)
|
|
{
|
|
$this->_html = (string)$html;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns HTML content.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
public function getHtml()
|
|
{
|
|
return $this->_html;
|
|
}
|
|
|
|
/**
|
|
* Set URL to render.
|
|
*
|
|
* @author Charles SANQUER
|
|
* @param string $html
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setUrl($url)
|
|
{
|
|
$this->_url = (string) $url;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns URL.
|
|
*
|
|
* @author Charles SANQUER
|
|
* @return string
|
|
*/
|
|
public function getUrl()
|
|
{
|
|
return $this->_url;
|
|
}
|
|
|
|
/**
|
|
* Absolute path where to store files.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @throws Exception
|
|
* @param string $path
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setPath($path)
|
|
{
|
|
if (realpath($path) === false) {
|
|
throw new Exception("Path must be absolute");
|
|
}
|
|
|
|
$this->_path = realpath($path) . DIRECTORY_SEPARATOR;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns path where to store saved files.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
public function getPath()
|
|
{
|
|
return $this->_path;
|
|
}
|
|
|
|
/**
|
|
* Set page orientation.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param string $orientation
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setOrientation($orientation)
|
|
{
|
|
$this->_orientation = (string)$orientation;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns page orientation.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
public function getOrientation()
|
|
{
|
|
return $this->_orientation;
|
|
}
|
|
|
|
/**
|
|
* Sets the page size.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param string $size
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setPageSize($size)
|
|
{
|
|
$this->_pageSize = (string)$size;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns page size.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return int
|
|
*/
|
|
public function getPageSize()
|
|
{
|
|
return $this->_pageSize;
|
|
}
|
|
|
|
/**
|
|
* Set the zoom level.
|
|
*
|
|
* @author rikw22 <ricardoa.walter@gmail.com>
|
|
* @return string
|
|
*/
|
|
public function setZoom($zoom)
|
|
{
|
|
$this->_zoom = $zoom;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns zoom level.
|
|
*
|
|
* @author rikw22 <ricardoa.walter@gmail.com>
|
|
* @return int
|
|
*/
|
|
public function getZoom()
|
|
{
|
|
return $this->_zoom;
|
|
}
|
|
|
|
/**
|
|
* Enable / disable generation Table Of Contents.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param boolean $toc
|
|
* @return Wkhtmltopdf
|
|
*/
|
|
public function setTOC($toc = true)
|
|
{
|
|
$this->_toc = (boolean)$toc;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns value is enabled Table Of Contents generation or not.
|
|
*
|
|
* @author aur1nas <aur1mas@devnet.lt>
|
|
* @return boolean
|
|
*/
|
|
public function getTOC()
|
|
{
|
|
return $this->_toc;
|
|
}
|
|
|
|
/**
|
|
* Returns bin path.
|
|
*
|
|
* @author heliocorreia <dev@heliocorreia.org>
|
|
* @return string
|
|
*/
|
|
public function getBinPath()
|
|
{
|
|
return $this->_bin;
|
|
}
|
|
|
|
/**
|
|
* Returns bin path.
|
|
*
|
|
* @author heliocorreia <dev@heliocorreia.org>
|
|
* @return string
|
|
*/
|
|
public function setBinPath($path)
|
|
{
|
|
if (file_exists($path)) {
|
|
$this->_bin = (string)$path;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set number of copies.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param int $copies
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setCopies($copies)
|
|
{
|
|
$this->_copies = (int)$copies;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns number of copies to make.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return int
|
|
*/
|
|
public function getCopies()
|
|
{
|
|
return $this->_copies;
|
|
}
|
|
|
|
/**
|
|
* Whether to print in grayscale or not.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param boolean $mode
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setGrayscale($mode)
|
|
{
|
|
$this->_grayscale = (boolean)$mode;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns is page will be printed in grayscale format.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return boolean
|
|
*/
|
|
public function getGrayscale()
|
|
{
|
|
return $this->_grayscale;
|
|
}
|
|
|
|
/**
|
|
* If TRUE, runs wkhtmltopdf in a virtual X session.
|
|
*
|
|
* @param bool $xvfb
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setRunInVirtualX($xvfb)
|
|
{
|
|
$this->_xvfb = (bool)$xvfb;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* If TRUE, runs wkhtmltopdf in a virtual X session.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function getRunInVirtualX()
|
|
{
|
|
if ($this->_xvfb) {
|
|
return $this->_xvfb;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the PDF title.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param string $title
|
|
* @return Wkthmltopdf
|
|
*/
|
|
public function setTitle($title)
|
|
{
|
|
$this->_title = (string)$title;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns PDF document title.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @throws Exception
|
|
* @return string
|
|
*/
|
|
public function getTitle()
|
|
{
|
|
if ($this->_title) {
|
|
return $this->_title;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set header spacing.
|
|
*
|
|
* @param string $spacing
|
|
* @return Wkthmltopdf
|
|
* @author amorriscode <glxyds@gmail.com>
|
|
*/
|
|
public function setHeaderSpacing($spacing)
|
|
{
|
|
$this->_headerSpacing = (string)$spacing;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get header spacing.
|
|
*
|
|
* @return string
|
|
* @author amorriscode <glxyds@gmail.com>
|
|
*/
|
|
public function getHeaderSpacing()
|
|
{
|
|
return $this->_headerSpacing;
|
|
}
|
|
|
|
/**
|
|
* Set header html.
|
|
*
|
|
* @param string $header
|
|
* @return Wkthmltopdf
|
|
* @author amorriscode <glxyds@gmail.com>
|
|
*/
|
|
public function setHeaderHtml($header)
|
|
{
|
|
$this->_headerHtml = (string)$header;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get header html.
|
|
*
|
|
* @return string
|
|
* @author amorriscode <glxyds@gmail.com>
|
|
*/
|
|
public function getHeaderHtml()
|
|
{
|
|
return $this->_headerHtml;
|
|
}
|
|
|
|
/**
|
|
* Set footer html.
|
|
*
|
|
* @param string $footer
|
|
* @return Wkthmltopdf
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function setFooterHtml($footer)
|
|
{
|
|
$this->_footerHtml = (string)$footer;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get footer html.
|
|
*
|
|
* @return string
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function getFooterHtml()
|
|
{
|
|
return $this->_footerHtml;
|
|
}
|
|
|
|
/**
|
|
* Set HTTP username.
|
|
*
|
|
* @param string $username
|
|
* @return Wkthmltopdf
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function setUsername($username)
|
|
{
|
|
$this->_username = (string)$username;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get HTTP username.
|
|
*
|
|
* @return string
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function getUsername()
|
|
{
|
|
return $this->_username;
|
|
}
|
|
|
|
/**
|
|
* Set http password.
|
|
*
|
|
* @param string $password
|
|
* @return Wkthmltopdf
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function setPassword($password)
|
|
{
|
|
$this->_password = (string)$password;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get http password.
|
|
*
|
|
* @return string
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
*/
|
|
public function getPassword()
|
|
{
|
|
return $this->_password;
|
|
}
|
|
|
|
public function getCommand() {
|
|
return $this->_getCommand();
|
|
}
|
|
|
|
/**
|
|
* Returns command to execute.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @return string
|
|
*/
|
|
protected function _getCommand()
|
|
{
|
|
$command = $this->_bin;
|
|
|
|
$command .= ($this->getCopies() > 1) ? " --copies " . $this->getCopies() : "";
|
|
$command .= " --orientation " . $this->getOrientation();
|
|
$command .= " --page-size " . $this->getPageSize();
|
|
$command .= " --zoom " . $this->getZoom();
|
|
$command .= ($this->getEnableSmartShrinking()) ? " --enable-smart-shrinking" : "";
|
|
|
|
foreach($this->getMargins() as $position => $margin) {
|
|
$command .= (!is_null($margin)) ? sprintf(' --margin-%s %s', $position, $margin) : '';
|
|
}
|
|
|
|
foreach ($this->getOptions() as $key => $value) {
|
|
$command .= " --$key $value";
|
|
}
|
|
|
|
$command .= ($this->getWindowStatus()) ? " --window-status ".$this->getWindowStatus()."" : "";
|
|
$command .= ($this->getTOC()) ? " --toc" : "";
|
|
$command .= ($this->getGrayscale()) ? " --grayscale" : "";
|
|
$command .= (mb_strlen($this->getPassword()) > 0) ? " --password " . $this->getPassword() . "" : "";
|
|
$command .= (mb_strlen($this->getUsername()) > 0) ? " --username " . $this->getUsername() . "" : "";
|
|
$command .= (mb_strlen($this->getHeaderSpacing()) > 0) ? " --header-spacing " . $this->getHeaderSpacing() . "" : "";
|
|
$command .= (mb_strlen($this->getHeaderHtml()) > 0) ? " --header-html \"" . $this->getHeaderHtml() . "\"" : "";
|
|
$command .= (mb_strlen($this->getFooterHtml()) > 0) ? " --margin-bottom 20 --footer-left \"" . $this->getFooterHtml() . "\"" : "";
|
|
|
|
$command .= ($this->getUserStyleSheet()) ? " --user-style-sheet ".$this->getUserStyleSheet()."" : "";
|
|
|
|
$command .= ($this->getTitle()) ? ' --title "' . $this->getTitle() . '"' : '';
|
|
$command .= ' "%input%"';
|
|
$command .= " -";
|
|
if ($this->getRunInVirtualX()) {
|
|
$command = 'xvfb-run ' . $command;
|
|
}
|
|
return $command;
|
|
}
|
|
|
|
/**
|
|
* @todo use file cache
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @throws Exception
|
|
* @return string
|
|
*/
|
|
protected function _render()
|
|
{
|
|
if (mb_strlen($this->_html, 'utf-8') === 0 && empty($this->_url)) {
|
|
throw new Exception("HTML content or source URL not set");
|
|
}
|
|
|
|
if ($this->getUrl()) {
|
|
$input = $this->getUrl();
|
|
} else {
|
|
file_put_contents($this->getFilePath(), $this->getHtml());
|
|
$input = $this->getFilePath();
|
|
}
|
|
|
|
$content = $this->_exec(str_replace('%input%', $input, $this->_getCommand()));
|
|
|
|
if (strpos(mb_strtolower($content['stderr']), 'error')) {
|
|
throw new Exception("System error <pre>" . $content['stderr'] . "</pre>");
|
|
}
|
|
|
|
if (mb_strlen($content['stdout'], 'utf-8') === 0) {
|
|
throw new Exception("WKHTMLTOPDF didn't return any data");
|
|
}
|
|
|
|
if ((int)$content['return'] > 1) {
|
|
throw new Exception("Shell error, return code: " . (int)$content['return']);
|
|
}
|
|
|
|
return $content['stdout'];
|
|
}
|
|
|
|
/**
|
|
* Create the PDF file.
|
|
*
|
|
* @author aur1mas <aur1mas@devnet.lt>
|
|
* @param int $mode
|
|
* @param string $filename
|
|
*/
|
|
public function output($mode, $filename)
|
|
{
|
|
switch ($mode) {
|
|
case self::MODE_DOWNLOAD:
|
|
if (!headers_sent()) {
|
|
$result = $this->_render();
|
|
header("Content-Description: File Transfer");
|
|
header("Cache-Control: public; must-revalidate, max-age=0");
|
|
header("Pragma: public");
|
|
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
|
header("Last-Modified: " . gmdate('D, d m Y H:i:s') . " GMT");
|
|
header("Content-Type: application/force-download");
|
|
header("Content-Type: application/octec-stream", false);
|
|
header("Content-Type: application/download", false);
|
|
header("Content-Type: application/pdf", false);
|
|
header('Content-Disposition: attachment; filename="' . basename($filename) .'";');
|
|
header("Content-Transfer-Encoding: binary");
|
|
header("Content-Length: " . strlen($result));
|
|
echo $result;
|
|
$filepath = $this->getFilePath();
|
|
if (!empty($filepath))
|
|
unlink($filepath);
|
|
exit();
|
|
} else {
|
|
throw new Exception("Headers already sent");
|
|
}
|
|
break;
|
|
case self::MODE_STRING:
|
|
return $this->_render();
|
|
break;
|
|
case self::MODE_EMBEDDED:
|
|
if (!headers_sent()) {
|
|
$result = $this->_render();
|
|
header("Content-type: application/pdf");
|
|
header("Cache-control: public, must-revalidate, max-age=0");
|
|
header("Pragme: public");
|
|
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
|
header("Last-Modified: " . gmdate('D, d m Y H:i:s') . " GMT");
|
|
header("Content-Length: " . strlen($result));
|
|
header('Content-Disposition: inline; filename="' . basename($filename) .'";');
|
|
echo $result;
|
|
$filepath = $this->getFilePath();
|
|
if (!empty($filepath)) {
|
|
unlink($filepath);
|
|
}
|
|
exit();
|
|
} else {
|
|
throw new Exception("Headers already sent");
|
|
}
|
|
break;
|
|
case self::MODE_SAVE:
|
|
file_put_contents($this->getPath() . basename($filename), $this->_render());
|
|
$filepath = $this->getFilePath();
|
|
if (!empty($filepath)) {
|
|
unlink($filepath);
|
|
}
|
|
break;
|
|
default:
|
|
throw new Exception("Mode: " . $mode . " is not supported");
|
|
}
|
|
}
|
|
}
|