Commit 0d91f660 authored by Elias Villiger's avatar Elias Villiger
Browse files

Merge branch '6357-save-pdf-on-server' into 'master'

6357 save pdf on server

See merge request !59
parents 3c1cd324 b7faa96b
Pipeline #836 passed with stage
in 1 minute and 36 seconds
......@@ -6088,6 +6088,30 @@ A limited set of attributes is supported: ::
SELECT "complete.pdf|Download PDF|fileadmin/test1.pdf|fileadmin/test2.pdf|id=export&r=1" AS _Pdf
.. _column-save-pdf:
Column: _savePdf
^^^^^^^^^^^^^^^^
Generated PDFs can be stored directly on the server with this functionality. The link query consists of the following parameters:
* One or more element sources (such as `F:`, `U:`, `p:`, see download-parameter-files_), including possible wkhtmltopdf parameters
* The export filename and path as `d:` - for security reasons, this path has to start with *fileadmin/*
Tips:
* Please note that this option does not render anything in the front end, but is executed each time it is parsed.
You may want to add a check to prevent multiple execution.
* It is not advised to generate the filename with user input for security reasons.
* If the target file already exists it will be overwriten. To save individual files, choose a new filename,
for example by adding a timestamp.
Examples: ::
SELECT "d:fileadmin/result.pdf|F:fileadmin/_temp_/test.pdf" AS _savePdf
SELECT "d:fileadmin/result.pdf|F:fileadmin/_temp_/test.pdf|U:id=test&--orientation=landscape" AS _savePdf
.. _column-thumbnail:
Column: _thumbnail
......@@ -6253,7 +6277,7 @@ By using the `_link` column name:
* setting `s:1` is mandatory for the download function,
* the alttext `a:...` specifies a message in the download popup.
By using `_pdf`, `_Pdf`, `_file`, `_File`, `_zip`, `_Zip`, `_excel` as column name, the options `d`, `m` and `s`
By using `_pdf`, `_Pdf`, `_file`, `_File`, `_zip`, `_Zip`, `_excel` as column name, the options `d`, `M` and `s`
will be set.
All files will be read by PHP - therefore the directory might be protected against direct web access. This is the
......@@ -6261,7 +6285,7 @@ preferred option 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 functionality described here is not appropriate for
such a scenario.
such a scenario. If necessary, column-save-pdf_ can be used to generate such a file.
.. _download-parameter-files:
......
......@@ -234,6 +234,7 @@ const ERROR_MULTIPLE_URL_PAGE_MAILTO_DEFINITION = 1406;
const ERROR_UNKNOWN_TOKEN = 1407;
const ERROR_TOO_FEW_PARAMETER_FOR_SENDMAIL = 1408;
const ERROR_TOO_MANY_PARAMETER = 1409;
const ERROR_INVALID_SAVE_PDF_FILENAME = 1410;
// Upload
const ERROR_UPLOAD = 1500;
......@@ -1318,6 +1319,7 @@ const COLUMN_PAGES = 'pages';
const COLUMN_YANK = 'yank';
const COLUMN_PDF = 'pdf';
const COLUMN_SAVE_PDF = 'savePdf';
const COLUMN_FILE = 'file';
const COLUMN_ZIP = 'zip';
const COLUMN_MONITOR = 'monitor';
......@@ -1351,6 +1353,7 @@ const FORM_LOG_ACTIVE = 'formLogActive';
const DOWNLOAD_MODE = 'mode';
const DOWNLOAD_MODE_FILE = 'file';
const DOWNLOAD_MODE_PDF = 'pdf';
const DOWNLOAD_MODE_SAVE_PDF = 'save-pdf';
const DOWNLOAD_MODE_EXCEL = 'excel';
const DOWNLOAD_MODE_ZIP = 'zip';
const DOWNLOAD_MODE_THUMBNAIL = 'thumbnail';
......
......@@ -632,21 +632,8 @@ class Save {
throw new UserFormException("Upload failed, no target '" . FE_FILE_DESTINATION . "' specified.", ERROR_NO_TARGET_PATH_FILE_NAME);
}
if (file_exists($pathFileName)) {
if (isset($formElement[FE_FILE_REPLACE_MODE]) && $formElement[FE_FILE_REPLACE_MODE] == FE_FILE_REPLACE_MODE_ALWAYS) {
if (!unlink($pathFileName)) {
throw new UserFormException('Copy upload failed - file exist and unlink() failed: ' . $pathFileName, ERROR_IO_UNLINK);
}
} else {
throw new UserFormException('Copy upload failed - file already exist: ' . $pathFileName, ERROR_IO_FILE_EXIST);
}
}
Support::mkDirParent($pathFileName);
if (!rename($srcFile, $pathFileName)) {
throw new UserFormException("Rename file: '$srcFile' > '$pathFileName'", ERROR_IO_RENAME);
}
$overwrite = isset($formElement[FE_FILE_REPLACE_MODE]) && $formElement[FE_FILE_REPLACE_MODE] == FE_FILE_REPLACE_MODE_ALWAYS;
Support::copyFile($srcFile, $pathFileName, $overwrite);
$this->splitUpload($formElement, $pathFileName);
......
......@@ -1258,6 +1258,30 @@ class Support {
}
}
/**
* @param $srcFile
* @param $pathFileName
* @param bool $overwrite
* @throws UserFormException
*/
public static function copyFile($srcFile, $pathFileName, $overwrite = false) {
if (file_exists($pathFileName)) {
if ($overwrite) {
if (!unlink($pathFileName)) {
throw new UserFormException('Copy upload failed - file exist and unlink() failed: ' . $pathFileName, ERROR_IO_UNLINK);
}
} else {
throw new UserFormException('Copy upload failed - file already exist: ' . $pathFileName, ERROR_IO_FILE_EXIST);
}
}
Support::mkDirParent($pathFileName);
if (!rename($srcFile, $pathFileName)) {
throw new UserFormException("Rename file: '$srcFile' > '$pathFileName'", ERROR_IO_RENAME);
}
}
/**
*
*/
......
......@@ -403,32 +403,24 @@ class Link {
// 1: 'text'
case '1':
$link = $this->wrapLinkTextOnly($vars, FINAL_CONTENT);
break;
case '11':
$link = $this->wrapLinkTextOnly($vars, FINAL_CONTENT);
break;
// 2: 'url'
case '2':
$link = $this->wrapLinkTextOnly($vars, FINAL_HREF);
break;
case '12':
$link = $this->wrapLinkTextOnly($vars, FINAL_HREF);
break;
// 3: <a href=url ...>url</a>
case '3':
$link = Support::wrapTag($vars[FINAL_ANCHOR], $vars[FINAL_HREF]);
break;
case '13':
$link = Support::wrapTag($vars[FINAL_ANCHOR], $vars[FINAL_HREF]);
break;
// 4: <a href=url ...>Text</a>
case '4':
$link = Support::wrapTag($vars[FINAL_ANCHOR], $vars[FINAL_CONTENT]);
break;
case '14':
$link = Support::wrapTag($vars[FINAL_ANCHOR], $vars[FINAL_CONTENT]);
break;
......@@ -503,7 +495,7 @@ class Link {
* @throws UserFormException
* @throws UserReportException
*/
private function fillParameter($str, array &$rcTokenGiven) {
public function fillParameter($str, array &$rcTokenGiven) {
// Define all possible vars: no more isset().
$vars = $this->initVars();
......@@ -794,6 +786,7 @@ class Link {
// Do some checks.
switch ($mode) {
case DOWNLOAD_MODE_PDF:
case DOWNLOAD_MODE_SAVE_PDF:
case DOWNLOAD_MODE_ZIP:
case DOWNLOAD_MODE_EXCEL:
break;
......
......@@ -760,6 +760,28 @@ class Report {
$content .= $this->link->renderLink($linkValue);
break;
case COLUMN_SAVE_PDF:
$tokenGiven = [];
$vars = $this->link->fillParameter($columnValue,$tokenGiven);
$vars[DOWNLOAD_MODE] = DOWNLOAD_MODE_PDF;
$vars[SIP_DOWNLOAD_PARAMETER] = implode(PARAM_DELIMITER, $vars[NAME_COLLECT_ELEMENTS]);
// Save file with specified export filename
$pathFileName = $vars[DOWNLOAD_EXPORT_FILENAME];
$sanitizedFileName = Sanitize::safeFilename($pathFileName, false, true);
if($pathFileName == '' ||
substr($pathFileName, 0, strlen("fileadmin/")) !== "fileadmin/" ||
substr($pathFileName, -4) !== '.pdf') {
throw new UserReportException( "savePdf filenames need to be in the fileadmin/ directory and end in .pdf for security reasons.", ERROR_INVALID_SAVE_PDF_FILENAME);
} elseif ($pathFileName !== $sanitizedFileName) {
throw new UserReportException("The provided filename '$pathFileName' does not meet sanitize criteria. Use '$sanitizedFileName' instead.", ERROR_INVALID_SAVE_PDF_FILENAME);
} else {
$download = new Download();
$file = $download->process($vars, OUTPUT_MODE_FILE);
Support::copyFile($file, $pathFileName, true);
}
break;
case COLUMN_THUMBNAIL:
if ($this->thumbnail == null) {
$this->thumbnail = new Thumbnail();
......@@ -1206,6 +1228,7 @@ class Report {
}
$columNameToMode = [COLUMN_PDF => DOWNLOAD_MODE_PDF,
COLUMN_SAVE_PDF => DOWNLOAD_MODE_PDF,
COLUMN_FILE => DOWNLOAD_MODE_FILE,
COLUMN_ZIP => DOWNLOAD_MODE_ZIP,
COLUMN_EXCEL => DOWNLOAD_MODE_EXCEL];
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment