Commit | Line | Data |
---|---|---|
59ab4d0f | 1 | <?php |
a9229942 | 2 | |
59ab4d0f | 3 | namespace wcf\page; |
a9229942 | 4 | |
10fdb35f | 5 | use Laminas\Diactoros\Response\EmptyResponse; |
59ab4d0f | 6 | use wcf\data\media\Media; |
76125db4 | 7 | use wcf\data\media\MediaEditor; |
59ab4d0f | 8 | use wcf\system\exception\IllegalLinkException; |
306b6bdd | 9 | use wcf\system\exception\PermissionDeniedException; |
59ab4d0f MS |
10 | use wcf\util\FileReader; |
11 | use wcf\util\StringUtil; | |
12 | ||
13 | /** | |
14 | * Shows a media file. | |
a9229942 TD |
15 | * |
16 | * @author Matthias Schmidt | |
17 | * @copyright 2001-2019 WoltLab GmbH | |
18 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
a9229942 | 19 | * @since 3.0 |
59ab4d0f | 20 | */ |
a9229942 TD |
21 | class MediaPage extends AbstractPage |
22 | { | |
23 | const AVAILABLE_DURING_OFFLINE_MODE = true; | |
24 | ||
25 | /** | |
26 | * etag for the media file | |
27 | * @var string | |
28 | */ | |
29 | public $eTag; | |
30 | ||
31 | /** | |
32 | * file reader object | |
33 | * @var FileReader | |
34 | */ | |
35 | public $fileReader; | |
36 | ||
37 | /** | |
38 | * requested media file | |
39 | * @var Media | |
40 | */ | |
41 | public $media; | |
42 | ||
43 | /** | |
44 | * id of the requested media file | |
45 | * @var int | |
46 | */ | |
47 | public $mediaID = 0; | |
48 | ||
49 | /** | |
50 | * size of the requested thumbnail | |
51 | * @var string | |
52 | */ | |
53 | public $thumbnail = ''; | |
54 | ||
55 | /** | |
56 | * @inheritDoc | |
57 | */ | |
58 | public $useTemplate = false; | |
59 | ||
60 | /** | |
61 | * list of mime types which belong to files that are displayed inline | |
62 | * @var string[] | |
63 | */ | |
64 | public static $inlineMimeTypes = [ | |
65 | 'image/gif', | |
66 | 'image/jpeg', | |
67 | 'image/png', | |
68 | 'image/x-png', | |
69 | 'application/pdf', | |
70 | 'image/pjpeg', | |
71 | 'image/webp', | |
72 | ]; | |
73 | ||
74 | /** | |
75 | * @inheritDoc | |
76 | */ | |
77 | public function readData() | |
78 | { | |
79 | parent::readData(); | |
80 | ||
81 | // get file data | |
82 | if ($this->thumbnail) { | |
83 | $mimeType = $this->media->{$this->thumbnail . 'ThumbnailType'}; | |
84 | $filesize = $this->media->{$this->thumbnail . 'ThumbnailSize'}; | |
85 | $location = $this->media->getThumbnailLocation($this->thumbnail); | |
86 | $this->eTag = \strtoupper($this->thumbnail) . '_' . $this->mediaID; | |
87 | } else { | |
88 | $mimeType = $this->media->fileType; | |
89 | $filesize = $this->media->filesize; | |
90 | $location = $this->media->getLocation(); | |
91 | $this->eTag = $this->mediaID; | |
92 | } | |
93 | ||
94 | $this->eTag .= '_' . $this->media->fileHash; | |
95 | ||
96 | // init file reader | |
97 | $maxAge = 3600; | |
98 | $this->fileReader = new FileReader($location, [ | |
99 | 'filename' => $this->media->filename, | |
100 | 'mimeType' => $mimeType, | |
101 | 'filesize' => $filesize, | |
102 | 'showInline' => \in_array($mimeType, self::$inlineMimeTypes), | |
103 | 'enableRangeSupport' => $this->thumbnail ? true : false, | |
104 | 'lastModificationTime' => $this->media->fileUpdateTime ?? $this->media->uploadTime, | |
105 | 'expirationDate' => TIME_NOW + $maxAge, | |
106 | 'maxAge' => $maxAge, | |
107 | ]); | |
108 | ||
109 | if ($this->eTag !== null) { | |
110 | $this->fileReader->addHeader('ETag', '"' . $this->eTag . '"'); | |
111 | } | |
112 | } | |
113 | ||
114 | /** | |
115 | * @inheritDoc | |
116 | */ | |
117 | public function readParameters() | |
118 | { | |
119 | parent::readParameters(); | |
120 | ||
121 | if (isset($_REQUEST['id'])) { | |
122 | $this->mediaID = \intval($_REQUEST['id']); | |
123 | } | |
124 | $this->media = new Media($this->mediaID); | |
125 | if (!$this->media->mediaID) { | |
126 | throw new IllegalLinkException(); | |
127 | } | |
128 | if (!$this->media->isAccessible()) { | |
129 | throw new PermissionDeniedException(); | |
130 | } | |
131 | ||
132 | if (isset($_REQUEST['thumbnail'])) { | |
133 | $this->thumbnail = StringUtil::trim($_REQUEST['thumbnail']); | |
134 | } | |
135 | if ($this->thumbnail === 'original') { | |
136 | // The 'original' size is required by the editor, but is not a valid thumbnail size. | |
137 | $this->thumbnail = ''; | |
138 | } | |
139 | if ($this->thumbnail && !isset(Media::getThumbnailSizes()[$this->thumbnail])) { | |
140 | throw new IllegalLinkException(); | |
141 | } | |
142 | ||
143 | if ($this->thumbnail && !$this->media->{$this->thumbnail . 'ThumbnailType'}) { | |
144 | $this->thumbnail = ''; | |
145 | } | |
146 | } | |
147 | ||
148 | /** | |
149 | * @inheritDoc | |
150 | */ | |
151 | public function show() | |
152 | { | |
153 | parent::show(); | |
154 | ||
155 | // etag caching | |
156 | if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == '"' . $this->eTag . '"') { | |
10fdb35f | 157 | return new EmptyResponse(304); |
a9229942 TD |
158 | } |
159 | ||
160 | if (!$this->thumbnail) { | |
161 | // update download count | |
162 | (new MediaEditor($this->media))->update([ | |
163 | 'downloads' => $this->media->downloads + 1, | |
164 | 'lastDownloadTime' => TIME_NOW, | |
165 | ]); | |
166 | } | |
167 | ||
168 | // send file to client | |
169 | $this->fileReader->send(); | |
170 | ||
171 | exit; | |
172 | } | |
59ab4d0f | 173 | } |