Update media implementation
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / page / MediaPage.class.php
1 <?php
2 namespace wcf\page;
3 use wcf\data\article\Article;
4 use wcf\data\box\Box;
5 use wcf\data\media\Media;
6 use wcf\data\IMessage;
7 use wcf\system\box\BoxHandler;
8 use wcf\system\event\EventHandler;
9 use wcf\system\exception\IllegalLinkException;
10 use wcf\system\exception\PermissionDeniedException;
11 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
12 use wcf\system\WCF;
13 use wcf\util\FileReader;
14 use wcf\util\StringUtil;
15
16 /**
17 * Shows a media file.
18 *
19 * @author Matthias Schmidt
20 * @copyright 2001-2016 WoltLab GmbH
21 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
22 * @package WoltLabSuite\Core\Page
23 * @since 3.0
24 */
25 class MediaPage extends AbstractPage {
26 /**
27 * article which uses the media file as the main article image
28 * @var Article|null
29 */
30 public $article;
31
32 /**
33 * id of the article which uses the media file as the main article image
34 * @var integer
35 */
36 public $articleID = 0;
37
38 /**
39 * box which uses the media file as box image
40 * @var Box
41 */
42 public $box;
43
44 /**
45 * id of the box which uses the media file as box image
46 * @var integer
47 */
48 public $boxID = 0;
49
50 /**
51 * etag for the media file
52 * @var string
53 */
54 public $eTag;
55
56 /**
57 * file reader object
58 * @var FileReader
59 */
60 public $fileReader;
61
62 /**
63 * requested media file
64 * @var Media
65 */
66 public $media;
67
68 /**
69 * message in which the media is embedded
70 * @var IMessage
71 */
72 public $message;
73
74 /**
75 * id of the message in which the media is embedded
76 * @var integer
77 */
78 public $messageID = 0;
79
80 /**
81 * name of the object type of the message in which the media is embedded
82 * @var string
83 */
84 public $messageObjectType = '';
85
86 /**
87 * id of the requested media file
88 * @var integer
89 */
90 public $mediaID = 0;
91
92 /**
93 * size of the requested thumbnail
94 * @var string
95 */
96 public $thumbnail = '';
97
98 /**
99 * @inheritDoc
100 */
101 public $useTemplate = false;
102
103 /**
104 * list of mime types which belong to files that are displayed inline
105 * @var string[]
106 */
107 public static $inlineMimeTypes = [
108 'image/gif',
109 'image/jpeg',
110 'image/png',
111 'image/x-png',
112 'application/pdf',
113 'image/pjpeg'
114 ];
115
116 /**
117 * @inheritDoc
118 */
119 public function checkPermissions() {
120 parent::checkPermissions();
121
122 if (!WCF::getSession()->getPermission('admin.content.cms.canManageMedia')) {
123 if ($this->articleID) {
124 $this->article = new Article($this->articleID);
125
126 if (!$this->article->articleID || !$this->article->canRead()) {
127 throw new PermissionDeniedException();
128 }
129 }
130 else if ($this->boxID) {
131 $this->box = BoxHandler::getInstance()->getBox($this->boxID);
132
133 if ($this->box === null || !$this->box->isAccessible()) {
134 throw new PermissionDeniedException();
135 }
136 }
137 else if ($this->messageID) {
138 MessageEmbeddedObjectManager::getInstance()->loadObjects($this->messageObjectType, [$this->messageID]);
139 $this->message = MessageEmbeddedObjectManager::getInstance()->getObject($this->messageObjectType, $this->messageID);
140 if ($this->message === null || !($this->message instanceof IMessage) || !$this->message->isVisible()) {
141 throw new PermissionDeniedException();
142 }
143 }
144 else {
145 $parameters = ['canAccess' => false];
146
147 EventHandler::getInstance()->fireAction($this, 'checkMediaAccess', $parameters);
148
149 if (empty($parameters['canAccess'])) {
150 throw new PermissionDeniedException();
151 }
152 }
153 }
154 }
155
156 /**
157 * @inheritDoc
158 */
159 public function readData() {
160 parent::readData();
161
162 // get file data
163 if ($this->thumbnail) {
164 $mimeType = $this->media->{$this->thumbnail.'ThumbnailType'};
165 $filesize = $this->media->{$this->thumbnail.'ThumbnailSize'};
166 $location = $this->media->getThumbnailLocation($this->thumbnail);
167 $this->eTag = strtoupper($this->thumbnail).'_'.$this->mediaID;
168 }
169 else {
170 $mimeType = $this->media->fileType;
171 $filesize = $this->media->filesize;
172 $location = $this->media->getLocation();
173 $this->eTag = $this->mediaID;
174 }
175
176 // init file reader
177 $this->fileReader = new FileReader($location, [
178 'filename' => $this->media->filename,
179 'mimeType' => $mimeType,
180 'filesize' => $filesize,
181 'showInline' => (in_array($mimeType, self::$inlineMimeTypes)),
182 'enableRangeSupport' => ($this->thumbnail ? true : false),
183 'lastModificationTime' => $this->media->uploadTime,
184 'expirationDate' => TIME_NOW + 31536000,
185 'maxAge' => 31536000
186 ]);
187
188 if ($this->eTag !== null) {
189 $this->fileReader->addHeader('ETag', '"'.$this->eTag.'"');
190 }
191 }
192
193 /**
194 * @inheritDoc
195 */
196 public function readParameters() {
197 parent::readParameters();
198
199 if (isset($_REQUEST['id'])) $this->mediaID = intval($_REQUEST['id']);
200 $this->media = new Media($this->mediaID);
201 if (!$this->media->mediaID) {
202 throw new IllegalLinkException();
203 }
204
205 if (isset($_REQUEST['thumbnail'])) $this->thumbnail = StringUtil::trim($_REQUEST['thumbnail']);
206 if ($this->thumbnail && !isset(Media::getThumbnailSizes()[$this->thumbnail])) {
207 throw new IllegalLinkException();
208 }
209
210 if ($this->thumbnail && !$this->media->{$this->thumbnail.'ThumbnailType'}) {
211 $this->thumbnail = '';
212 }
213
214 // read context parameters
215 if (isset($_REQUEST['articleID'])) {
216 $this->articleID = intval($_REQUEST['articleID']);
217 }
218 else if (isset($_REQUEST['boxID'])) {
219 $this->boxID = intval($_REQUEST['boxID']);
220 }
221 else if (isset($_REQUEST['messageObjectType']) && isset($_REQUEST['messageID'])) {
222 $this->messageObjectType = StringUtil::trim($_REQUEST['messageObjectType']);
223 $this->messageID = intval($_REQUEST['messageID']);
224 }
225 }
226
227 /**
228 * @inheritDoc
229 */
230 public function show() {
231 parent::show();
232
233 // etag caching
234 if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == '"'.$this->eTag.'"') {
235 @header('HTTP/1.1 304 Not Modified');
236 exit;
237 }
238
239 // send file to client
240 $this->fileReader->send();
241 exit;
242 }
243 }