From 314c670605431955fd3c3c69548d6e8cfdad4d59 Mon Sep 17 00:00:00 2001 From: Carsten Rose <carsten.rose@math.uzh.ch> Date: Mon, 6 Mar 2017 23:08:18 +0100 Subject: [PATCH] print.php / wkhtmltopdf: wrapper to offer HTML to PDF conversion. Index.rst: Update Administratormanual how to install and use print.php. print.php: wrapper for wkhtmltopdf. --- .../AdministratorManual/Index.rst | 38 ++++- extension/config.qfq.example.ini | 4 + extension/qfq/api/print.php | 137 ++++++++++++++++++ extension/qfq/qfq/Constants.php | 3 + 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 extension/qfq/api/print.php diff --git a/extension/Documentation/AdministratorManual/Index.rst b/extension/Documentation/AdministratorManual/Index.rst index 47d1ce3d4..e6384cffc 100644 --- a/extension/Documentation/AdministratorManual/Index.rst +++ b/extension/Documentation/AdministratorManual/Index.rst @@ -14,6 +14,9 @@ Administrator Manual Preparation ----------- +Report & Form +^^^^^^^^^^^^^ + The QFQ extension needs in PHP 5.x the PHP MySQL native driver. The following functions are used and are only available with the native driver (see also: http://dev.mysql.com/downloads/connector/php-mysqlnd/): @@ -34,6 +37,34 @@ Preparation steps for Ubuntu 16.04:: sudo apt install php7.0-intl +Print page via wkhtmltopdf +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Different browser prints the same page in different variations. To prevent this, QFQ implements a small PHP wrapper `print.php` +which uses http://wkhtmltopdf.org/ (webkit based) to convert HTML to PDF. The converter is not included in QFQ and has +to be manually installed. + +Hint: The Ubuntu package `wkhtmltopdf` needs a running Xserver - this does not work on a headless webserver. Best is to +install the QT version from the named website above. + +In config.qfq.ini specify the: +* installed `wkhtmltopdf` binary, +* the site base URL. + +Provide a `print this page`-link (replace {current pageId}):: + + <a href="typo3conf/ext/qfq/qfq/api/print.php?id={current pageId}">Print this page</a> + +Any parameter specified after `print.php` will be delivered to `wkhtmltopdf` as part of the URL. + +Typoscript code to implement a print link on every page:: + + 10 = TEXT + 10 { + wrap = <a href="typo3conf/ext/qfq/qfq/api/print.php?id=|&type=2"><span class="glyphicon glyphicon-print" aria-hidden="true"></span> Printview</a> + data = page:uid + } + Setup ----- @@ -162,7 +193,10 @@ config.qfq.ini +-----------------------------+-----------------------------------------+----------------------------------------------------------------------------+ | FORM_BUTTON_ON_CHANGE_CLASS | FORM_BUTTON_ON_CHANGE_CLASS=alert-info btn-info | Color for save button after modification | +-----------------------------+-----------------------------------------+----------------------------------------------------------------------------+ - +| BASE_URL_PRINT | BASE_URL_PRINT=http://example.com | URL where wkhtmltopdf will fetch the HTML (no parameter, those comes later)| ++-----------------------------+-----------------------------------------+----------------------------------------------------------------------------+ +| WKHTMLTOPDF | WKHTMLTOPDF=/usr/bin/wkhtmltopdf | Binary where to find wkhtmltopdf | ++-----------------------------+-----------------------------------------+----------------------------------------------------------------------------+ Example: *typo3conf/config.qfq.ini* @@ -190,6 +224,8 @@ Example: *typo3conf/config.qfq.ini* ;FORM_BS_LABEL_COLUMNS = 3 ;FORM_BS_INPUT_COLUMNS = 6 ;FORM_BS_NOTE_COLUMNS = 3 + BASE_URL_PRINT=http://example.com + WKHTMLTOPDF=/usr/bin/wkhtmltopdf Documentation ------------- diff --git a/extension/config.qfq.example.ini b/extension/config.qfq.example.ini index 56ad6f37e..9d1e9415a 100644 --- a/extension/config.qfq.example.ini +++ b/extension/config.qfq.example.ini @@ -41,3 +41,7 @@ DATE_FORMAT = yyyy-mm-dd ;FORM_BS_LABEL_COLUMNS = 3 ;FORM_BS_INPUT_COLUMNS = 6 ;FORM_BS_NOTE_COLUMNS = 3 + +; Configure URL where `wkhtmltopdf` fetches pages and produces PDFs +BASE_URL_PRINT = http://example.com/ +WKHTMLTOPDF = /opt/wkhtmltox/bin/wkhtmltopdf diff --git a/extension/qfq/api/print.php b/extension/qfq/api/print.php new file mode 100644 index 000000000..080a9c58d --- /dev/null +++ b/extension/qfq/api/print.php @@ -0,0 +1,137 @@ +<?php +/** + * Created by PhpStorm. + * User: ep + * Date: 12/23/15 + * Time: 6:17 PM + */ + + +namespace qfq; + +use qfq; + +require_once(__DIR__ . '/../qfq/store/Config.php'); +require_once(__DIR__ . '/../qfq/Constants.php'); +require_once(__DIR__ . '/../qfq/helper/KeyValueStringParser.php'); + +const PAGEID = 'id'; +const PARAM_GET = 'paramGet'; +const URL_PRINT = 'urlPrint'; + +/** + * Create a temporary file. + * + * @return string + */ +function createEmptyFile() { + return tempnam(sys_get_temp_dir(), "webkitPrintPdf"); +} + +/** + * Set HTML Header to initiate PDF download. + * + * @param $filename + */ +function setHeader($filename) { + + header("Content-Disposition: inline; filename=\"$filename\""); + header("Content-Type: application/pdf"); + header("Content-Transfer-Encoding: binary"); +} + +/** + * Read QFQ config. Only SYSTEM_BASE_URL_PRINT and SYSTEM_WKHTMLTOPDF will be used. + * Check and get all clean _GET Parameter. Build a URL based on SYSTEM_BASE_URL_PRINT and the delivered URL params. + * + * @return array + * @throws UserFormException + * @throws \exception + */ +function init() { + $cfg = new Config(); + + $config = $cfg->readConfig(''); + $param = readCleanGetParam(); + + if (!isset($config[SYSTEM_BASE_URL_PRINT]) || $config[SYSTEM_BASE_URL_PRINT] == '') { + throw new \exception(CONFIG_INI . ' - Missing ' . SYSTEM_BASE_URL_PRINT); + } + + if (!isset($config[SYSTEM_WKHTMLTOPDF]) || $config[SYSTEM_WKHTMLTOPDF] == '') { + throw new \exception(CONFIG_INI . ' - Missing ' . SYSTEM_WKHTMLTOPDF); + } + + if (!is_executable($config[SYSTEM_WKHTMLTOPDF])) { + throw new \exception(CONFIG_INI . ' - ' . SYSTEM_WKHTMLTOPDF . '=' . $config[SYSTEM_WKHTMLTOPDF] . ' - not found or not executable.'); + } + + if (!isset($param[PAGEID]) || $param[PAGEID] == '') { + throw new \exception("Missing GET Parameter '" . PAGEID . "'."); + } + + $setup = array(); + $setup[URL_PRINT] = $config[SYSTEM_BASE_URL_PRINT] . '/?' . KeyValueStringParser::unparse($param, '=', '&'); + $setup[PAGEID] = $param[PAGEID]; + $setup[SYSTEM_WKHTMLTOPDF] = $config[SYSTEM_WKHTMLTOPDF]; + + return $setup; +} + +; + +/** + * Return an array with GET params who are clean - they do not violate $pattern. + * + * @return array + */ +function readCleanGetParam() { + + $param = array(); + $pattern = '^[\-_\.,;:\/a-zA-Z0-9]*$'; // ':alnum:' does not work here in FF + + foreach ($_GET as $key => $value) { + if (preg_match("/$pattern/", $value) === 1) { + $param[$key] = $value; + } + } + + return $param; +} + +/** + * @param array $setup + * @throws \exception + */ +function page2pdf($setup) { + + $rc = 0; + $file = createEmptyFile(); + + $cmd = $setup[SYSTEM_WKHTMLTOPDF] . " '" . $setup[URL_PRINT] . "' " . $file . " > $file.log 2>&1"; + + $line = system($cmd, $rc); + + if ($rc == 0) { + setHeader('print.' . $setup[PAGEID] . '.pdf'); + @readfile($file); + @unlink($file); + @unlink($file . '.log'); + exit; // Do an extremely hard exit here to make sure there are no more additional bytes sent (makes the delivered PDF unusable). + } else { + throw new \exception("Error [RC=$rc] $line: $cmd"); + } +} + + +/** + * Main + */ +try { + $setup = init(); + + page2pdf($setup); + +} catch (\Exception $e) { + echo "Exception: " . $e->getMessage(); +} diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php index 5b01ff42d..727f712ea 100644 --- a/extension/qfq/qfq/Constants.php +++ b/extension/qfq/qfq/Constants.php @@ -322,6 +322,9 @@ const SYSTEM_FORM_BS_NOTE_COLUMNS = 'FORM_BS_NOTE_COLUMNS'; const SYSTEM_FORM_BUTTON_ON_CHANGE_CLASS = 'FORM_BUTTON_ON_CHANGE_CLASS'; +const SYSTEM_BASE_URL_PRINT = 'BASE_URL_PRINT'; +const SYSTEM_WKHTMLTOPDF = 'WKHTMLTOPDF'; + // computed automatically during runtime const SYSTEM_PATH_EXT = 'EXT_PATH'; const SYSTEM_SITE_PATH = 'SITE_PATH'; -- GitLab