Download.php 19.8 KB
Newer Older
Carsten  Rose's avatar
Carsten Rose committed
1
2
3
4
5
6
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 4/17/17
 * Time: 11:32 AM
Carsten  Rose's avatar
Carsten Rose committed
7
8
 *
 * Check: CODING.md > Download
Carsten  Rose's avatar
Carsten Rose committed
9
10
 */

Marc Egger's avatar
Marc Egger committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace IMATHUZH\Qfq\Core\Report;

use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Store\Session;
use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Store\Sip;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\Sanitize;
use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\DownloadPage;
use IMATHUZH\Qfq\Core\QuickFormQuery;

use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Helper\Support;
Carsten  Rose's avatar
Carsten Rose committed
27
28
29
30

/**
 * Class Download
 *
31
32
 * Documentation: PROTOCOL.md >> Download
 *
Carsten  Rose's avatar
Carsten Rose committed
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 * Param: i=1..n
 *   <i>_mode=direct | html2pdf
 *   <i>_id=<pageId>
 *   <i>_<key i>=<value i>
 *
 * @package qfq
 */
class Download {

    /**
     * @var Store
     */
    private $store = null;

    /**
     * @var Session
     */
    private $session = null;

    /**
     * @var Database
     */
    private $db = null;

    /**
     * @var Html2Pdf
     */
    private $html2pdf = null;

62
63
64
65
66
    /**
     * @var string Filename where to write download Information
     */
    private $downloadDebugLog = '';

67
68
69
70
71
    /**
     * @var string DOWNLOAD_OUTPUT_FORMAT_RAW | DOWNLOAD_OUTPUT_FORMAT_JSON
     */
    private $outputFormat = DOWNLOAD_OUTPUT_FORMAT_RAW;

Carsten  Rose's avatar
Carsten Rose committed
72
73
    /**
     * @param bool|false $phpUnit
Marc Egger's avatar
Marc Egger committed
74
75
76
77
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     * @throws \UserReportException
Carsten  Rose's avatar
Carsten Rose committed
78
79
80
     */
    public function __construct($phpUnit = false) {

81
        #TODO: rewrite $phpUnit to: "if (!defined('PHPUNIT_QFQ')) {...}"
Carsten  Rose's avatar
Carsten Rose committed
82
83
84
        $this->session = Session::getInstance($phpUnit);
        $this->store = Store::getInstance('', $phpUnit);
        $this->db = new Database();
85
        $this->html2pdf = new Html2Pdf($this->store->getStore(STORE_SYSTEM), $phpUnit);
86

87
        if (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_DOWNLOAD, $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM))) {
88
89
            $this->downloadDebugLog = $this->store->getVar(SYSTEM_SQL_LOG, STORE_SYSTEM);
        }
Carsten  Rose's avatar
Carsten Rose committed
90
91
92
93
94
95
    }

    /**
     * Concatenate all named files to one PDF file. Return name of new full PDF.
     *
     * @param array $files
Carsten  Rose's avatar
Carsten Rose committed
96
     *
Carsten  Rose's avatar
Carsten Rose committed
97
     * @return string  - fileName of concatenated file
Marc Egger's avatar
Marc Egger committed
98
99
100
     * @throws \CodeException
     * @throws \DownloadException
     * @throws \UserFormException
Carsten  Rose's avatar
Carsten Rose committed
101
102
103
     */
    private function concatPdfFiles(array $files) {

104
105
106
        // Remove empty entries. Might happen if there was no upload
        $files = OnArray::removeEmptyElementsFromArray($files);

Carsten  Rose's avatar
Carsten Rose committed
107
        // Check that all files exist and are readable
108
        foreach ($files AS $filename) {
109
            if (!is_readable($filename)) {
Marc Egger's avatar
Marc Egger committed
110
                throw new \DownloadException("Error reading file $filename. Not found or no permission", ERROR_DOWNLOAD_FILE_NOT_READABLE);
111
112
113
            }
        }

Carsten  Rose's avatar
Carsten Rose committed
114
115
116
        if (count($files) === 0) {
            return '';
        }
117

Carsten  Rose's avatar
Carsten Rose committed
118
119
120
121
        // Check that all files are of type 'application/pdf'
        foreach ($files AS $filename) {
            $mimetype = mime_content_type($filename);
            if ($mimetype != 'application/pdf') {
Marc Egger's avatar
Marc Egger committed
122
                throw new \DownloadException("Error concat file $filename. Mimetype 'application/pdf' expected, got: $mimetype", ERROR_DOWNLOAD_UNEXPECTED_MIME_TYPE);
Carsten  Rose's avatar
Carsten Rose committed
123
124
125
            }
        }

Carsten  Rose's avatar
Carsten Rose committed
126
127
128
        if (count($files) == 1) {
            return $files[0];
        }
Carsten  Rose's avatar
Carsten Rose committed
129

Carsten  Rose's avatar
Carsten Rose committed
130
        $files = OnArray::arrayEscapeshellarg($files);
Carsten  Rose's avatar
Carsten Rose committed
131
132
        $inputFiles = implode(' ', $files);
        if (trim($inputFiles) == '') {
Marc Egger's avatar
Marc Egger committed
133
            throw new \DownloadException('No files to concatenate.', ERROR_DOWNLOAD_NO_FILES);
Carsten  Rose's avatar
Carsten Rose committed
134
135
        }

Carsten  Rose's avatar
Carsten Rose committed
136
137
138
        // Need to create a separate result file, even if it is just a single file (#6929)
        $concatFile = HelperFile::tempnam();
        if (false === $concatFile) {
Marc Egger's avatar
Marc Egger committed
139
            throw new \DownloadException('Error creating output file.', ERROR_DOWNLOAD_CREATE_NEW_FILE);
Carsten  Rose's avatar
Carsten Rose committed
140
141
        }

142
143
144
//        $cmd = "pdftk $inputFiles cat output $concatFile 2>&1";  # Outdated. Hard to install on Ubuntu 18. Fails for recent PDFs.
//        $cmd = "qpdf --empty --pages $inputFiles -- $concatFile 2>&1"; # Fails to merge identical files, if they contain references.
        $cmd = "pdfunite $inputFiles $concatFile 2>&1"; // Based on poppler. URLs are preserved. Orientation and size are preserved.
Carsten  Rose's avatar
Carsten Rose committed
145

146
147
148
149
        if ($this->downloadDebugLog != '') {
            Logger::logMessage("Download: $cmd", $this->downloadDebugLog);
        }

Carsten  Rose's avatar
Carsten Rose committed
150
151
152
        exec($cmd, $output, $rc);

        if ($rc != 0) {
Marc Egger's avatar
Marc Egger committed
153
            throw new \DownloadException (json_encode([ERROR_MESSAGE_TO_USER => "Failed to merge PDF file",
154
155
                    ERROR_MESSAGE_TO_DEVELOPER => "CMD: " . $cmd . "<br>RC: $rc<br>Output: " . implode("<br>", $output)])
                , ERROR_DOWNLOAD_MERGE_FAILED);
Carsten  Rose's avatar
Carsten Rose committed
156
157
158
159
160
161
        }

        return $concatFile;
    }

    /**
162
163
     * Get the mimetype of $filename and store them in $rcMimetype.
     * Checks if the extension of $outputFilename fit's to the mimetype. If not, append the mimetype extension.
Carsten  Rose's avatar
Carsten Rose committed
164
     *
165
166
167
     * @param string $filename
     * @param string $outputFilename
     * @param string $rcMimetype
Carsten  Rose's avatar
Carsten Rose committed
168
     *
169
     * @return string possible updated $outputFilename, according the mimetype.
Carsten  Rose's avatar
Carsten Rose committed
170
     */
171
    private function targetFilenameExtension($filename, $outputFilename, &$rcMimetype) {
Carsten  Rose's avatar
Carsten Rose committed
172

173
        $rcMimetype = mime_content_type($filename);
174

175
176
177
178
179
180
        return $outputFilename;
    }

    /**
     * Set header type and output $filename. Be careful not to send any additional characters.
     *
181
     * @param $file
182
     * @param $outputFilename
Marc Egger's avatar
Marc Egger committed
183
     * @throws \DownloadException
184
     */
185
    private function outputFile($file, $outputFilename) {
186

187
188
        $json = '';
        $flagJson = ($this->getOutputFormat() === DOWNLOAD_OUTPUT_FORMAT_JSON);
189

190
        $outputFilename = $this->targetFilenameExtension($file, $outputFilename, $mimeType);
191
        $outputFilename = Sanitize::safeFilename($outputFilename); // be sure that there are no problematic chars in the filename. E.g. MacOS X don't like spaces for downloads.
192

193
194
        if ($flagJson) {
            if (false === ($json = json_encode([JSON_TEXT => file_get_contents($file)]))) {
Marc Egger's avatar
Marc Egger committed
195
                throw new \DownloadException(json_encode(
196
                    [ERROR_MESSAGE_TO_USER => 'Error converting to JSON',
Marc Egger's avatar
Marc Egger committed
197
                        ERROR_MESSAGE_TO_DEVELOPER => "json_last_error()=" . json_last_error() . ", File=" . $file]), ERROR_DOWNLOAD_JSON_CONVERT);
198
199
200
201
202
203
204
205
206
            }
            $length = strlen($json);

            $mimeType = 'application/json';
        } else {
            $length = filesize($file);
        }

        header("Content-type: $mimeType");
Carsten  Rose's avatar
Carsten Rose committed
207
        header("Content-Length: $length");
208
        if (!$flagJson) {
209
210
211
212
            // If defined as 'attachment': PDFs are not shown inside the browser (if user configured that). Instead, always a 'save as'-dialog appears (Chrome, FF)
            // header("Content-Disposition: attachment; filename=$outputFilename");
            header("Content-Disposition: inline; filename=\"$outputFilename\"; name=\"$outputFilename\"");
        }
Carsten  Rose's avatar
Carsten Rose committed
213
214
        header("Pragma: no-cache");
        header("Expires: 0");
Carsten  Rose's avatar
Carsten Rose committed
215

216
217
        if ($flagJson) {
            print $json;
218
        } else {
219
            readfile($file);
220
        }
Carsten  Rose's avatar
Carsten Rose committed
221
222
223
    }

    /**
224
     * Interprets $element and fetches corresponding content, either as a file or the content in a variable.
Carsten  Rose's avatar
Carsten Rose committed
225
226
     *
     * @param string $element - U:id=myExport&r=12, u:http://www.nzz.ch/issue?nr=21, f:fileadmin/sample.pdf
Carsten  Rose's avatar
Carsten Rose committed
227
     *
228
     * @param string $downloadMode - DOWNLOAD_MODE_EXCEL | ....
229
     * @param string $rcData - With $downloadMode=DOWNLOAD_MODE_EXCEL, this contains the rendered code from the given T3 page.
Carsten  Rose's avatar
Carsten Rose committed
230
     * @return string filename - already ready or fresh exported. Fresh exported needs to be deleted later.
Marc Egger's avatar
Marc Egger committed
231
232
233
234
235
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
236
237
238
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
Carsten  Rose's avatar
Carsten Rose committed
239
     */
240
    private function getElement($element, $downloadMode, &$rcData) {
Carsten  Rose's avatar
Carsten Rose committed
241

242
243
244
245
        $filename = '';
        $rcArgs = array();
        $rcSipEncode = false;

Carsten  Rose's avatar
Carsten Rose committed
246
247
        $arr = explode(':', $element, 2);
        if (count($arr) != 2) {
248
            $possibleReason = ($element === '') ? 'If this is a download link, did you forget to include s:1?' : '';
Marc Egger's avatar
Marc Egger committed
249
            throw new \DownloadException("Missing parameter for '$element'. $possibleReason", ERROR_MISSING_REQUIRED_PARAMETER);
Carsten  Rose's avatar
Carsten Rose committed
250
        }
Carsten  Rose's avatar
Carsten Rose committed
251

Carsten  Rose's avatar
Carsten Rose committed
252
253
        $token = $arr[0];
        $value = $arr[1];
254
255
256
257
258
        if ($token === TOKEN_UID) { // extract uid
            $uidParamsArr = explode('&', $value, 2);
            $uid = $uidParamsArr[0];
            $value = $uidParamsArr[1] ?? ''; // additional params
        }
Carsten  Rose's avatar
Carsten Rose committed
259

Carsten  Rose's avatar
Carsten Rose committed
260
261
262
        switch ($token) {
            case TOKEN_URL:
            case TOKEN_URL_PARAM:
263
            case TOKEN_PAGE:
264
            case TOKEN_UID:
265
266
267
268
269
270
                $urlParam = OnString::splitParam($value, $rcArgs, $rcSipEncode);
                $urlParamString = KeyValueStringParser::unparse($urlParam, '=', '&');
                if ($rcSipEncode) {
                    $sip = new Sip();
                    $urlParamString = $sip->queryStringToSip($urlParamString, RETURN_URL);
                }
271

272
                if ($downloadMode == DOWNLOAD_MODE_EXCEL) {
273
                    if ($token === TOKEN_UID) {
274
                        $rcData = $this->getEvaluatedBodytext($uid, $urlParam);
275
276
277
278
                    } else {
                        $baseUrl = $this->store->getVar(SYSTEM_BASE_URL, STORE_SYSTEM);
                        $rcData = DownloadPage::getContent($urlParamString, $baseUrl);
                    }
279
                } else {
280
281
282
283
284
                    if ($token === TOKEN_UID) {
                        // create tmp html document with bodytext
                        $htmlText = $this->getEvaluatedBodytext($uid, $urlParam);
                        $tmpFilename = HelperFile::tempnam() . '.html';

285
                        $tmpFile = fopen($tmpFilename, "w") or die('Cannot create file:  ' . $tmpFilename);
286
287
288
289
290
                        fwrite($tmpFile, $htmlText);
                        fclose($tmpFile);

                        $rcArgsString = KeyValueStringParser::unparse($rcArgs, '=', '&');
                        $url = Support::mergeUrlComponents('', $tmpFilename, $rcArgsString);
291
292
293
                        $filename = $this->html2pdf->page2pdf($token, $url);
                        HelperFile::cleanTempFiles([$tmpFilename]);

294
                    } else {
295
                        $filename = $this->html2pdf->page2pdf($token, $value);
296
                    }
297
                }
Carsten  Rose's avatar
Carsten Rose committed
298
                break;
Carsten  Rose's avatar
Carsten Rose committed
299

Carsten  Rose's avatar
Carsten Rose committed
300
            case TOKEN_FILE:
301
            case TOKEN_FILE_DEPRECATED:
Carsten  Rose's avatar
Carsten Rose committed
302
303
304
                $filename = $value;
                break;
            default:
Marc Egger's avatar
Marc Egger committed
305
                throw new \DownloadException('Unknown token: "' . $token . '"', ERROR_UNKNOWN_TOKEN);
Carsten  Rose's avatar
Carsten Rose committed
306
                break;
Carsten  Rose's avatar
Carsten Rose committed
307
308
309
310
311
        }

        return $filename;
    }

312
313
314
315
316
    /**
     * @param $uid
     * @param array $urlParam
     *
     * @return string
Marc Egger's avatar
Marc Egger committed
317
318
319
320
321
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
322
323
324
325
326
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    private function getEvaluatedBodyText($uid, $urlParam) {
327
        foreach ($urlParam as $key => $paramValue) {
328
329
330
            $this->store->setVar($key, $paramValue, STORE_SIP);
        }

331
        $dbT3 = $this->store->getVar(SYSTEM_DB_NAME_T3, STORE_SYSTEM);
332
333
334
        $sql = "SELECT bodytext FROM $dbT3.tt_content WHERE uid = ?";
        $tt_content = $this->db->sql($sql, ROW_EXPECT_1, [$uid]);

335
        $qfq = new QuickFormQuery([T3DATA_BODYTEXT => $tt_content[T3DATA_BODYTEXT]], false, false);
336
337
338
339
        return $qfq->process();

    }

Carsten  Rose's avatar
Carsten Rose committed
340
341
342
343
344

    /**
     * Creates a ZIP Files of all given $files
     *
     * @param array $files
Carsten  Rose's avatar
Carsten Rose committed
345
     *
Carsten  Rose's avatar
Carsten Rose committed
346
     * @return string ZIP filename - has to be deleted later.
Marc Egger's avatar
Marc Egger committed
347
     * @throws \DownloadException
Carsten  Rose's avatar
Carsten Rose committed
348
349
350
     */
    private function zipFiles(array $files) {

351
        $zipFile = HelperFile::tempnam();
Carsten  Rose's avatar
Carsten Rose committed
352
        if (false === $zipFile) {
Marc Egger's avatar
Marc Egger committed
353
            throw new \DownloadException("Error creating output file.", ERROR_DOWNLOAD_CREATE_NEW_FILE);
Carsten  Rose's avatar
Carsten Rose committed
354
355
356
357
        }

        $zip = new \ZipArchive();

Carsten  Rose's avatar
Carsten Rose committed
358
        if ($zip->open($zipFile, \ZipArchive::CREATE) !== true) {
Marc Egger's avatar
Marc Egger committed
359
            throw new \DownloadException("Error creating/opening new empty zip file: $zipFile", ERROR_IO_OPEN);
Carsten  Rose's avatar
Carsten Rose committed
360
361
        }

362
        $len = strlen(TMP_FILE_PREFIX);
363
        $ii = 1;
Carsten  Rose's avatar
Carsten Rose committed
364
        foreach ($files AS $filename) {
365
            $localName = substr($filename, strrpos($filename, '/') + 1);
366

367
368
            if (substr($localName, 0, $len) == TMP_FILE_PREFIX) {
                $localName = 'file-' . $ii;
369
370
371
                $ii++;
            }

372
            $zip->addFile($filename, $localName);
Carsten  Rose's avatar
Carsten Rose committed
373
374
375
376
377
378
        }
        $zip->close();

        return $zipFile;
    }

Carsten  Rose's avatar
Carsten Rose committed
379
    /**
380
381
     * $vars[DOWNLOAD_EXPORT_FILENAME] - Optional. '<new filename>'
     * $vars[DOWNLOAD_MODE] - Optional.  file | pdf | excel | thumbnail | monitor - default is a) 'file' in case of only one or b) 'pdf' in case of multiple sources.
Carsten  Rose's avatar
Carsten Rose committed
382
383
384
385
     * HTML to PDF | Excel
     *   <i>_id=<Typo3 pageId>
     *   <i>_<key>=<value i>
     * Direct
386
     *   <i>_file=<filename>
Carsten  Rose's avatar
Carsten Rose committed
387
     *
Carsten  Rose's avatar
Carsten Rose committed
388
     * @param array $vars [ DOWNLOAD_EXPORT_FILENAME, DOWNLOAD_MODE, SIP_DOWNLOAD_PARAMETER ]
Carsten  Rose's avatar
Carsten Rose committed
389
     *
Carsten  Rose's avatar
Carsten Rose committed
390
391
     * @param string $outputMode OUTPUT_MODE_DIRECT | OUTPUT_MODE_FILE | OUTPUT_MODE_COPY_TO_FILE
     * @return string            Filename of the generated file. The filename only points to a real existing filename with  $outputMode=OUTPUT_MODE_FILE | OUTPUT_MODE_COPY_TO_FILE
Marc Egger's avatar
Marc Egger committed
392
393
394
395
396
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
397
398
399
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
Carsten  Rose's avatar
Carsten Rose committed
400
     */
