1 <?php
2
3 4 5
6 class rex_managed_media
7 {
8 private $media_path = '';
9 private $media;
10 private $asImage = false;
11 private $image;
12 private = [];
13 private $sourcePath;
14 private $format;
15
16 private $mimetypeMap = [
17 'image/jpeg' => 'jpg',
18 'image/jpg' => 'jpg',
19 'image/pjpeg' => 'jpg',
20 'image/vnd.wap.wbmp' => 'wbmp',
21 'image/png' => 'png',
22 'image/gif' => 'gif',
23 'image/webp' => 'webp',
24 ];
25
26 public function __construct($media_path)
27 {
28 $this->setMediaPath($media_path);
29 $this->format = strtolower(rex_file::extension($this->getMediaPath()));
30 }
31
32 33 34 35 36 37 38
39 public function getMediaPath()
40 {
41 return $this->media_path;
42 }
43
44 public function setMediaPath($media_path)
45 {
46 $this->media_path = $media_path;
47
48 if (null === $media_path) {
49 return;
50 }
51
52 $this->media = basename($media_path);
53 $this->asImage = false;
54
55 if (file_exists($media_path)) {
56 $this->sourcePath = $media_path;
57 } else {
58 $this->sourcePath = rex_path::addon('media_manager', 'media/warning.jpg');
59 }
60 }
61
62 public function getMediaFilename()
63 {
64 return $this->media;
65 }
66
67 public function setMediaFilename($filename)
68 {
69 $this->media = $filename;
70 }
71
72 public function ($type, $content)
73 {
74 $this->header[$type] = $content;
75 }
76
77 public function ()
78 {
79 return $this->header;
80 }
81
82 public function asImage()
83 {
84 if ($this->asImage) {
85 return;
86 }
87
88 $this->asImage = true;
89
90 $this->image = [];
91 $this->image['src'] = false;
92
93
94 if (class_exists('finfo') && $finfo = new finfo(FILEINFO_MIME_TYPE)) {
95 if ($ftype = @$finfo->file($this->getSourcePath())) {
96 if (array_key_exists($ftype, $this->mimetypeMap)) {
97 $this->format = $this->mimetypeMap[$ftype];
98 }
99 }
100 }
101
102 if ($this->format == 'jpg' || $this->format == 'jpeg') {
103 $this->format = 'jpeg';
104 $this->image['src'] = @imagecreatefromjpeg($this->getSourcePath());
105 } elseif ($this->format == 'gif') {
106 $this->image['src'] = @imagecreatefromgif($this->getSourcePath());
107 } elseif ($this->format == 'wbmp') {
108 $this->image['src'] = @imagecreatefromwbmp($this->getSourcePath());
109 } elseif ($this->format == 'webp') {
110 if (function_exists('imagecreatefromwebp')) {
111 $this->image['src'] = @imagecreatefromwebp($this->getSourcePath());
112 imagealphablending($this->image['src'], false);
113 imagesavealpha($this->image['src'], true);
114 }
115 } else {
116 $this->image['src'] = @imagecreatefrompng($this->getSourcePath());
117 if ($this->image['src']) {
118 imagealphablending($this->image['src'], false);
119 imagesavealpha($this->image['src'], true);
120 $this->format = 'png';
121 }
122 }
123
124 if (!$this->image['src']) {
125 $this->setSourcePath(rex_path::addon('media_manager', 'media/warning.jpg'));
126 $this->asImage();
127 } else {
128 $this->fixOrientation();
129 $this->refreshImageDimensions();
130 }
131 }
132
133 public function refreshImageDimensions()
134 {
135
136 if (!$this->asImage && 'webp' === $this->format && PHP_VERSION_ID < 70100) {
137 $this->asImage();
138 }
139
140 if ($this->asImage) {
141 $this->image['width'] = imagesx($this->image['src']);
142 $this->image['height'] = imagesy($this->image['src']);
143
144 return;
145 }
146
147 if ('jpeg' !== $this->format && !in_array($this->format, $this->mimetypeMap)) {
148 return;
149 }
150
151 $size = getimagesize($this->sourcePath);
152 $this->image['width'] = $size[0];
153 $this->image['height'] = $size[1];
154 }
155
156 public function getFormat()
157 {
158 return $this->format;
159 }
160
161 public function setFormat($format)
162 {
163 $this->format = $format;
164 }
165
166 public function sendMedia($sourceCacheFilename, $headerCacheFilename, $save = false)
167 {
168 $this->prepareHeaders();
169
170 if ($this->asImage) {
171 $src = $this->getSource();
172 $this->setHeader('Content-Length', rex_string::size($src));
173
174 rex_response::cleanOutputBuffers();
175 foreach ($this->header as $t => $c) {
176 header($t . ': ' . $c);
177 }
178
179 echo $src;
180
181 if ($save) {
182 rex_file::putCache($headerCacheFilename, [
183 'media_path' => $this->getMediaPath(),
184 'format' => $this->format,
185 'headers' => $this->header,
186 ]);
187
188 rex_file::put($sourceCacheFilename, $src);
189 }
190 } else {
191 $this->setHeader('Content-Length', filesize($this->getSourcePath()));
192
193 rex_response::cleanOutputBuffers();
194 foreach ($this->header as $t => $c) {
195 rex_response::setHeader($t, $c);
196 }
197
198 rex_response::sendFile($this->getSourcePath(), $this->header['Content-Type']);
199
200 if ($save) {
201 rex_file::putCache($headerCacheFilename, [
202 'media_path' => $this->getMediaPath(),
203 'format' => $this->format,
204 'headers' => $this->header,
205 ]);
206
207 rex_file::copy($this->getSourcePath(), $sourceCacheFilename);
208 }
209 }
210 }
211
212 public function save($sourceCacheFilename, $headerCacheFilename)
213 {
214 $src = $this->getSource();
215
216 $this->prepareHeaders($src);
217 $this->saveFiles($src, $sourceCacheFilename, $headerCacheFilename);
218 }
219
220 protected function getImageSource()
221 {
222 $addon = rex_addon::get('media_manager');
223
224 $format = $this->format;
225 $format = 'jpeg' === $format ? 'jpg' : $format;
226
227 $interlace = $this->getImageProperty('interlace', $addon->getConfig('interlace', ['jpg']));
228 imageinterlace($this->image['src'], in_array($format, $interlace) ? 1 : 0);
229
230 ob_start();
231 if ($format == 'jpg') {
232 $quality = $this->getImageProperty('jpg_quality', $addon->getConfig('jpg_quality', 85));
233 imagejpeg($this->image['src'], null, $quality);
234 } elseif ($format == 'png') {
235 $compression = $this->getImageProperty('png_compression', $addon->getConfig('png_compression', 5));
236 imagepng($this->image['src'], null, $compression);
237 } elseif ($format == 'gif') {
238 imagegif($this->image['src']);
239 } elseif ($format == 'wbmp') {
240 imagewbmp($this->image['src']);
241 } elseif ($format == 'webp') {
242 $quality = $this->getImageProperty('webp_quality', $addon->getConfig('webp_quality', 85));
243 imagewebp($this->image['src'], null, $quality);
244 }
245 return ob_get_clean();
246 }
247
248 public function getImage()
249 {
250 return $this->image['src'];
251 }
252
253 public function setImage($src)
254 {
255 $this->image['src'] = $src;
256 $this->asImage = true;
257 }
258
259 public function setSourcePath($path)
260 {
261 $this->sourcePath = $path;
262
263 $this->asImage = false;
264
265 if (isset($this->image['src']) && is_resource($this->image['src'])) {
266 imagedestroy($this->image['src']);
267 }
268 }
269
270 271 272 273 274 275 276
277 public function getSourcePath()
278 {
279 return $this->sourcePath;
280 }
281
282 283 284
285 public function getSource()
286 {
287 if ($this->asImage) {
288 return $this->getImageSource();
289 }
290
291 return rex_file::get($this->sourcePath);
292 }
293
294 public function setImageProperty($name, $value)
295 {
296 $this->image[$name] = $value;
297 }
298
299 public function getImageProperty($name, $default = null)
300 {
301 return isset($this->image[$name]) ? $this->image[$name] : $default;
302 }
303
304 public function getWidth()
305 {
306 return $this->image['width'];
307 }
308
309 public function getHeight()
310 {
311 return $this->image['height'];
312 }
313
314 315 316
317 public function getImageWidth()
318 {
319 return $this->getWidth();
320 }
321
322 323 324
325 public function getImageHeight()
326 {
327 return $this->getHeight();
328 }
329
330 private function fixOrientation()
331 {
332 if (!function_exists('exif_read_data')) {
333 return;
334 }
335
336 if (!in_array($this->getFormat(), ['jpg', 'jpeg', 'tiff'])) {
337 return;
338 }
339
340 $exif = @exif_read_data($this->getSourcePath());
341
342 if (!isset($exif['Orientation']) || !in_array($exif['Orientation'], [3, 6, 8])) {
343 return;
344 }
345
346 switch ($exif['Orientation']) {
347 case 8:
348 $this->image['src'] = imagerotate($this->image['src'], 90, 0);
349 break;
350 case 3:
351 $this->image['src'] = imagerotate($this->image['src'], 180, 0);
352 break;
353 case 6:
354 $this->image['src'] = imagerotate($this->image['src'], -90, 0);
355 break;
356 }
357 }
358
359 360 361
362 private function ($src = null)
363 {
364 if ($src !== null) {
365 $this->setHeader('Content-Length', rex_string::size($src));
366 }
367
368 $header = $this->getHeader();
369 if (!isset($header['Content-Type'])) {
370 $content_type = '';
371
372 if (!$content_type && function_exists('mime_content_type')) {
373 $content_type = mime_content_type($this->getSourcePath());
374 }
375
376 if (!$content_type && function_exists('finfo_open')) {
377 $finfo = finfo_open(FILEINFO_MIME_TYPE);
378 $content_type = finfo_file($finfo, $this->getSourcePath());
379 }
380
381
382 if ($content_type == 'text/plain') {
383 if (pathinfo($this->getSourcePath(), PATHINFO_EXTENSION) == 'css') {
384 $content_type = 'text/css';
385 } elseif (pathinfo($this->getSourcePath(), PATHINFO_EXTENSION) == 'js') {
386 $content_type = 'application/javascript';
387 }
388 }
389
390 if ($content_type != '') {
391 $this->setHeader('Content-Type', $content_type);
392 }
393 }
394 if (!isset($header['Content-Disposition'])) {
395 $this->setHeader('Content-Disposition', 'inline; filename="' . $this->getMediaFilename() . '";');
396 }
397 if (!isset($header['Last-Modified'])) {
398 $this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s T'));
399 }
400 }
401
402 403 404 405 406
407 private function saveFiles($src, $sourceCacheFilename, $headerCacheFilename)
408 {
409 rex_file::putCache($headerCacheFilename, [
410 'media_path' => $this->getMediaPath(),
411 'format' => $this->format,
412 'headers' => $this->header,
413 ]);
414
415 rex_file::put($sourceCacheFilename, $src);
416 }
417 }
418