1 <?php
2
3 4 5
6 class rex_media_manager
7 {
8 private $media;
9 private $originalFilename;
10 private $cache_path;
11 private $type;
12 private $use_cache;
13 private $cache;
14
15 private static $effects = [];
16
17 public function __construct(rex_managed_media $media)
18 {
19 $this->media = $media;
20 $this->originalFilename = $media->getMediaFilename();
21 $this->useCache(true);
22 }
23
24 25 26 27 28 29 30 31 32
33 public static function create($type, $file)
34 {
35 $mediaPath = rex_path::media($file);
36 $cachePath = rex_path::addonCache('media_manager');
37
38 $media = new rex_managed_media($mediaPath);
39 $manager = new self($media);
40 $manager->setCachePath($cachePath);
41 $manager->applyEffects($type);
42
43 if ($manager->use_cache && $manager->isCached()) {
44 $media->setSourcePath($manager->getCacheFilename());
45
46 $cache = $manager->getHeaderCache();
47
48 $media->setFormat($cache['format']);
49
50 foreach ($cache['headers'] as $key => $value) {
51 $media->setHeader($key, $value);
52 }
53 } elseif ($manager->use_cache) {
54 $media->save($manager->getCacheFilename(), $manager->getHeaderCacheFilename());
55 }
56
57 $media->refreshImageDimensions();
58
59 return $manager;
60 }
61
62 63 64
65 public function getMedia()
66 {
67 return $this->media;
68 }
69
70 protected function applyEffects($type)
71 {
72 $this->type = $type;
73
74 if (!$this->isCached()) {
75 $set = $this->effectsFromType($type);
76 $set = rex_extension::registerPoint(new rex_extension_point('MEDIA_MANAGER_FILTERSET', $set, ['rex_media_type' => $type]));
77
78 if (count($set) == 0) {
79 $this->use_cache = false;
80 return $this->media;
81 }
82
83
84 foreach ($set as $effect_params) {
85 $effect_class = 'rex_effect_' . $effect_params['effect'];
86
87 $effect = new $effect_class();
88 $effect->setMedia($this->media);
89 $effect->setParams($effect_params['params']);
90 $effect->execute();
91 }
92 }
93 }
94
95 public function effectsFromType($type)
96 {
97 $qry = '
98 SELECT e.*
99 FROM ' . rex::getTablePrefix() . 'media_manager_type t, ' . rex::getTablePrefix() . 'media_manager_type_effect e
100 WHERE e.type_id = t.id AND t.name=? order by e.priority';
101
102 $sql = rex_sql::factory();
103
104 $sql->setQuery($qry, [$type]);
105
106 $effects = [];
107 foreach ($sql as $row) {
108 $effname = $row->getValue('effect');
109 $params = json_decode($row->getValue('parameters'), true);
110 $effparams = [];
111
112
113 if (isset($params['rex_effect_' . $effname])) {
114 foreach ($params['rex_effect_' . $effname] as $name => $value) {
115 $effparams[str_replace('rex_effect_' . $effname . '_', '', $name)] = $value;
116 unset($effparams[$name]);
117 }
118 }
119
120 $effect = [
121 'effect' => $effname,
122 'params' => $effparams,
123 ];
124
125 $effects[] = $effect;
126 }
127
128 return $effects;
129 }
130
131 public function setCachePath($cache_path = '')
132 {
133 $this->cache_path = $cache_path;
134 }
135
136 public function getCachePath()
137 {
138 return $this->cache_path;
139 }
140
141 protected function useCache($t = true)
142 {
143 $this->use_cache = $t;
144 }
145
146 public function isCached()
147 {
148 $cache_file = $this->getCacheFilename();
149
150 if (!file_exists($cache_file)) {
151 return false;
152 }
153
154 $cache = $this->getHeaderCache();
155
156 if (!$cache) {
157 return false;
158 }
159
160 $mediapath = $cache['media_path'];
161
162 if (null === $mediapath) {
163 return true;
164 }
165
166 if (!file_exists($mediapath)) {
167 return false;
168 }
169
170 $cachetime = filemtime($cache_file);
171 $filetime = filemtime($mediapath);
172
173
174 return $cachetime > $filetime;
175 }
176
177 public function getCacheFilename()
178 {
179 return $this->cache_path.$this->type.'/'.$this->originalFilename;
180 }
181
182 public function ()
183 {
184 return $this->getCacheFilename() . '.header';
185 }
186
187 private function ()
188 {
189 if ($this->cache) {
190 return $this->cache;
191 }
192
193 return $this->cache = rex_file::getCache($this->getHeaderCacheFilename(), null);
194 }
195
196 public static function deleteCacheByType($type_id)
197 {
198 $qry = 'SELECT * FROM ' . rex::getTablePrefix() . 'media_manager_type' . ' WHERE id=?';
199 $sql = rex_sql::factory();
200
201 $sql->setQuery($qry, [$type_id]);
202 $counter = 0;
203 foreach ($sql as $row) {
204 $counter += self::deleteCache(null, $row->getValue('name'));
205 }
206
207 rex_file::delete(rex_path::addonCache('media_manager', 'types.cache'));
208
209 return $counter;
210 }
211
212 public static function deleteCache($filename = null, $type = null)
213 {
214 $filename = ($filename ?: '').'*';
215
216 if (!$type) {
217 $type = '*';
218 }
219
220 $counter = 0;
221 $folder = rex_path::addonCache('media_manager');
222
223 $glob = glob($folder.$type.'/'.$filename, GLOB_NOSORT);
224 if ($glob) {
225 foreach ($glob as $file) {
226 if (rex_file::delete($file)) {
227 ++$counter;
228 }
229 }
230 }
231
232 return $counter;
233 }
234
235 public function sendMedia()
236 {
237 rex_extension::registerPoint(new rex_extension_point('MEDIA_MANAGER_BEFORE_SEND', $this, []));
238
239 $headerCacheFilename = $this->getHeaderCacheFilename();
240 $CacheFilename = $this->getCacheFilename();
241
242 rex_response::cleanOutputBuffers();
243
244
245
246 if (rex_get('buster')) {
247 if (PHP_SESSION_ACTIVE == session_status()) {
248
249 rex_response::sendCacheControl('private, max-age=7200');
250 } else {
251 rex_response::sendCacheControl('public, max-age=31536000, immutable');
252 }
253 }
254
255
256 if (function_exists('session_abort')) {
257 session_abort();
258 } else {
259 session_write_close();
260 }
261
262 if ($this->use_cache && $this->isCached()) {
263 $header = $this->getHeaderCache()['headers'];
264 if (isset($header['Last-Modified'])) {
265 rex_response::sendLastModified(strtotime($header['Last-Modified']));
266 unset($header['Last-Modified']);
267 }
268 foreach ($header as $t => $c) {
269 rex_response::setHeader($t, $c);
270 }
271 rex_response::sendFile($CacheFilename, $header['Content-Type']);
272 } else {
273 $this->media->sendMedia($CacheFilename, $headerCacheFilename, $this->use_cache);
274 }
275
276 rex_extension::registerPoint(new rex_extension_point('MEDIA_MANAGER_AFTER_SEND', $this, []));
277
278 exit;
279 }
280
281 public static function getSupportedEffects()
282 {
283 $dirs = [
284 __DIR__ . '/effects/',
285 ];
286
287 $effects = [];
288 foreach ($dirs as $dir) {
289 $files = glob($dir . 'effect_*.php');
290 if ($files) {
291 foreach ($files as $file) {
292 $effects[self::getEffectClass($file)] = self::getEffectName($file);
293 }
294 }
295 }
296
297 foreach (self::$effects as $class) {
298 $effects[$class] = str_replace(['rex_', 'effect_'], '', $class);
299 }
300
301 return $effects;
302 }
303
304 public static function addEffect($class)
305 {
306 self::$effects[] = $class;
307 }
308
309 private static function getEffectName($effectFile)
310 {
311 return str_replace(
312 ['effect_', '.php'],
313 '',
314 basename($effectFile)
315 );
316 }
317
318 private static function getEffectClass($effectFile)
319 {
320 return 'rex_' . str_replace(
321 '.php',
322 '',
323 basename($effectFile)
324 );
325 }
326
327 328 329
330 public static function mediaUpdated(rex_extension_point $ep)
331 {
332 self::deleteCache($ep->getParam('filename'));
333 }
334
335 public static function init()
336 {
337
338 $rex_media_manager_file = self::getMediaFile();
339 $rex_media_manager_type = self::getMediaType();
340
341 if ($rex_media_manager_file != '' && $rex_media_manager_type != '') {
342 $media_path = rex_path::media($rex_media_manager_file);
343 $cache_path = rex_path::addonCache('media_manager');
344
345 $media = new rex_managed_media($media_path);
346 $media_manager = new self($media);
347 $media_manager->setCachePath($cache_path);
348 $media_manager->applyEffects($rex_media_manager_type);
349 $media_manager->sendMedia();
350
351 exit();
352 }
353 }
354
355 public static function getMediaFile()
356 {
357 $rex_media_file = rex_get('rex_media_file', 'string');
358
359
360
361 $rex_media_file = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $rex_media_file);
362 $rex_media_file = basename($rex_media_file);
363
364 return $rex_media_file;
365 }
366
367 public static function getMediaType()
368 {
369 $type = rex_get('rex_media_type', 'string');
370
371
372
373 $type = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $type);
374 $type = basename($type);
375
376 return $type;
377 }
378
379 380 381 382 383 384 385 386 387
388 public static function getUrl($type, $file, $timestamp = null, $escape = true)
389 {
390 if ($file instanceof rex_media) {
391 if (null === $timestamp) {
392 $timestamp = $file->getUpdateDate();
393 }
394
395 $file = $file->getFileName();
396 }
397
398 $params = [
399 'rex_media_type' => $type,
400 'rex_media_file' => $file,
401 ];
402
403 if (null !== $timestamp) {
404 $cache = self::getTypeCache();
405
406 if (isset($cache[$type])) {
407 $params['buster'] = max($timestamp, $cache[$type]);
408 }
409 }
410
411 if (rex::isBackend()) {
412 $url = rex_url::backendController($params, $escape);
413 } else {
414 $url = rex_url::frontendController($params, $escape);
415 }
416
417 return rex_extension::registerPoint(new rex_extension_point('MEDIA_MANAGER_URL', $url, [
418 'type' => $type,
419 'file' => $file,
420 'buster' => isset($params['buster']) ? $params['buster'] : null,
421 'escape' => $escape,
422 ]));
423 }
424
425 private static function getTypeCache()
426 {
427 $file = rex_path::addonCache('media_manager', 'types.cache');
428
429 if (null !== $cache = rex_file::getCache($file, null)) {
430 return $cache;
431 }
432
433 $cache = [];
434
435 $sql = rex_sql::factory();
436 $sql->setQuery('SELECT name, updatedate FROM '.rex::getTable('media_manager_type'));
437
438
439 foreach ($sql as $row) {
440 $cache[$row->getValue('name')] = $row->getDateTimeValue('updatedate');
441 }
442
443 rex_file::putCache($file, $cache);
444
445 return $cache;
446 }
447 }
448