Commit e10937b6 authored by Carsten  Rose's avatar Carsten Rose
Browse files

#3218 / download.php / export

* Recode the '_link' notation for download
* Add 'ZIP' as export format
* Add 'parameter' to wkhtmltopdf
* Implemented 'SYSTEM_STORE / SYSTEM_DOWNLOAD_POPUP' for detecting if there are download links on the page. This eleminates passing parameters through dozens of functions.
* Report/Columntype '_dDownload' broken!
Coding.md: described `download` from a coding point of view.
Manual.rst: Update '_link' to latest notation of 'download'.
download.php: implemented catching of 'Undefined index'. Added further exceptions.
Download.php: Added cache=off for downloading. Rename getFile() to getElement(). Make getElement() more generic. Add zipFiles(). Implement 'downloadMode' in doElements().
Html2Pdf.php: recode to new download notation. Parameter to wkhtmltopdf implemented.
Link.php: New TOKEN_* and NAME_DOWNLOAD_*, NAME_FILE. Move TOKEN_* to Constants.php. Will be used in Download.php too. Implemented 'SYSTEM_STORE / SYSTEM_DOWNLOAD_POPUP'. Implemented BASE64 encoding of multiple 'U' and 'u'.
Report.php: Implemented 'SYSTEM_STORE / SYSTEM_DOWNLOAD_POPUP'.
Sip.php: implement debugSip() to show Sip. New: base64 encoded parameter will be shown in clear.
Store.php: some functions missed keyword 'static'. getVar() and getStore automatically decode base64 parameter.
QuickFormQuery.php: Implemented 'SYSTEM_STORE / SYSTEM_DOWNLOAD_POPUP'.
parent 58db5537
......@@ -191,6 +191,51 @@ Form save
* delete [STORE_EXTRA][<uploadSip>]
* Step 3: update record with final <fileDestination>
Download
--------
A download might be:
* a single file (any type, will be detected on the fly),
* an export of several files as a ZIP archive,
* an export of a T3-'XML'-Page converted to Excel,
* a converted HTML page to PDF,
* a PDF file, concatenated on single PDF files and/or converted HTML page to PDF.
'api/download.php' will be called with a SIP (no other vars used). The SIP contains:
* DOWNLOAD_EXPORT_FILENAME - any target filename, if none given take DOWNLOAD_OUTPUT_PDF ('output.pdf').
* DONWLOAD_MODE - file / pdf / excel / zip. If not specified:
a) 'file' is the default if only one is given and if this is a file.
b) 'pdf' is the default if there are multiple TOKEN_URL, TOKEN_URL_PARAM, TOKEN_FILE in SIP_DOWNLOAD_PARAMETER found.
* SIP_DOWNLOAD_PARAMETER (base64 encoded) - contains all parameter to source elements.
Format: <format 1>:<element 1>|<format 2>:<element 2>|...|<format n>:<element n>|
<format>: TOKEN_URL, TOKEN_URL_PARAM, TOKEN_FILE
<element>: depending on the token - see below
URL: a) 'u:http://w3c.org', b) 'u:w3c.org/', c) 'u:w3c.org/2017/index.php?issue=23'
URL_PARAM: a) 'U:id=export&r=123', b) 'U:id=export&r=123&_orientation=landscape&_page-size=a3'
FILE: a) 'f:fileadmin/example.png'
* In URL_PARAM extra parameter used by `wkhtmltopdf` can be specified. All Parameter, starting with '-'
will be extracted from the regular URL_PARAM and instead forwarded as options to `wkhtmlpdf`
* The base64 encoding is necessary:
* to deliver multiple elements with the same token (e.g. multiple PDF files to concatenate).
* special parameter names, like 'id', should not force the regular interpretation of 'id' during conversion to a SIP.
During preparing and delivering the download, a popup shows a spinning gear by default. The popup itself will display an
individual message. The popup needs some HTML code (only once per T3 page).
Download links might be generated in `report` as well as in `subrecords of forms`. To trigger the generation of the HTML
popup code, a variable DOWNLOAD_POPUP_REQUEST in STORE_SYSTEM will be set to 'true' (string) in class Link(), as soon as
the first download link is rendered. During internal rendering of the download link, the const text token
DOWNLOAD_POPUP_REPLACE_TEXT and DOWNLOAD_POPUP_REPLACE_TITLE will be replaced with individual texts, defined per download link.
Print
-----
tbd
Formelement type: DATE / DATETIME / TIME
----------------------------------------
* Available Formats:
......
......@@ -2374,7 +2374,7 @@ The sum of these three columns should always be 12.
Multiple Elements per row
^^^^^^^^^^^^^^^^^^^^^^^^^
Every row is by default wrapped in a `<div class='form-group'>` and every column is wrapped in a `<div class='col-md-?>`.
Every row is by default wrapped in a `<div class='form-group'>` and every column is wrapped in a `<div class='col-md-?'>`.
To display multiple input elements in one row, the wrapping of the *FormElement* row and of the three columns can be
customized via the checkboxes of `Label / Input / Note`. Every open and every close tag can be individually switched on
or off.
......@@ -3275,7 +3275,7 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|x | |Page |p:<pageId> |p:impressum |Prepend '?' or '?id=', no hostname qualifier (automatically set by browser), default link class: internal, default value: {{pageId}} |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|x | |Download |d |d |If an image is specified, it will be rendered inside the link, default link class: internal. Link points to `api/download.php` |
|x | |Download |d:[<exportFilename>] |d:complete.pdf |Link points to `api/download.php`. Additonal parameter are encoded into a SIP. 'Download' needs an enabled SIP. See `download`_. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Text |t:<text> |t:Firstname Lastname |- |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
......@@ -3303,7 +3303,7 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Tooltip |o:<text> |o:More information here |Tooltip text |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Alttext |a:<text> |a:Name of person |Alttext for images |
| | |Alttext |a:<text> |a:Name of person |a) Alttext for images, b) Message text for download popup window. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Class |c:[n|i|e|<text>] |c:i |CSS class for link. n:no class attribut, i:internal (ext_localconf.php)(default), e:external (ext_localconf.php), <text>: explicit named|
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
......@@ -3317,6 +3317,10 @@ Column: _link
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |SIP |s[:0|1] |s, s:0, s:1 |If 's' or 's:1' a SIP entry is generated with all non Typo 3 Parameters. The URL contains only parameter 's' and Typo 3 parameter |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Mode |M:file|pdf|excel|zip |M:file, M:pdf, M:excel |Mode. Used to specify type of download. One or more element sources needs to be configured. See `download`_. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |File |f:<filename> |f:fileadmin/file.pdf |Element source for download mode file|pdf|zip. See `download`_. |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
| | |Delete record | x[:a|r|c] |x, x:r, x:c |a: ajax (only QFQ internal used), r: report (default), c: close (current page, open last page) |
+---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
......@@ -3384,7 +3388,8 @@ Link Examples
+-----------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|SELECT "U:form=Person&r=123|x|t:Delete" as _link |<a href="typo3conf/ext/qfq/qfq/api/delete.php?s=badcaffee1234">Delete</a> |
+-----------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
|SELECT "d:U:1_pageId=req&1_id=12&1_mode=html2pdf" |<a href="typo3conf/ext/qfq/qfq/api/download.php?s=badcaffee1234">Download</a> |
|SELECT "s:1|d:full.pdf|M:pdf|U:id=det1&r=12|U:id=det2|f:cv.pdf| |<a href="typo3conf/ext/qfq/qfq/api/download.php?s=badcaffee1234">Download</a> |
| t:Download|a:Create complete PDF - please wait" as _link | |
+-----------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------+
.. _question:
......@@ -3435,75 +3440,96 @@ Examples:
| SELECT "p:form_person|q:Edit Person:::10:0" AS _link | The Alert will be shown 10 seconds and is not modal. |
+------------------------------------------------------------+---------------------------------------------------------------------------+
.. _download:
Download
^^^^^^^^
Download links can be used to offer:
Download offers:
* to download a single file, or
* to concatenate several files and/or web pages (=HTML to PDF) into one output file, or
* to create an `Excel` export.
* download a single file (any type),
* concatenate several files (uploaded) and/or web pages (=HTML to PDF) into one PDF output file,
* create an `excel` export (based on a Typo3 page which creates XML output),
* create a ZIP archive, filled with several files ('uploaded' or 'HTML to PDF'-converted).
The downloads are SIP protected. Only the current user can use the link to download files.
By using the `_link` columnname:
* the option `d` enables the download mode
* setting `s` (or `s=1`) is mandatory for download mode
By using `_download` or `_Download` as columnname the options `d` and `s` will be set by automatically.
* the option `d` initiate creating the download link and optional specifies an export filename,
* the optional `M` (Mode) specifies the export type (file, pdf, excel, zip),
* setting `s` (or `s=1`) is mandatory for the download function,
* the alttext `a` specifies a message in the dowload popup.
By using `_pdf`, `_Pdf`, `_file`, `_File`, `_excel`, `_Excel`, `_zip`, `_Zip` as columnname the options `d`, `m` and `s`
will be set by automatically.
All files will be read by PHP - therefore the directory might be protected against direct web access. This way is the
preferred way to offer secure downloads via QFQ.
In case the download needs a persistant URL (no SIP, no user session), a regular
link, pointing directly to a file, have to be used - the download described here won't help.
link, pointing directly to a file, have to be used - the download functionality described here is not appropriate.
.. _download-parameter-files:
Specify file(s)/web page(s)
'''''''''''''''''''''''''''
Parameter and (element) sources
'''''''''''''''''''''''''''''''
The following parameter have to be specified as 'U' parameter. The SIP encoded parameter remains on the server and
are not transferred to the client. This prohibits parameter manipulation.
* *download*: `d[:<exportFilename>]`
* *Link parameter 'U:.....'* :
* *exportFilename* = <filename for save as> - Name, offered in the 'File save as' browser dialog. Default: 'output.pdf'.
The user typically expect meaningfull and distinct filenames for different download links.
* *exportFilename* = <filename for save as> - Name, offered in the 'File save as' browser dialog. Default: 'output.pdf'.
The user typically expect meaningfull and distinct filenames for different downloads.
* *popupMessage*: `a:<text>` - will be displayed in the popup window during download. If the creating/download is fast,
the window might disapear quicly.
* *mode* = <file | pdf | excel> - This parameter is optional and can be skipped in most situations.
* *mode*: `m:<mode>`
* If `mode=file`, the mimetype is derived dynamically from the specified file. All others are fix (PDF or Excel).
* In case of multiple files and/or web pages, only `pdf` is supported.
* `excel` is not implemented now.
* The **default** depends on the number of specified `elements` (=file or web page). If only one `file` is specifed,
the default is `file`. If there is a) a page defined or b) multiple elements, the default is `pdf`.
* *mode* = <file | pdf | excel | zip> - This parameter is optional and can be skipped in most situations. Mandatory
for 'excel', 'zip'.
* For `web page` or `excel` export, all pages have to be specified with the necessary parameters (might
vary per page). The preceeding number `<i>` aggregates all parameter to one element (=`file` or `page`). The ordering has to start with `1`
and has to be consecutive.
* If `m:file`, the mimetype is derived dynamically from the specified file. In this mode, only one element source
is allowed per download link (no concatenation).
* *<i>_id* = <Typo3 pageId> - `id` is fix and mandatory for `web page` and `excel`.
* *<i>_<keyname>* = <value key i> - <keyname> is free of choice except `id` and `file`.
* In case of multiple element sources, only `pdf` or `zip` is supported.
* `m:excel` is not implemented now.
* If `m:zip` is used together with `U:...` oder `u:..`, those HTML pages will be converted to PDF and have technical
filenames inside the archive.
* If not specified, the **default** depends on the number of specified element sources (=file or web page).
* For `file`
* If only one `file` is specifed, the default is `file`.
* If there is a) a page defined or b) multiple elements, the default is `pdf`.
* *<i>_file* = <pathfilename> - `file` is fix and mandatory for direct `file` access.
* *element sources* - for `m:pdf` or `m:zip`, all of the following three element sources might be specified multiple times.
Any combination and order of the three options are allowed.
* *file*: `f:<pathFilename>` - relative or absolute pathFilename offered for a) download (single), or to be concatenated
in a PDF or ZIP.
* *urlParam*: `U:id=<t3 page>&<key 1>=<value 1>&<key 2>=<value 2>&...&<key n>=<value n>
* *url*: `u:<url>` - any URL, pointing to an internal or external destination.
* *Options* for `urlParam` or `url`:
* The 'HTML to PDF' will be done via `wkhtmltopdf`.
* All possible options, suitable for `wkhtmltopdf`, can be submitted in the `u:...` or `U:...` element source.
Check https://wkhtmltopdf.org/usage/wkhtmltopdf.txt. Examples see below.
Most of the other Link-Class attributes can be used to customize the link.
Example: ::
# single `file`
SELECT "d|s|t:PDF|U:exportFilename=final.pdf&1_file=fileadmin/pdf/test.pdf" AS _link
# single `file`. Specifying a popup message window text is not necessary, cause a file directly accessed is fast.
SELECT "d:file.pdf|s|t:Download|f:fileadmin/pdf/test.pdf" AS _link
# single `file`, with mode
SELECT "d|s|t:PDF|U:exportFilename=final.pdf&mode=file&1_file=fileadmin/pdf/test.pdf" AS _link
# two pages (1_id, 2_id) and one file (3_file)
SELECT "d|s|t:PDF|U:exportFilename=final.pdf&1_id=exportP1&2_id=123&3_file=fileadmin/pdf/test.pdf" AS _link
# two pages (1_id, 2_id) and one file (3_file) with mode
SELECT "d|s|t:PDF|U:exportFilename=final.pdf&mode=pdf&1_id=exportP1&2_id=123&3_file=fileadmin/pdf/test.pdf" AS _link
SELECT "d:file.pdf|m:pdf|s|t:Download|f:fileadmin/pdf/test.pdf" AS _link
# three sources: two pages and one file
SELECT "d:complete.pdf|s|t:Complete PDF|U:id=detail&r=1|U:id=detail2&r=1|f:fileadmin/pdf/test.pdf" AS _link AS _link
# three sources: two pages and one file
SELECT "d:complete.pdf|s|t:Complete PDF|U:id=detail&r=1|U:id=detail2&r=1|f:fileadmin/pdf/test.pdf" AS _link AS _link
# three sources: two pages and one file, the second page will be in landscape and pagesize A3
SELECT "d:complete.pdf|s|t:Complete PDF|U:id=detail&r=1|U:id=detail2&r=1&--orientation=Landscape&--page-size=A3|f:fileadmin/pdf/test.pdf" AS _link AS _link
..
......
......@@ -4,6 +4,8 @@
* User: crose
* Date: 4/17/17
* Time: 5:51 PM
*
* Check: CODING.md > Download
*/
namespace qfq;
......@@ -11,19 +13,31 @@ namespace qfq;
use qfq;
require_once(__DIR__ . '/../qfq/report/Download.php');
//require_once(__DIR__ . '/../qfq/store/Store.php');
require_once(__DIR__ . '/../qfq/Constants.php');
require_once(__DIR__ . '/../qfq/exceptions/DownloadException.php');
require_once(__DIR__ . '/../qfq/exceptions/CodeException.php');
require_once(__DIR__ . '/../qfq/exceptions/DbException.php');
require_once(__DIR__ . '/../qfq/exceptions/ErrorHandler.php');
set_error_handler("\\qfq\\ErrorHandler::exception_error_handler");
$data = '';
try {
$download = new \qfq\Download();
// If all is fine - this function never returns! The output file is delivered and PHP is stopped after that.
// If all is fine - 'process()' never returns! The output file is delivered and PHP is stopped after that.
$data = $download->process();
} catch (qfq\CodeException $e) {
$data = $e->formatMessage();
} catch (qfq\DbException $e) {
$data = $e->formatMessage();
} catch (qfq\DownloadException $e) {
$data = $e->formatMessage();
} catch (\Exception $e) {
$data = "Exception: " . $e->getMessage();
}
echo $data;
......@@ -212,6 +212,7 @@ const ERROR_DOWNLOAD_CREATE_NEW_FILE = 1700;
const ERROR_DOWNLOAD_NO_FILES = 1701;
const ERROR_DOWNLOAD_NOTHING_TO_DO = 1702;
const ERROR_DOWNLOAD_UNEXPECTED_MIMETYPE = 1703;
const ERROR_DOWNLOAD_UNEXPECTED_NUMBER_OF_SOURCES = 1704;
// KeyValueParser
const ERROR_KVP_VALUE_HAS_NO_KEY = 1900;
......@@ -366,6 +367,12 @@ const SYSTEM_REPORT_FULL_LEVEL = 'reportFullLevel'; // Keyname of SQL-column pro
const SYSTEM_LDAP_1_RDN = 'LDAP_1_RDN'; // Credentials to access LDAP
const SYSTEM_LDAP_1_PASSWORD = 'LDAP_1_PASSWORD'; // Credentials to access LDAP
const SYSTEM_DOWNLOAD_POPUP = 'hasDownloadPopup'; // Marker which is set to 'true' if there is at least one Download Link rendered
const DOWNLOAD_POPUP_REQUEST = 'true';
const DOWNLOAD_POPUP_REPLACE_TEXT = '#downloadPopupReplaceText#';
const DOWNLOAD_POPUP_REPLACE_TITLE = '#downloadPopupReplaceTitle#';
// die folgenden Elemente sind vermutlich nicht noetig, wenn Store Klassen gloable Vars benutzt.
//const SYSTEM_FORM_DEF = 'formDefinition'; // Type: SANITIZE_ALNUMX / AssocArray. Final form to process. Useful for error reporting.
//const SYSTEM_FORM_ELEMENT_DEF = 'formElementDefinition'; // Type: SANITIZE_ALL / AssocArray. Formelement which are processed at the moment. Useful for error reporting.
......@@ -387,6 +394,10 @@ const SIP_FORM = CLIENT_FORM;
const SIP_TABLE = 'table'; // delete a record from 'table'
const SIP_URLPARAM = 'urlparam';
const SIP_MAKE_URLPARAM_UNIQ = '_makeUrlParamUniq'; // SIPs for 'new records' needs to be uniq per TAB! Therefore add a uniq parameter
const SIP_DOWNLOAD_PARAMETER = '_b64_download'; // Parametername, filled in SIP, to hold all download element parameter.
const SIP_PREFIX_BASE64 = '_b64';
// FURTHER: all extracted params from 'urlparam
const ACTION_KEYWORD_SLAVE_ID = 'slaveId';
......@@ -853,15 +864,54 @@ const DOWNLOAD_MODE = 'mode';
const DOWNLOAD_MODE_FILE = 'file';
const DOWNLOAD_MODE_PDF = 'pdf';
const DOWNLOAD_MODE_EXCEL = 'excel';
const DOWNLOAD_EXPORT_FILENAME = 'exportFilename';
const DOWNLOAD_PAGE_ID = 'id';
const DOWNLOAD_FILE = 'file';
const DOWNLOAD_FILE_PREFIX = 'qfq.temp';
const DOWNLOAD_MODE_ZIP = 'zip';
const DOWNLOAD_EXPORT_FILENAME = '_exportFilename';
const DOWNLOAD_FILE_PREFIX = 'qfq.temp'; // temporary filename on server of single export file
const DOWNLOAD_OUTPUT_PDF = 'output.pdf';
const DOWNLOAD_PARAMETER_DELIMITER = '_';
// HTML2PDF
const HTML2PDF_PAGEID = 'id';
const HTML2PDF_PARAM_GET = 'paramGet';
const HTML2PDF_URL_PRINT = 'urlPrint';
// Class: LINK
const PARAM_DELIMITER = '|';
const TOKEN_URL = 'u';
const TOKEN_MAIL = 'm';
const TOKEN_PAGE = 'p';
const TOKEN_DOWNLOAD = 'd';
const TOKEN_TEXT = 't';
const TOKEN_ALT_TEXT = 'a';
const TOKEN_TOOL_TIP = 'o';
const TOKEN_PICTURE = 'P';
const TOKEN_BULLET = 'B';
const TOKEN_CHECK = 'C';
const TOKEN_DELETE = 'D';
const TOKEN_EDIT = 'E';
const TOKEN_HELP = 'H';
const TOKEN_INFO = 'I';
const TOKEN_NEW = 'N';
const TOKEN_SHOW = 'S';
const TOKEN_RENDER = 'r';
const TOKEN_TARGET = 'g';
const TOKEN_CLASS = 'c';
const TOKEN_QUESTION = 'q';
const TOKEN_ENCRYPTION = 'e';
const TOKEN_SIP = 's';
const TOKEN_URL_PARAM = 'U';
const TOKEN_RIGHT = 'R';
const TOKEN_FILE = 'f';
const TOKEN_DOWNLOAD_MODE = 'M';
const TOKEN_ACTION_DELETE = 'x';
const TOKEN_ACTION_DELETE_AJAX = 'a';
const TOKEN_ACTION_DELETE_REPORT = 'r';
const TOKEN_ACTION_DELETE_CLOSE = 'c';
const TOKEN_CLASS_NONE = 'n';
const TOKEN_CLASS_INTERNAL = 'i';
const TOKEN_CLASS_EXTERNAL = 'e';
......@@ -183,6 +183,7 @@ class QuickFormQuery {
*/
public function process() {
$html = '';
$rcHasDownloadLinks = false;
if ($this->store->getVar(TYPO3_DEBUG_SHOW_BODY_TEXT, STORE_TYPO3) === 'yes') {
$htmlId = HelperFormElement::buildFormElementId($this->formSpec[F_ID], 0, 0, 0);
......@@ -192,9 +193,16 @@ class QuickFormQuery {
$html .= $this->doForm(FORM_LOAD);
$html .= $this->doReport();
// Only needed if there are download which show a popup during rendering/downloading.
if ($this->store->getVar(SYSTEM_DOWNLOAD_POPUP, STORE_SYSTEM) == DOWNLOAD_POPUP_REQUEST) {
$html .= $this->getModalCode();
}
$class = $this->store->getVar(SYSTEM_CSS_CLASS_QFQ_CONTAINER, STORE_SYSTEM);
if ($class)
if ($class) {
$html = Support::wrapTag("<div class='$class'>", $html);
}
// $feUidLoggedIn = isset($GLOBALS["TSFE"]->fe_user->user["uid"]) ? $GLOBALS["TSFE"]->fe_user->user["uid"] : false;
// $feUidSession = $_SESSION[SESSION_NAME][SESSION_FE_USER_UID];
......@@ -913,4 +921,35 @@ class QuickFormQuery {
$this->store->setStore($tmpParam, STORE_SIP, true);
}
/**
* @return string
*/
private function getModalCode() {
$code = <<<EOF
<!-- Modal -->
<div class="modal fade" id="qfqModal101" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="qfqModalTitle101">Loading Document</h4>
</div>
<div class="modal-body" style="text-align: center;">
<span class="glyphicon glyphicon-cog glyphicon-spin text-large-with-margin text-primary"></span>
<p id="qfqModalText101">PDF Document is being generated. Please wait.</p>
</div>
<div class="modal-footer">
<p>In progress..</p>
</div>
</div>
</div>
</div>
EOF;
return $code;
}
}
\ No newline at end of file
......@@ -4,6 +4,8 @@
* User: crose
* Date: 4/17/17
* Time: 11:32 AM
*
* Check: CODING.md > Download
*/
namespace qfq;
......@@ -65,44 +67,6 @@ class Download {
$this->html2pdf = new Html2Pdf($this->store->getStore(STORE_SYSTEM));
}
/**
* Collect all elements, separated per element.
* Skip parameter which do not start with '<i>_' (i=integer).
* Create a numbered and sorted (by key) array, with all parameter belonging to one element in one subarray.
*
* E.g.: exportFilename=final.pdf&mode=pdf&1_id=exportP1&2_id=123&3_file=fileadmin/pdf/test.pdf&1_grId=78
* result [
* [1] => [ 'id' => 'exportP1', 'grId' = '78' ],
* [2] => [ 'id' => '123' ],
* [3] => [ 'file' => 'fileadmin/pdf/test.pdf' ],
* [mode] => 'pdf|file|excel',
* [exportFilename] => '....'
* ]
*
* @param array $vars
* @return array
*/
private function collectElement(array $vars) {
$final = array();
foreach ($vars as $key => $value) {
$splitArr = explode(DOWNLOAD_PARAMETER_DELIMITER, $key, 2);
$idx = $splitArr[0];
if ((count($splitArr) == 2) && is_numeric($idx) && !isset($final[$idx])) {
$arr = OnArray::getArrayItemKeyNameStartWith($vars, $idx . DOWNLOAD_PARAMETER_DELIMITER);
if (count($arr) > 0) {
$final[$idx] = $arr;
}
}
}
// sort array
ksort($final, SORT_NATURAL);
return $final;
}
/**
* Concatenate all named files to one PDF file. Return name of new full PDF.
*
......@@ -156,7 +120,11 @@ class Download {
header("Content-type: $mimetype");
header("Content-Length: $length");
// No idea if 'attachment' has disadvantages.
// header("Content-Disposition: attachment; filename=$outputFilename");
header("Content-Disposition: inline; filename=$outputFilename");
header("Pragma: no-cache");
header("Expires: 0");
print file_get_contents($filename);
}
......@@ -178,32 +146,70 @@ class Download {
}
/**
* @param $element
* @return mixed
* Interprets $element and fetches corresponding content as file.
*
* @param string $element - U:id=myExport&r=12, u:http://www.nzz.ch/issue?nr=21, f:fileadmin/sample.pdf
* @return string filename - already ready or fresh exported. Fresh exported needs to be deleted later.
* @throws DownloadException
* @throws \exception
*/
private function getFile($element) {
// $first = each($element);
// $key = $first['key'];
// $arr = explode(DOWNLOAD_PARAMETER_DELIMITER, $key, 2);
// $idx = $arr[0];
if (isset($element[DOWNLOAD_FILE])) {
private function getElement($element) {
$filename = $element[DOWNLOAD_FILE];
$arr = explode(':', $element, 2);
if (count($arr) != 2) {
throw new DownloadException('Missing parameter for "' . $element . '"', ERROR_MISSING_REQUIRED_PARAMETER);
}
} elseif (isset($element[DOWNLOAD_PAGE_ID])) {
$token = $arr[0];
$value = $arr[1];
$filename = $this->html2pdf->page2pdf($element);
switch ($token) {
case TOKEN_URL:
case TOKEN_URL_PARAM:
$filename = $this->html2pdf->page2pdf($token, $value);
break;
} else {
throw new DownloadException('Neither found: ' . DOWNLOAD_FILE . ', ' . DOWNLOAD_PAGE_ID, ERROR_MISSING_REQUIRED_PARAMETER);
case TOKEN_FILE:
$filename = $value;
break;
default:
throw new DownloadException('Unknown token: "' . $token . '"', ERROR_UNKNOWN_TOKEN);
break;
}
return $filename;
}
/**
* Creates a ZIP Files of all given $files
*
* @param array $files
* @return string ZIP filename - has to be deleted later.
* @throws DownloadException
*/
private function zipFiles(array $files) {
$zipFile = tempnam(sys_get_temp_dir(), DOWNLOAD_FILE_PREFIX);
if (false === $zipFile) {
throw new DownloadException("Error creating output file.", ERROR_DOWNLOAD_CREATE_NEW_FILE);
}
$zip = new \ZipArchive();
if ($zip->open($zipFile, \ZipArchive::CREATE) !== TRUE) {
throw new DownloadException("Error creating/opening new empty zip file: $zipFile", ERROR_IO_OPEN);
}
foreach ($files AS $filename) {
$localname = substr($filename, strrpos($filename, '/'));
$zip->addFile($filename, $localname);
}
$zip->close();
return $zipFile;
}
/**
* exportFilename=<new filename>
* mode=file | pdf | excel - default is 'file' in case of only one or 'pdf' in case of multiple sources.
......@@ -213,10 +219,11 @@ class Download {
* Direct
* <i>_file=<filename>
*
* @param array $elements
* @param array $vars [ DOWNLOAD_EXPORT_FILENAME, DOWNLOAD_MODE, SIP_DOWNLOAD_PARAMETER ]
* @throws DownloadException
* @internal param array $elements
*/
private function doElements(array $elements, array $vars) {
private function doElements(array $vars) {
$tmpFiles = array();
......@@ -225,31 +232,35 @@ class Download {
throw new DownloadException ("Error chdir($workDir)", ERROR_IO_CHDIR);
}
$exportFilename = isset($vars[DOWNLOAD_EXPORT_FILENAME]) ? $vars[DOWNLOAD_EXPORT_FILENAME] : '';
$exportFilename = empty($vars[DOWNLOAD_EXPORT_FILENAME]) ? DOWNLOAD_OUTPUT_PDF : $vars[DOWNLOAD_EXPORT_FILENAME];
$downloadMode = $vars[DOWNLOAD_MODE];
$elements = explode(PARAM_DELIMITER, $vars[SIP_DOWNLOAD_PARAMETER]);
// Get all files
foreach ($elements as $element) {
$tmpFiles[] = $this->getFile($element);
$tmpFiles[] = $this->getElement($element);
}
switch (count($tmpFiles)) {
case 0:
throw new DownloadException('Nothing to do.', ERROR_DOWNLOAD_NOTHING_TO_DO);
// Export, Concat File(s)
switch ($downloadMode) {
case DOWNLOAD_MODE_ZIP:
$filename = $this->zipFiles($tmpFiles);
break;
case DOWNLOAD_MODE_EXCEL: