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
81
82
83
     */
    public function __construct($phpUnit = false) {

        $this->session = Session::getInstance($phpUnit);
        $this->store = Store::getInstance('', $phpUnit);
        $this->db = new Database();
84
        $this->html2pdf = new Html2Pdf($this->store->getStore(STORE_SYSTEM), $phpUnit);
85

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

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

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

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

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

Carsten  Rose's avatar
Carsten Rose committed
117
118
119
120
        // 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
121
                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
122
123
124
            }
        }

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

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

Carsten  Rose's avatar
Carsten Rose committed
135
136
137
        // 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
138
            throw new \DownloadException('Error creating output file.', ERROR_DOWNLOAD_CREATE_NEW_FILE);
Carsten  Rose's avatar
Carsten Rose committed
139
140
        }

141
142
143
//        $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
144

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

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

        if ($rc != 0) {
Marc Egger's avatar
Marc Egger committed
152
            throw new \DownloadException (json_encode([ERROR_MESSAGE_TO_USER => "Failed to merge PDF file",
153
154
                    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
155
156
157
158
159
160
        }

        return $concatFile;
    }

    /**
161
162
     * 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
163
     *
164
165
166
     * @param string $filename
     * @param string $outputFilename
     * @param string $rcMimetype
Carsten  Rose's avatar
Carsten Rose committed
167
     *
168
     * @return string possible updated $outputFilename, according the mimetype.
Carsten  Rose's avatar
Carsten Rose committed
169
     */
170
    private function targetFilenameExtension($filename, $outputFilename, &$rcMimetype) {
Carsten  Rose's avatar
Carsten Rose committed
171

172
        $rcMimetype = mime_content_type($filename);
173

174
175
176
177
178
179
        return $outputFilename;
    }

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

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

189
        $outputFilename = $this->targetFilenameExtension($file, $outputFilename, $mimeType);
190
        $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.
191

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

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

        header("Content-type: $mimeType");
Carsten  Rose's avatar
Carsten Rose committed
206
        header("Content-Length: $length");
207
        if (!$flagJson) {
208
209
210
211
            // 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
212
213
        header("Pragma: no-cache");
        header("Expires: 0");
Carsten  Rose's avatar
Carsten Rose committed
214

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

    /**
223
     * Interprets $element and fetches corresponding content, either as a file or the content in a variable.
Carsten  Rose's avatar
Carsten Rose committed
224
225
     *
     * @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
226
     *
227
     * @param string $downloadMode - DOWNLOAD_MODE_EXCEL | ....
228
     * @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
229
     * @return string filename - already ready or fresh exported. Fresh exported needs to be deleted later.
Marc Egger's avatar
Marc Egger committed
230
231
232
233
234
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
235
236
237
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
Carsten  Rose's avatar
Carsten Rose committed
238
     */
239
    private function getElement($element, $downloadMode, &$rcData) {
Carsten  Rose's avatar
Carsten Rose committed
240

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

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

Carsten  Rose's avatar
Carsten Rose committed
251
252
        $token = $arr[0];
        $value = $arr[1];
253
254
255
256
257
        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
258

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

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

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

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

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

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

        return $filename;
    }

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

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

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

    }

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

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

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

        $zip = new \ZipArchive();

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

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

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

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

        return $zipFile;
    }

Carsten  Rose's avatar
Carsten Rose committed
378
    /**
379
380
     * $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
381
382
383
384
     * HTML to PDF | Excel
     *   <i>_id=<Typo3 pageId>
     *   <i>_<key>=<value i>
     * Direct
385
     *   <i>_file=<filename>
Carsten  Rose's avatar
Carsten Rose committed
386
     *
Carsten  Rose's avatar
Carsten Rose committed
387
     * @param array $vars [ DOWNLOAD_EXPORT_FILENAME, DOWNLOAD_MODE, SIP_DOWNLOAD_PARAMETER ]
Carsten  Rose's avatar
Carsten Rose committed
388
     *
Carsten  Rose's avatar
Carsten Rose committed
389
390
     * @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
391
392
393
394
395
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \UserFormException
     * @throws \UserReportException
396
397
398
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
Carsten  Rose's avatar
Carsten Rose committed
399
     */
400
    private function doElements(array $vars, $outputMode) {
Carsten  Rose's avatar
Carsten Rose committed
401
402
403
404

        $tmpFiles = array();

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

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

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

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

415
416
417
418
419
420
421
        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
422
        $elements = explode(PARAM_DELIMITER, $vars[SIP_DOWNLOAD_PARAMETER]);
Carsten  Rose's avatar
Carsten Rose committed
423

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

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

            case DOWNLOAD_MODE_EXCEL:
444
445
446
447
448
449
450
451
452
                $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
453
454
                break;

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

            case DOWNLOAD_MODE_PDF:
463

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

466
467
468
469
470
471
472
473
474
475
476
477
                // 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
478
479
480
                break;

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

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

491
492
493
494
495
        switch ($outputMode) {

            case OUTPUT_MODE_FILE:
                break;

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

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

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

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

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

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

        return $pathFilenameThumbnail;
    }

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

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

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

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

556
557
558
559
560
561
562
563
564
565
566
567
568
    /**
     * @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;
    }
569
}
Carsten  Rose's avatar
Carsten Rose committed
570