401
    private function doElements(array $vars, $outputMode) {
Carsten  Rose's avatar
Carsten Rose committed
402
403
404
405

        $tmpFiles = array();

        $workDir = $this->store->getVar(SYSTEM_SITE_PATH, STORE_SYSTEM);
406
        HelperFile::chdir($workDir);
Carsten  Rose's avatar
Carsten Rose committed
407

Carsten  Rose's avatar
Carsten Rose committed
408
        $downloadMode = $vars[DOWNLOAD_MODE];
409

410
        if ($downloadMode == DOWNLOAD_MODE_MONITOR) {
411
            $monitor = new Monitor();
Carsten  Rose's avatar
Carsten Rose committed
412
413

            return $monitor->dump($vars[TOKEN_L_FILE], $vars[TOKEN_L_TAIL], $vars[TOKEN_L_APPEND]);
414
415
        }

416
417
418
419
420
421
422
        if ($downloadMode == DOWNLOAD_MODE_THUMBNAIL) {
            // Fake $vars control array.
            $pathFilenameThumbnail = $this->doThumbnail($vars[SIP_DOWNLOAD_PARAMETER]);
            $downloadMode = DOWNLOAD_MODE_FILE;
            $vars[SIP_DOWNLOAD_PARAMETER] = TOKEN_FILE . ':' . $pathFilenameThumbnail;
        }

Carsten  Rose's avatar
Carsten Rose committed
423
        $elements = explode(PARAM_DELIMITER, $vars[SIP_DOWNLOAD_PARAMETER]);
Carsten  Rose's avatar
Carsten Rose committed
424

425
        // Get all files / content
426
        $tmpData = array();
Carsten  Rose's avatar
Carsten Rose committed
427
        foreach ($elements as $element) {
428
            $data = '';
429
            $tmpFiles[] = $this->getElement($element, $downloadMode, $data);
430
431
            if (!empty($data)) {
                $tmpData[] = $data;
432
            }
Carsten  Rose's avatar
Carsten Rose committed
433
434
        }

Carsten  Rose's avatar
Carsten Rose committed
435
436
437
438
        // Export, Concat File(s)
        switch ($downloadMode) {
            case DOWNLOAD_MODE_ZIP:
                $filename = $this->zipFiles($tmpFiles);
439
440
441
                if (empty($vars[DOWNLOAD_EXPORT_FILENAME])) {
                    $vars[DOWNLOAD_EXPORT_FILENAME] = basename($filename);
                }
Carsten  Rose's avatar
Carsten Rose committed
442
443
444
                break;

            case DOWNLOAD_MODE_EXCEL:
445
446
447
448
449
450
451
452
453
                $excel = new Excel();
                $filename = $excel->process($tmpFiles, $tmpData);
                if (empty($vars[DOWNLOAD_EXPORT_FILENAME])) {
                    if (HelperFile::isQfqTemp($filename)) {
                        $vars[DOWNLOAD_EXPORT_FILENAME] = DOWNLOAD_OUTPUT_FILENAME . ".xlsx";
                    } else {
                        $vars[DOWNLOAD_EXPORT_FILENAME] = basename($filename);
                    }
                }
Carsten  Rose's avatar
Carsten Rose committed
454
455
                break;

Carsten  Rose's avatar
Carsten Rose committed
456
            case DOWNLOAD_MODE_FILE:
Carsten  Rose's avatar
Carsten Rose committed
457
                $filename = $tmpFiles[0];
458
                if (empty($vars[DOWNLOAD_EXPORT_FILENAME])) {
459
                    $vars[DOWNLOAD_EXPORT_FILENAME] = basename($filename);
460
                }
Carsten  Rose's avatar
Carsten Rose committed
461
                break;
Carsten  Rose's avatar
Carsten Rose committed
462
463

            case DOWNLOAD_MODE_PDF:
464

Carsten  Rose's avatar
Carsten Rose committed
465
                $filename = $this->concatPdfFiles($tmpFiles);
466

467
468
469
470
471
472
473
474
475
476
477
478
                // try to find a meaningful filename
                if (empty($vars[DOWNLOAD_EXPORT_FILENAME])) {
                    if (count($tmpFiles) > 1) {
                        $vars[DOWNLOAD_EXPORT_FILENAME] = DOWNLOAD_OUTPUT_FILENAME . ".pdf";
                    } else {
                        if (HelperFile::isQfqTemp($filename)) {
                            $vars[DOWNLOAD_EXPORT_FILENAME] = DOWNLOAD_OUTPUT_FILENAME . ".pdf";
                        } else {
                            $vars[DOWNLOAD_EXPORT_FILENAME] = basename($filename);
                        }
                    }
                }
Carsten  Rose's avatar
Carsten Rose committed
479
480
481
                break;

            default:
Marc Egger's avatar
Marc Egger committed
482
                throw new \DownloadException("Unknown downloadMode: $downloadMode", ERROR_UNKNOWN_MODE);
Carsten  Rose's avatar
Carsten Rose committed
483
484
485
                break;
        }

486
        if ($filename != '' && !file_exists($filename)) {
Marc Egger's avatar
Marc Egger committed
487
            throw new \DownloadException(json_encode(
488
                [ERROR_MESSAGE_TO_USER => 'Can\'t read file',
Marc Egger's avatar
Marc Egger committed
489
                    ERROR_MESSAGE_TO_DEVELOPER => "File: $filename"]), ERROR_IO_FILE_EXIST);
490
491
        }

492
493
494
495
496
        switch ($outputMode) {

            case OUTPUT_MODE_FILE:
                break;

Carsten  Rose's avatar
Carsten Rose committed
497
498
499
500
501
            case OUTPUT_MODE_COPY_TO_FILE:
                HelperFile::copy($filename, $vars[DOWNLOAD_EXPORT_FILENAME]);
                HelperFile::cleanTempFiles([$filename]);
                break;

502
            case OUTPUT_MODE_DIRECT:
503
                $this->outputFile($filename, $vars[DOWNLOAD_EXPORT_FILENAME]);
504
                HelperFile::cleanTempFiles([$filename]);
505
                $filename = '';
506
                break;
Carsten  Rose's avatar
Carsten Rose committed
507

508
            default:
Marc Egger's avatar
Marc Egger committed
509
                throw new \CodeException('Unkown mode: ' . $outputMode, ERROR_UNKNOWN_MODE);
510
511
512
        }

        return $filename;
Carsten  Rose's avatar
Carsten Rose committed
513
514
    }

