xref: /webtrees/app/MediaFile.php (revision 5225fdfc946018075eec2860e0b84c418dea4a02)
18f5f5da8SGreg Roach<?php
28f5f5da8SGreg Roach/**
38f5f5da8SGreg Roach * webtrees: online genealogy
41062a142SGreg Roach * Copyright (C) 2018 webtrees development team
58f5f5da8SGreg Roach * This program is free software: you can redistribute it and/or modify
68f5f5da8SGreg Roach * it under the terms of the GNU General Public License as published by
78f5f5da8SGreg Roach * the Free Software Foundation, either version 3 of the License, or
88f5f5da8SGreg Roach * (at your option) any later version.
98f5f5da8SGreg Roach * This program is distributed in the hope that it will be useful,
108f5f5da8SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
118f5f5da8SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128f5f5da8SGreg Roach * GNU General Public License for more details.
138f5f5da8SGreg Roach * You should have received a copy of the GNU General Public License
148f5f5da8SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
158f5f5da8SGreg Roach */
168f5f5da8SGreg Roachnamespace Fisharebest\Webtrees;
178f5f5da8SGreg Roach
188f5f5da8SGreg Roachuse League\Glide\Urls\UrlBuilderFactory;
192361dfe8SGreg Roachuse Throwable;
208f5f5da8SGreg Roach
218f5f5da8SGreg Roach/**
228f5f5da8SGreg Roach * A GEDCOM media file.  A media object can contain many media files,
238f5f5da8SGreg Roach * such as scans of both sides of a document, the transcript of an audio
248f5f5da8SGreg Roach * recording, etc.
258f5f5da8SGreg Roach */
268f5f5da8SGreg Roachclass MediaFile {
27*5225fdfcSGreg Roach	const MIME_TYPES = [
28*5225fdfcSGreg Roach		'bmp'  => 'image/bmp',
29*5225fdfcSGreg Roach		'doc'  => 'application/msword',
30*5225fdfcSGreg Roach		'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
31*5225fdfcSGreg Roach		'ged'  => 'text/x-gedcom',
32*5225fdfcSGreg Roach		'gif'  => 'image/gif',
33*5225fdfcSGreg Roach		'html' => 'text/html',
34*5225fdfcSGreg Roach		'htm'  => 'text/html',
35*5225fdfcSGreg Roach		'jpeg' => 'image/jpeg',
36*5225fdfcSGreg Roach		'jpg'  => 'image/jpeg',
37*5225fdfcSGreg Roach		'mov'  => 'video/quicktime',
38*5225fdfcSGreg Roach		'mp3'  => 'audio/mpeg',
39*5225fdfcSGreg Roach		'mp4'  => 'video/mp4',
40*5225fdfcSGreg Roach		'ogv'  => 'video/ogg',
41*5225fdfcSGreg Roach		'pdf'  => 'application/pdf',
42*5225fdfcSGreg Roach		'png'  => 'image/png',
43*5225fdfcSGreg Roach		'rar'  => 'application/x-rar-compressed',
44*5225fdfcSGreg Roach		'swf'  => 'application/x-shockwave-flash',
45*5225fdfcSGreg Roach		'svg'  => 'image/svg',
46*5225fdfcSGreg Roach		'tiff' => 'image/tiff',
47*5225fdfcSGreg Roach		'tif'  => 'image/tiff',
48*5225fdfcSGreg Roach		'xls'  => 'application/vnd-ms-excel',
49*5225fdfcSGreg Roach		'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
50*5225fdfcSGreg Roach		'wmv'  => 'video/x-ms-wmv',
51*5225fdfcSGreg Roach		'zip'  => 'application/zip',
52*5225fdfcSGreg Roach	];
53*5225fdfcSGreg Roach
548f5f5da8SGreg Roach	/** @var string The filename */
558f5f5da8SGreg Roach	private $multimedia_file_refn = '';
568f5f5da8SGreg Roach
578f5f5da8SGreg Roach	/** @var string The file extension; jpeg, txt, mp4, etc. */
588f5f5da8SGreg Roach	private $multimedia_format = '';
598f5f5da8SGreg Roach
608f5f5da8SGreg Roach	/** @var string The type of document; newspaper, microfiche, etc. */
618f5f5da8SGreg Roach	private $source_media_type = '';
628f5f5da8SGreg Roach	/** @var string The filename */
638f5f5da8SGreg Roach
648f5f5da8SGreg Roach	/** @var string The name of the document */
658f5f5da8SGreg Roach	private $descriptive_title = '';
668f5f5da8SGreg Roach
678f5f5da8SGreg Roach	/** @var Media $media The media object to which this file belongs */
688f5f5da8SGreg Roach	private $media;
698f5f5da8SGreg Roach
7064b90bf1SGreg Roach	/** @var string */
7164b90bf1SGreg Roach	private $fact_id;
7264b90bf1SGreg Roach
738f5f5da8SGreg Roach	/**
748f5f5da8SGreg Roach	 * Create a MediaFile from raw GEDCOM data.
758f5f5da8SGreg Roach	 *
768f5f5da8SGreg Roach	 * @param string $gedcom
778f5f5da8SGreg Roach	 * @param Media  $media
788f5f5da8SGreg Roach	 */
798f5f5da8SGreg Roach	public function __construct($gedcom, Media $media) {
808f5f5da8SGreg Roach		$this->media   = $media;
8164b90bf1SGreg Roach		$this->fact_id = md5($gedcom);
828f5f5da8SGreg Roach
838f5f5da8SGreg Roach		if (preg_match('/^\d FILE (.+)/m', $gedcom, $match)) {
848f5f5da8SGreg Roach			$this->multimedia_file_refn = $match[1];
858f5f5da8SGreg Roach		}
868f5f5da8SGreg Roach
878f5f5da8SGreg Roach		if (preg_match('/^\d FORM (.+)/m', $gedcom, $match)) {
888f5f5da8SGreg Roach			$this->multimedia_format = $match[1];
898f5f5da8SGreg Roach		}
908f5f5da8SGreg Roach
918f5f5da8SGreg Roach		if (preg_match('/^\d TYPE (.+)/m', $gedcom, $match)) {
928f5f5da8SGreg Roach			$this->source_media_type = $match[1];
938f5f5da8SGreg Roach		}
948f5f5da8SGreg Roach
958f5f5da8SGreg Roach		if (preg_match('/^\d TITL (.+)/m', $gedcom, $match)) {
968f5f5da8SGreg Roach			$this->descriptive_title = $match[1];
978f5f5da8SGreg Roach		}
988f5f5da8SGreg Roach	}
998f5f5da8SGreg Roach
1008f5f5da8SGreg Roach	/**
10164b90bf1SGreg Roach	 * Get the filename.
1028f5f5da8SGreg Roach	 *
1038f5f5da8SGreg Roach	 * @return string
1048f5f5da8SGreg Roach	 */
1056e6a9947SGreg Roach	public function filename(): string {
1066e6a9947SGreg Roach		return $this->multimedia_file_refn;
1078f5f5da8SGreg Roach	}
1088f5f5da8SGreg Roach
1098f5f5da8SGreg Roach	/**
110d6641c58SGreg Roach	 * Get the base part of the filename.
111d6641c58SGreg Roach	 *
112d6641c58SGreg Roach	 * @return string
113d6641c58SGreg Roach	 */
114d6641c58SGreg Roach	public function basename(): string {
115d6641c58SGreg Roach		return basename($this->multimedia_file_refn);
116d6641c58SGreg Roach	}
117d6641c58SGreg Roach
118d6641c58SGreg Roach	/**
119d6641c58SGreg Roach	 * Get the folder part of the filename.
120d6641c58SGreg Roach	 *
121d6641c58SGreg Roach	 * @return string
122d6641c58SGreg Roach	 */
123d6641c58SGreg Roach	public function dirname(): string {
124d6641c58SGreg Roach		$dirname = dirname($this->multimedia_file_refn);
125d6641c58SGreg Roach
126d6641c58SGreg Roach		if ($dirname === '.') {
127d6641c58SGreg Roach			return '';
128d6641c58SGreg Roach		} else {
129d6641c58SGreg Roach			return $dirname;
130d6641c58SGreg Roach		}
131d6641c58SGreg Roach	}
132d6641c58SGreg Roach
133d6641c58SGreg Roach	/**
13464b90bf1SGreg Roach	 * Get the format.
1358f5f5da8SGreg Roach	 *
1368f5f5da8SGreg Roach	 * @return string
1378f5f5da8SGreg Roach	 */
1386e6a9947SGreg Roach	public function format(): string {
1398f5f5da8SGreg Roach		return $this->multimedia_format;
1408f5f5da8SGreg Roach	}
1418f5f5da8SGreg Roach
1428f5f5da8SGreg Roach	/**
14364b90bf1SGreg Roach	 * Get the type.
1448f5f5da8SGreg Roach	 *
1458f5f5da8SGreg Roach	 * @return string
1468f5f5da8SGreg Roach	 */
1476e6a9947SGreg Roach	public function type(): string {
1488f5f5da8SGreg Roach		return $this->source_media_type;
1498f5f5da8SGreg Roach	}
1508f5f5da8SGreg Roach
1518f5f5da8SGreg Roach	/**
15264b90bf1SGreg Roach	 * Get the title.
1538f5f5da8SGreg Roach	 *
1548f5f5da8SGreg Roach	 * @return string
1558f5f5da8SGreg Roach	 */
1566e6a9947SGreg Roach	public function title(): string {
1578f5f5da8SGreg Roach		return $this->descriptive_title;
1588f5f5da8SGreg Roach	}
1598f5f5da8SGreg Roach
1608f5f5da8SGreg Roach	/**
16164b90bf1SGreg Roach	 * Get the fact ID.
16264b90bf1SGreg Roach	 *
16364b90bf1SGreg Roach	 * @return string
16464b90bf1SGreg Roach	 */
16564b90bf1SGreg Roach	public function factId(): string {
16664b90bf1SGreg Roach		return $this->fact_id;
16764b90bf1SGreg Roach	}
16864b90bf1SGreg Roach
16964b90bf1SGreg Roach	/**
170d6641c58SGreg Roach	 * @return bool
171d6641c58SGreg Roach	 */
172ccf1c580SGreg Roach	public function isPendingAddition() {
173d6641c58SGreg Roach		foreach ($this->media->getFacts() as $fact) {
174d6641c58SGreg Roach			if ($fact->getFactId() === $this->fact_id) {
175d6641c58SGreg Roach				return $fact->isPendingAddition();
176d6641c58SGreg Roach			}
177d6641c58SGreg Roach		}
178d6641c58SGreg Roach
179d6641c58SGreg Roach		return false;
180d6641c58SGreg Roach	}
181d6641c58SGreg Roach
182d6641c58SGreg Roach	/**
183d6641c58SGreg Roach	 * @return bool
184d6641c58SGreg Roach	 */
185d6641c58SGreg Roach	public function isPendingDeletion() {
186d6641c58SGreg Roach		foreach ($this->media->getFacts() as $fact) {
187d6641c58SGreg Roach			if ($fact->getFactId() === $this->fact_id) {
188d6641c58SGreg Roach				return $fact->isPendingDeletion();
189d6641c58SGreg Roach			}
190d6641c58SGreg Roach		}
191d6641c58SGreg Roach
192d6641c58SGreg Roach		return false;
193d6641c58SGreg Roach	}
194d6641c58SGreg Roach
195d6641c58SGreg Roach	/**
19664b90bf1SGreg Roach	 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
19764b90bf1SGreg Roach	 *
19864b90bf1SGreg Roach	 * @param int      $width      Pixels
19964b90bf1SGreg Roach	 * @param int      $height     Pixels
20064b90bf1SGreg Roach	 * @param string   $fit        "crop" or "contain"
20164b90bf1SGreg Roach	 * @param string[] $attributes Additional HTML attributes
20264b90bf1SGreg Roach	 *
20364b90bf1SGreg Roach	 * @return string
20464b90bf1SGreg Roach	 */
20564b90bf1SGreg Roach	public function displayImage($width, $height, $fit, $attributes = []) {
20664b90bf1SGreg Roach		if ($this->isExternal()) {
20764b90bf1SGreg Roach			$src    = $this->multimedia_file_refn;
20864b90bf1SGreg Roach			$srcset = [];
20964b90bf1SGreg Roach		} else {
21064b90bf1SGreg Roach			// Generate multiple images for displays with higher pixel densities.
21164b90bf1SGreg Roach			$src    = $this->imageUrl($width, $height, $fit);
21264b90bf1SGreg Roach			$srcset = [];
21364b90bf1SGreg Roach			foreach ([2, 3, 4] as $x) {
21464b90bf1SGreg Roach				$srcset[] = $this->imageUrl($width * $x, $height * $x, $fit) . ' ' . $x . 'x';
21564b90bf1SGreg Roach			}
21664b90bf1SGreg Roach		}
21764b90bf1SGreg Roach
21864b90bf1SGreg Roach		$image = '<img ' . Html::attributes($attributes + [
21964b90bf1SGreg Roach					'dir'    => 'auto',
22064b90bf1SGreg Roach					'src'    => $src,
22164b90bf1SGreg Roach					'srcset' => implode(',', $srcset),
2225be0d03dSGreg Roach					'alt'    => htmlspecialchars_decode(strip_tags($this->media->getFullName())),
22364b90bf1SGreg Roach				]) . '>';
22464b90bf1SGreg Roach
225e1d1700bSGreg Roach		if ($this->isImage()) {
22664b90bf1SGreg Roach			$attributes = Html::attributes([
22764b90bf1SGreg Roach				'class'      => 'gallery',
22864b90bf1SGreg Roach				'type'       => $this->mimeType(),
22960e3c46aSGreg Roach				'href'       => $this->imageUrl(0, 0, 'contain'),
2305be0d03dSGreg Roach				'data-title' => htmlspecialchars_decode(strip_tags($this->media->getFullName())),
23164b90bf1SGreg Roach			]);
232e1d1700bSGreg Roach		} else {
233e1d1700bSGreg Roach			$attributes = Html::attributes([
234e1d1700bSGreg Roach				'type' => $this->mimeType(),
235e1d1700bSGreg Roach				'href' => $this->downloadUrl(),
236e1d1700bSGreg Roach			]);
237e1d1700bSGreg Roach		}
23864b90bf1SGreg Roach
23964b90bf1SGreg Roach		return '<a ' . $attributes . '>' . $image . '</a>';
24064b90bf1SGreg Roach	}
24164b90bf1SGreg Roach
2424a9f750fSGreg Roach	/**
2434a9f750fSGreg Roach	 * A list of image attributes
2444a9f750fSGreg Roach	 *
2454a9f750fSGreg Roach	 * @return string[]
2464a9f750fSGreg Roach	 */
2474a9f750fSGreg Roach	public function attributes(): array {
2484a9f750fSGreg Roach		$attributes = [];
24964b90bf1SGreg Roach
2504a9f750fSGreg Roach		if (!$this->isExternal() || $this->fileExists()) {
2514a9f750fSGreg Roach			$file = $this->folder() . $this->multimedia_file_refn;
2524a9f750fSGreg Roach
2534a9f750fSGreg Roach			$attributes['__FILE_SIZE__'] = $this->fileSizeKB();
2544a9f750fSGreg Roach
2554a9f750fSGreg Roach			$imgsize = getimagesize($file);
2564a9f750fSGreg Roach			if (is_array($imgsize) && !empty($imgsize['0'])) {
2574a9f750fSGreg Roach				$attributes['__IMAGE_SIZE__'] = I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1']));
2584a9f750fSGreg Roach			}
2594a9f750fSGreg Roach		}
2604a9f750fSGreg Roach
2614a9f750fSGreg Roach		return $attributes;
2624a9f750fSGreg Roach	}
2634a9f750fSGreg Roach
2644a9f750fSGreg Roach	/**
2654a9f750fSGreg Roach	 * check if the file exists on this server
2664a9f750fSGreg Roach	 *
2674a9f750fSGreg Roach	 * @return bool
2684a9f750fSGreg Roach	 */
2694a9f750fSGreg Roach	public function fileExists() {
270d6641c58SGreg Roach		return !$this->isExternal() && file_exists($this->folder() . $this->multimedia_file_refn);
2714a9f750fSGreg Roach	}
2724a9f750fSGreg Roach
2734a9f750fSGreg Roach	/**
2744a9f750fSGreg Roach	 * Is the media file actually a URL?
2754a9f750fSGreg Roach	 */
2764a9f750fSGreg Roach	public function isExternal(): bool {
2774a9f750fSGreg Roach		return strpos($this->multimedia_file_refn, '://') !== false;
2784a9f750fSGreg Roach	}
2794a9f750fSGreg Roach
2804a9f750fSGreg Roach	/**
2814a9f750fSGreg Roach	 * Is the media file an image?
2824a9f750fSGreg Roach	 */
2834a9f750fSGreg Roach	public function isImage(): bool {
2844a9f750fSGreg Roach		return in_array($this->extension(), ['jpeg', 'jpg', 'gif', 'png']);
2854a9f750fSGreg Roach	}
2864a9f750fSGreg Roach
2874a9f750fSGreg Roach	/**
28844379edcSGreg Roach	 * Where is the file stored on disk?
28944379edcSGreg Roach	 */
29044379edcSGreg Roach	public function folder(): string {
29144379edcSGreg Roach		return WT_DATA_DIR . $this->media->getTree()->getPreference('MEDIA_DIRECTORY');
29244379edcSGreg Roach	}
29344379edcSGreg Roach
29444379edcSGreg Roach	/**
2954a9f750fSGreg Roach	 * A user-friendly view of the file size
2964a9f750fSGreg Roach	 *
2974a9f750fSGreg Roach	 * @return int
2984a9f750fSGreg Roach	 */
2994a9f750fSGreg Roach	private function fileSizeBytes(): int {
3004a9f750fSGreg Roach		try {
3014a9f750fSGreg Roach			return filesize($this->folder() . $this->multimedia_file_refn);
3022361dfe8SGreg Roach		} catch (Throwable $ex) {
3034a9f750fSGreg Roach			DebugBar::addThrowable($ex);
3044a9f750fSGreg Roach
3054a9f750fSGreg Roach			return 0;
3064a9f750fSGreg Roach		}
3074a9f750fSGreg Roach	}
3084a9f750fSGreg Roach
3094a9f750fSGreg Roach	/**
3104a9f750fSGreg Roach	 * get the media file size in KB
3114a9f750fSGreg Roach	 *
3124a9f750fSGreg Roach	 * @return string
3134a9f750fSGreg Roach	 */
3144a9f750fSGreg Roach	public function fileSizeKB() {
3154a9f750fSGreg Roach		$size = $this->filesizeBytes();
3164a9f750fSGreg Roach		$size = (int) (($size + 1023) / 1024);
3174a9f750fSGreg Roach
3184a9f750fSGreg Roach		return /* I18N: size of file in KB */ I18N::translate('%s KB', I18N::number($size));
3194a9f750fSGreg Roach	}
32064b90bf1SGreg Roach
32164b90bf1SGreg Roach	/**
3228f5f5da8SGreg Roach	 * Get the filename on the server - for those (very few!) functions which actually
323bf7c4bf8SGreg Roach	 * need the filename, such as the PDF reports.
3248f5f5da8SGreg Roach	 *
3258f5f5da8SGreg Roach	 * @return string
3268f5f5da8SGreg Roach	 */
3278f5f5da8SGreg Roach	public function getServerFilename() {
3288f5f5da8SGreg Roach		$MEDIA_DIRECTORY = $this->media->getTree()->getPreference('MEDIA_DIRECTORY');
3298f5f5da8SGreg Roach
33064b90bf1SGreg Roach		if ($this->isExternal() || !$this->multimedia_file_refn) {
3318f5f5da8SGreg Roach			// External image, or (in the case of corrupt GEDCOM data) no image at all
33264b90bf1SGreg Roach			return $this->multimedia_file_refn;
3338f5f5da8SGreg Roach		} else {
3348f5f5da8SGreg Roach			// Main image
33564b90bf1SGreg Roach			return WT_DATA_DIR . $MEDIA_DIRECTORY . $this->multimedia_file_refn;
3368f5f5da8SGreg Roach		}
3378f5f5da8SGreg Roach	}
3388f5f5da8SGreg Roach
3398f5f5da8SGreg Roach	/**
3408f5f5da8SGreg Roach	 * get image properties
3418f5f5da8SGreg Roach	 *
3428f5f5da8SGreg Roach	 * @return array
3438f5f5da8SGreg Roach	 */
3448f5f5da8SGreg Roach	public function getImageAttributes() {
3458f5f5da8SGreg Roach		$imgsize = [];
3468f5f5da8SGreg Roach		if ($this->fileExists()) {
3478f5f5da8SGreg Roach			try {
3488f5f5da8SGreg Roach				$imgsize = getimagesize($this->getServerFilename());
3498f5f5da8SGreg Roach				if (is_array($imgsize) && !empty($imgsize['0'])) {
3508f5f5da8SGreg Roach					// this is an image
3518f5f5da8SGreg Roach					$imageTypes     = ['', 'GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF', 'TIFF', 'JPC', 'JP2', 'JPX', 'JB2', 'SWC', 'IFF', 'WBMP', 'XBM'];
3528f5f5da8SGreg Roach					$imgsize['ext'] = $imageTypes[0 + $imgsize[2]];
3538f5f5da8SGreg Roach					// this is for display purposes, always show non-adjusted info
3548f5f5da8SGreg Roach					$imgsize['WxH'] = /* I18N: image dimensions, width × height */
3558f5f5da8SGreg Roach						I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1']));
3568f5f5da8SGreg Roach				}
3572361dfe8SGreg Roach			} catch (Throwable $ex) {
3588f5f5da8SGreg Roach				DebugBar::addThrowable($ex);
3598f5f5da8SGreg Roach
3608f5f5da8SGreg Roach				// Not an image, or not a valid image?
3618f5f5da8SGreg Roach				$imgsize = false;
3628f5f5da8SGreg Roach			}
3638f5f5da8SGreg Roach		}
3648f5f5da8SGreg Roach
3658f5f5da8SGreg Roach		if (!is_array($imgsize) || empty($imgsize['0'])) {
3668f5f5da8SGreg Roach			// this is not an image, OR the file doesn’t exist OR it is a url
3678f5f5da8SGreg Roach			$imgsize[0]      = 0;
3688f5f5da8SGreg Roach			$imgsize[1]      = 0;
3698f5f5da8SGreg Roach			$imgsize['ext']  = '';
3708f5f5da8SGreg Roach			$imgsize['mime'] = '';
3718f5f5da8SGreg Roach			$imgsize['WxH']  = '';
3728f5f5da8SGreg Roach		}
3738f5f5da8SGreg Roach
3748f5f5da8SGreg Roach		if (empty($imgsize['mime'])) {
3758f5f5da8SGreg Roach			// this is not an image, OR the file doesn’t exist OR it is a url
3768f5f5da8SGreg Roach			// set file type equal to the file extension - can’t use parse_url because this may not be a full url
3774a9f750fSGreg Roach			$exp            = explode('?', $this->multimedia_file_refn);
3788f5f5da8SGreg Roach			$imgsize['ext'] = strtoupper(pathinfo($exp[0], PATHINFO_EXTENSION));
3798f5f5da8SGreg Roach			// all mimetypes we wish to serve with the media firewall must be added to this array.
3808f5f5da8SGreg Roach			$mime = [
3818f5f5da8SGreg Roach				'DOC' => 'application/msword',
3828f5f5da8SGreg Roach				'MOV' => 'video/quicktime',
3838f5f5da8SGreg Roach				'MP3' => 'audio/mpeg',
3848f5f5da8SGreg Roach				'PDF' => 'application/pdf',
3858f5f5da8SGreg Roach				'PPT' => 'application/vnd.ms-powerpoint',
3868f5f5da8SGreg Roach				'RTF' => 'text/rtf',
3878f5f5da8SGreg Roach				'SID' => 'image/x-mrsid',
3888f5f5da8SGreg Roach				'TXT' => 'text/plain',
3898f5f5da8SGreg Roach				'XLS' => 'application/vnd.ms-excel',
3908f5f5da8SGreg Roach				'WMV' => 'video/x-ms-wmv',
3918f5f5da8SGreg Roach			];
3928f5f5da8SGreg Roach			if (empty($mime[$imgsize['ext']])) {
3938f5f5da8SGreg Roach				// if we don’t know what the mimetype is, use something ambiguous
3948f5f5da8SGreg Roach				$imgsize['mime'] = 'application/octet-stream';
3958f5f5da8SGreg Roach				if ($this->fileExists()) {
3968f5f5da8SGreg Roach					// alert the admin if we cannot determine the mime type of an existing file
3978f5f5da8SGreg Roach					// as the media firewall will be unable to serve this file properly
3984a9f750fSGreg Roach					Log::addMediaLog('Media Firewall error: >Unknown Mimetype< for file >' . $this->multimedia_file_refn . '<');
3998f5f5da8SGreg Roach				}
4008f5f5da8SGreg Roach			} else {
4018f5f5da8SGreg Roach				$imgsize['mime'] = $mime[$imgsize['ext']];
4028f5f5da8SGreg Roach			}
4038f5f5da8SGreg Roach		}
4048f5f5da8SGreg Roach
4058f5f5da8SGreg Roach		return $imgsize;
4068f5f5da8SGreg Roach	}
4078f5f5da8SGreg Roach
4088f5f5da8SGreg Roach	/**
409e1d1700bSGreg Roach	 * Generate a URL to download a non-image media file.
410e1d1700bSGreg Roach	 *
411e1d1700bSGreg Roach	 * @return string
412e1d1700bSGreg Roach	 */
413e1d1700bSGreg Roach	public function downloadUrl() {
414e1d1700bSGreg Roach		return route('media-download', [
415e1d1700bSGreg Roach			'xref'    => $this->media->getXref(),
416e1d1700bSGreg Roach			'ged'     => $this->media->getTree()->getName(),
417e1d1700bSGreg Roach			'fact_id' => $this->fact_id,
418e1d1700bSGreg Roach		]);
419e1d1700bSGreg Roach	}
420e1d1700bSGreg Roach
421e1d1700bSGreg Roach	/**
4228f5f5da8SGreg Roach	 * Generate a URL for an image.
4238f5f5da8SGreg Roach	 *
4248f5f5da8SGreg Roach	 * @param int    $width  Maximum width in pixels
4258f5f5da8SGreg Roach	 * @param int    $height Maximum height in pixels
4268f5f5da8SGreg Roach	 * @param string $fit    "crop" or "contain"
4278f5f5da8SGreg Roach	 *
4288f5f5da8SGreg Roach	 * @return string
4298f5f5da8SGreg Roach	 */
4308f5f5da8SGreg Roach	public function imageUrl($width, $height, $fit) {
4318f5f5da8SGreg Roach		// Sign the URL, to protect against mass-resize attacks.
4328f5f5da8SGreg Roach		$glide_key = Site::getPreference('glide-key');
4338f5f5da8SGreg Roach		if (empty($glide_key)) {
4348f5f5da8SGreg Roach			$glide_key = bin2hex(random_bytes(128));
4358f5f5da8SGreg Roach			Site::setPreference('glide-key', $glide_key);
4368f5f5da8SGreg Roach		}
4378f5f5da8SGreg Roach
43864b90bf1SGreg Roach		if (Auth::accessLevel($this->media->getTree()) > $this->media->getTree()->getPreference('SHOW_NO_WATERMARK')) {
4398f5f5da8SGreg Roach			$mark = 'watermark.png';
4408f5f5da8SGreg Roach		} else {
4418f5f5da8SGreg Roach			$mark = '';
4428f5f5da8SGreg Roach		}
4438f5f5da8SGreg Roach
4444a9f750fSGreg Roach		$url_builder = UrlBuilderFactory::create(WT_BASE_URL, $glide_key);
4454a9f750fSGreg Roach
4464a9f750fSGreg Roach		$url = $url_builder->getUrl('index.php', [
4474a9f750fSGreg Roach			'route'     => 'media-thumbnail',
4484a9f750fSGreg Roach			'xref'      => $this->media->getXref(),
44964b90bf1SGreg Roach			'ged'       => $this->media->getTree()->getName(),
4504a9f750fSGreg Roach			'fact_id'   => $this->fact_id,
4518f5f5da8SGreg Roach			'w'         => $width,
4528f5f5da8SGreg Roach			'h'         => $height,
4538f5f5da8SGreg Roach			'fit'       => $fit,
4548f5f5da8SGreg Roach			'mark'      => $mark,
4558f5f5da8SGreg Roach			'markh'     => '100h',
4568f5f5da8SGreg Roach			'markw'     => '100w',
4578f5f5da8SGreg Roach			'markalpha' => 25,
4588f5f5da8SGreg Roach			'or'        => 0, // Intervention uses exif_read_data() which is very buggy.
4598f5f5da8SGreg Roach		]);
4608f5f5da8SGreg Roach
4618f5f5da8SGreg Roach		return $url;
4628f5f5da8SGreg Roach	}
4638f5f5da8SGreg Roach
4648f5f5da8SGreg Roach	/**
4658f5f5da8SGreg Roach	 * What file extension is used by this file?
4668f5f5da8SGreg Roach	 *
4678f5f5da8SGreg Roach	 * @return string
4688f5f5da8SGreg Roach	 */
4698f5f5da8SGreg Roach	public function extension() {
470a99c6938SGreg Roach		if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->multimedia_file_refn, $match)) {
4718f5f5da8SGreg Roach			return strtolower($match[1]);
4728f5f5da8SGreg Roach		} else {
4738f5f5da8SGreg Roach			return '';
4748f5f5da8SGreg Roach		}
4758f5f5da8SGreg Roach	}
4768f5f5da8SGreg Roach
4778f5f5da8SGreg Roach	/**
4788f5f5da8SGreg Roach	 * What is the mime-type of this object?
4798f5f5da8SGreg Roach	 * For simplicity and efficiency, use the extension, rather than the contents.
4808f5f5da8SGreg Roach	 *
4818f5f5da8SGreg Roach	 * @return string
4828f5f5da8SGreg Roach	 */
4838f5f5da8SGreg Roach	public function mimeType() {
484*5225fdfcSGreg Roach		return self::MIME_TYPES[$this->extension()] ?? 'application/octet-stream';
4858f5f5da8SGreg Roach	}
4868f5f5da8SGreg Roach}
487