1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpOffice\PhpSpreadsheet\Helper; |
4
|
|
|
|
5
|
|
|
use PhpOffice\PhpSpreadsheet\Exception; |
6
|
|
|
|
7
|
|
|
class Downloader |
8
|
|
|
{ |
9
|
|
|
protected string $filepath; |
10
|
|
|
|
11
|
|
|
protected string $filename; |
12
|
|
|
|
13
|
|
|
protected string $filetype; |
14
|
|
|
|
15
|
|
|
protected const CONTENT_TYPES = [ |
16
|
|
|
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
17
|
|
|
'xls' => 'application/vnd.ms-excel', |
18
|
|
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet', |
19
|
|
|
'csv' => 'text/csv', |
20
|
|
|
'pdf' => 'application/pdf', |
21
|
|
|
]; |
22
|
|
|
|
23
|
|
|
public function __construct(string $folder, string $filename, ?string $filetype = null) |
24
|
|
|
{ |
25
|
|
|
if ((is_dir($folder) === false) || (is_readable($folder) === false)) { |
26
|
|
|
throw new Exception("Folder {$folder} is not accessable"); |
27
|
|
|
} |
28
|
|
|
$filepath = "{$folder}/{$filename}"; |
29
|
|
|
$this->filepath = (string) realpath($filepath); |
30
|
|
|
$this->filename = basename($filepath); |
31
|
|
|
if ((file_exists($this->filepath) === false) || (is_readable($this->filepath) === false)) { |
32
|
|
|
throw new Exception("{$this->filename} not found, or cannot be read"); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
$filetype ??= pathinfo($filename, PATHINFO_EXTENSION); |
36
|
|
|
if (array_key_exists(strtolower($filetype), self::CONTENT_TYPES) === false) { |
|
|
|
|
37
|
|
|
throw new Exception("Invalid filetype: {$filetype} cannot be downloaded"); |
38
|
|
|
} |
39
|
|
|
$this->filetype = strtolower($filetype); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
public function download(): void |
43
|
|
|
{ |
44
|
|
|
$this->headers(); |
45
|
|
|
|
46
|
|
|
readfile($this->filepath); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
public function headers(): void |
50
|
|
|
{ |
51
|
|
|
ob_clean(); |
52
|
|
|
|
53
|
|
|
$this->contentType(); |
54
|
|
|
$this->contentDisposition(); |
55
|
|
|
$this->cacheHeaders(); |
56
|
|
|
$this->fileSize(); |
57
|
|
|
|
58
|
|
|
flush(); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
protected function contentType(): void |
62
|
|
|
{ |
63
|
|
|
header('Content-Type: ' . self::CONTENT_TYPES[$this->filetype]); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
protected function contentDisposition(): void |
67
|
|
|
{ |
68
|
|
|
header('Content-Disposition: attachment;filename="' . $this->filename . '"'); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
protected function cacheHeaders(): void |
72
|
|
|
{ |
73
|
|
|
header('Cache-Control: max-age=0'); |
74
|
|
|
// If you're serving to IE 9, then the following may be needed |
75
|
|
|
header('Cache-Control: max-age=1'); |
76
|
|
|
|
77
|
|
|
// If you're serving to IE over SSL, then the following may be needed |
78
|
|
|
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past |
79
|
|
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified |
80
|
|
|
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1 |
81
|
|
|
header('Pragma: public'); // HTTP/1.0 |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
protected function fileSize(): void |
85
|
|
|
{ |
86
|
|
|
header('Content-Length: ' . filesize($this->filepath)); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
|