515
516
517
    /**
     * @param string $urlParam
     * @return string
Marc Egger's avatar
Marc Egger committed
518
519
520
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
521
522
523
524
525
526
527
528
529
     */
    private function doThumbnail($urlParam) {

        $thumbnail = new Thumbnail();
        $pathFilenameThumbnail = $thumbnail->process($urlParam, THUMBNAIL_VIA_DOWNLOAD);

        return $pathFilenameThumbnail;
    }

Carsten  Rose's avatar
Carsten Rose committed
530
    /**
531
532
     * Process download as requested in $vars. Output is either directly send to the browser, or a file which has to be deleted later.
     *
533
     * @param string|array $vars - If $config is an array, take it, else get values from STORE_SIP
534
535
     * @param string $outputMode OUTPUT_MODE_DIRECT | OUTPUT_MODE_FILE
     *
Carsten  Rose's avatar
Carsten Rose committed
536
     * @return string
Marc Egger's avatar
Marc Egger committed
537
538
539
540
541
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
542
543
544
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
Carsten  Rose's avatar
Carsten Rose committed
545
     */
546
    public function process($vars, $outputMode = OUTPUT_MODE_DIRECT) {
Carsten  Rose's avatar
Carsten Rose committed
547

548
549
550
        if (!is_array($vars)) {
            $vars = $this->store->getStore(STORE_SIP);
        }
551

552
553
        $this->setOutputFormat(empty($vars[DOWNLOAD_OUTPUT_FORMAT]) ? DOWNLOAD_OUTPUT_FORMAT_RAW : $vars[DOWNLOAD_OUTPUT_FORMAT]);

554
        return $this->doElements($vars, $outputMode);
Carsten  Rose's avatar
Carsten Rose committed
555
556
    }

557
558
559
560
561
562
563
564
565
566
567
568
569
    /**
     * @param $outputFormat
     */
    private function setOutputFormat($outputFormat) {
        $this->outputFormat = $outputFormat;
    }

    /**
     * @return string - DOWNLOAD_OUTPUT_FORMAT_RAW | DOWNLOAD_OUTPUT_FORMAT_JSON
     */
    public function getOutputFormat() {
        return $this->outputFormat;
    }
570
}
Carsten  Rose's avatar
Carsten Rose committed
571