18f5f5da8SGreg Roach<?php 28f5f5da8SGreg Roach/** 38f5f5da8SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 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 */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 188f5f5da8SGreg Roachnamespace Fisharebest\Webtrees; 198f5f5da8SGreg Roach 208f5f5da8SGreg Roachuse League\Glide\Urls\UrlBuilderFactory; 21*9b93b7c3SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 222361dfe8SGreg Roachuse Throwable; 23*9b93b7c3SGreg Roachuse function app; 248f5f5da8SGreg Roach 258f5f5da8SGreg Roach/** 268f5f5da8SGreg Roach * A GEDCOM media file. A media object can contain many media files, 278f5f5da8SGreg Roach * such as scans of both sides of a document, the transcript of an audio 288f5f5da8SGreg Roach * recording, etc. 298f5f5da8SGreg Roach */ 30c1010edaSGreg Roachclass MediaFile 31c1010edaSGreg Roach{ 3216d6367aSGreg Roach private const MIME_TYPES = [ 335225fdfcSGreg Roach 'bmp' => 'image/bmp', 345225fdfcSGreg Roach 'doc' => 'application/msword', 355225fdfcSGreg Roach 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 365225fdfcSGreg Roach 'ged' => 'text/x-gedcom', 375225fdfcSGreg Roach 'gif' => 'image/gif', 385225fdfcSGreg Roach 'html' => 'text/html', 395225fdfcSGreg Roach 'htm' => 'text/html', 405225fdfcSGreg Roach 'jpeg' => 'image/jpeg', 415225fdfcSGreg Roach 'jpg' => 'image/jpeg', 425225fdfcSGreg Roach 'mov' => 'video/quicktime', 435225fdfcSGreg Roach 'mp3' => 'audio/mpeg', 445225fdfcSGreg Roach 'mp4' => 'video/mp4', 455225fdfcSGreg Roach 'ogv' => 'video/ogg', 465225fdfcSGreg Roach 'pdf' => 'application/pdf', 475225fdfcSGreg Roach 'png' => 'image/png', 485225fdfcSGreg Roach 'rar' => 'application/x-rar-compressed', 495225fdfcSGreg Roach 'swf' => 'application/x-shockwave-flash', 505225fdfcSGreg Roach 'svg' => 'image/svg', 515225fdfcSGreg Roach 'tiff' => 'image/tiff', 525225fdfcSGreg Roach 'tif' => 'image/tiff', 535225fdfcSGreg Roach 'xls' => 'application/vnd-ms-excel', 545225fdfcSGreg Roach 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 555225fdfcSGreg Roach 'wmv' => 'video/x-ms-wmv', 565225fdfcSGreg Roach 'zip' => 'application/zip', 575225fdfcSGreg Roach ]; 585225fdfcSGreg Roach 598f5f5da8SGreg Roach /** @var string The filename */ 608f5f5da8SGreg Roach private $multimedia_file_refn = ''; 618f5f5da8SGreg Roach 628f5f5da8SGreg Roach /** @var string The file extension; jpeg, txt, mp4, etc. */ 638f5f5da8SGreg Roach private $multimedia_format = ''; 648f5f5da8SGreg Roach 658f5f5da8SGreg Roach /** @var string The type of document; newspaper, microfiche, etc. */ 668f5f5da8SGreg Roach private $source_media_type = ''; 678f5f5da8SGreg Roach /** @var string The filename */ 688f5f5da8SGreg Roach 698f5f5da8SGreg Roach /** @var string The name of the document */ 708f5f5da8SGreg Roach private $descriptive_title = ''; 718f5f5da8SGreg Roach 728f5f5da8SGreg Roach /** @var Media $media The media object to which this file belongs */ 738f5f5da8SGreg Roach private $media; 748f5f5da8SGreg Roach 7564b90bf1SGreg Roach /** @var string */ 7664b90bf1SGreg Roach private $fact_id; 7764b90bf1SGreg Roach 788f5f5da8SGreg Roach /** 798f5f5da8SGreg Roach * Create a MediaFile from raw GEDCOM data. 808f5f5da8SGreg Roach * 818f5f5da8SGreg Roach * @param string $gedcom 828f5f5da8SGreg Roach * @param Media $media 838f5f5da8SGreg Roach */ 84c1010edaSGreg Roach public function __construct($gedcom, Media $media) 85c1010edaSGreg Roach { 868f5f5da8SGreg Roach $this->media = $media; 8764b90bf1SGreg Roach $this->fact_id = md5($gedcom); 888f5f5da8SGreg Roach 898f5f5da8SGreg Roach if (preg_match('/^\d FILE (.+)/m', $gedcom, $match)) { 908f5f5da8SGreg Roach $this->multimedia_file_refn = $match[1]; 91423c6ccdSGreg Roach $this->multimedia_format = pathinfo($match[1], PATHINFO_EXTENSION); 928f5f5da8SGreg Roach } 938f5f5da8SGreg Roach 948f5f5da8SGreg Roach if (preg_match('/^\d FORM (.+)/m', $gedcom, $match)) { 958f5f5da8SGreg Roach $this->multimedia_format = $match[1]; 968f5f5da8SGreg Roach } 978f5f5da8SGreg Roach 988f5f5da8SGreg Roach if (preg_match('/^\d TYPE (.+)/m', $gedcom, $match)) { 998f5f5da8SGreg Roach $this->source_media_type = $match[1]; 1008f5f5da8SGreg Roach } 1018f5f5da8SGreg Roach 1028f5f5da8SGreg Roach if (preg_match('/^\d TITL (.+)/m', $gedcom, $match)) { 1038f5f5da8SGreg Roach $this->descriptive_title = $match[1]; 1048f5f5da8SGreg Roach } 1058f5f5da8SGreg Roach } 1068f5f5da8SGreg Roach 1078f5f5da8SGreg Roach /** 10864b90bf1SGreg Roach * Get the filename. 1098f5f5da8SGreg Roach * 1108f5f5da8SGreg Roach * @return string 1118f5f5da8SGreg Roach */ 112c1010edaSGreg Roach public function filename(): string 113c1010edaSGreg Roach { 1146e6a9947SGreg Roach return $this->multimedia_file_refn; 1158f5f5da8SGreg Roach } 1168f5f5da8SGreg Roach 1178f5f5da8SGreg Roach /** 118d6641c58SGreg Roach * Get the base part of the filename. 119d6641c58SGreg Roach * 120d6641c58SGreg Roach * @return string 121d6641c58SGreg Roach */ 122c1010edaSGreg Roach public function basename(): string 123c1010edaSGreg Roach { 124d6641c58SGreg Roach return basename($this->multimedia_file_refn); 125d6641c58SGreg Roach } 126d6641c58SGreg Roach 127d6641c58SGreg Roach /** 128d6641c58SGreg Roach * Get the folder part of the filename. 129d6641c58SGreg Roach * 130d6641c58SGreg Roach * @return string 131d6641c58SGreg Roach */ 132c1010edaSGreg Roach public function dirname(): string 133c1010edaSGreg Roach { 134d6641c58SGreg Roach $dirname = dirname($this->multimedia_file_refn); 135d6641c58SGreg Roach 136d6641c58SGreg Roach if ($dirname === '.') { 137d6641c58SGreg Roach return ''; 138d6641c58SGreg Roach } 139b2ce94c6SRico Sonntag 140b2ce94c6SRico Sonntag return $dirname; 141d6641c58SGreg Roach } 142d6641c58SGreg Roach 143d6641c58SGreg Roach /** 14464b90bf1SGreg Roach * Get the format. 1458f5f5da8SGreg Roach * 1468f5f5da8SGreg Roach * @return string 1478f5f5da8SGreg Roach */ 148c1010edaSGreg Roach public function format(): string 149c1010edaSGreg Roach { 1508f5f5da8SGreg Roach return $this->multimedia_format; 1518f5f5da8SGreg Roach } 1528f5f5da8SGreg Roach 1538f5f5da8SGreg Roach /** 15464b90bf1SGreg Roach * Get the type. 1558f5f5da8SGreg Roach * 1568f5f5da8SGreg Roach * @return string 1578f5f5da8SGreg Roach */ 158c1010edaSGreg Roach public function type(): string 159c1010edaSGreg Roach { 1608f5f5da8SGreg Roach return $this->source_media_type; 1618f5f5da8SGreg Roach } 1628f5f5da8SGreg Roach 1638f5f5da8SGreg Roach /** 16464b90bf1SGreg Roach * Get the title. 1658f5f5da8SGreg Roach * 1668f5f5da8SGreg Roach * @return string 1678f5f5da8SGreg Roach */ 168c1010edaSGreg Roach public function title(): string 169c1010edaSGreg Roach { 1708f5f5da8SGreg Roach return $this->descriptive_title; 1718f5f5da8SGreg Roach } 1728f5f5da8SGreg Roach 1738f5f5da8SGreg Roach /** 17464b90bf1SGreg Roach * Get the fact ID. 17564b90bf1SGreg Roach * 17664b90bf1SGreg Roach * @return string 17764b90bf1SGreg Roach */ 178c1010edaSGreg Roach public function factId(): string 179c1010edaSGreg Roach { 18064b90bf1SGreg Roach return $this->fact_id; 18164b90bf1SGreg Roach } 18264b90bf1SGreg Roach 18364b90bf1SGreg Roach /** 184d6641c58SGreg Roach * @return bool 185d6641c58SGreg Roach */ 1868f53f488SRico Sonntag public function isPendingAddition(): bool 187c1010edaSGreg Roach { 18830158ae7SGreg Roach foreach ($this->media->facts() as $fact) { 189905ab80aSGreg Roach if ($fact->id() === $this->fact_id) { 190d6641c58SGreg Roach return $fact->isPendingAddition(); 191d6641c58SGreg Roach } 192d6641c58SGreg Roach } 193d6641c58SGreg Roach 194d6641c58SGreg Roach return false; 195d6641c58SGreg Roach } 196d6641c58SGreg Roach 197d6641c58SGreg Roach /** 198d6641c58SGreg Roach * @return bool 199d6641c58SGreg Roach */ 2008f53f488SRico Sonntag public function isPendingDeletion(): bool 201c1010edaSGreg Roach { 20230158ae7SGreg Roach foreach ($this->media->facts() as $fact) { 203905ab80aSGreg Roach if ($fact->id() === $this->fact_id) { 204d6641c58SGreg Roach return $fact->isPendingDeletion(); 205d6641c58SGreg Roach } 206d6641c58SGreg Roach } 207d6641c58SGreg Roach 208d6641c58SGreg Roach return false; 209d6641c58SGreg Roach } 210d6641c58SGreg Roach 211d6641c58SGreg Roach /** 21264b90bf1SGreg Roach * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox. 21364b90bf1SGreg Roach * 21464b90bf1SGreg Roach * @param int $width Pixels 21564b90bf1SGreg Roach * @param int $height Pixels 21664b90bf1SGreg Roach * @param string $fit "crop" or "contain" 217e364afe4SGreg Roach * @param string[] $image_attributes Additional HTML attributes 21864b90bf1SGreg Roach * 21964b90bf1SGreg Roach * @return string 22064b90bf1SGreg Roach */ 221e364afe4SGreg Roach public function displayImage($width, $height, $fit, $image_attributes = []): string 222c1010edaSGreg Roach { 22364b90bf1SGreg Roach if ($this->isExternal()) { 22464b90bf1SGreg Roach $src = $this->multimedia_file_refn; 22564b90bf1SGreg Roach $srcset = []; 22664b90bf1SGreg Roach } else { 22764b90bf1SGreg Roach // Generate multiple images for displays with higher pixel densities. 22864b90bf1SGreg Roach $src = $this->imageUrl($width, $height, $fit); 22964b90bf1SGreg Roach $srcset = []; 230bb308685SGreg Roach foreach ([2, 3, 4] as $x) { 23164b90bf1SGreg Roach $srcset[] = $this->imageUrl($width * $x, $height * $x, $fit) . ' ' . $x . 'x'; 23264b90bf1SGreg Roach } 23364b90bf1SGreg Roach } 23464b90bf1SGreg Roach 23548b53306SGreg Roach if ($this->isImage()) { 236e364afe4SGreg Roach $image = '<img ' . Html::attributes($image_attributes + [ 23764b90bf1SGreg Roach 'dir' => 'auto', 23864b90bf1SGreg Roach 'src' => $src, 23964b90bf1SGreg Roach 'srcset' => implode(',', $srcset), 24039ca88baSGreg Roach 'alt' => htmlspecialchars_decode(strip_tags($this->media->fullName())), 24164b90bf1SGreg Roach ]) . '>'; 24264b90bf1SGreg Roach 243e364afe4SGreg Roach $link_attributes = Html::attributes([ 24464b90bf1SGreg Roach 'class' => 'gallery', 24564b90bf1SGreg Roach 'type' => $this->mimeType(), 24660e3c46aSGreg Roach 'href' => $this->imageUrl(0, 0, 'contain'), 24739ca88baSGreg Roach 'data-title' => htmlspecialchars_decode(strip_tags($this->media->fullName())), 24864b90bf1SGreg Roach ]); 249e1d1700bSGreg Roach } else { 25048b53306SGreg Roach $image = view('icons/mime', ['type' => $this->mimeType()]); 251e364afe4SGreg Roach 252e364afe4SGreg Roach $link_attributes = Html::attributes([ 253e1d1700bSGreg Roach 'type' => $this->mimeType(), 254e1d1700bSGreg Roach 'href' => $this->downloadUrl(), 255e1d1700bSGreg Roach ]); 256e1d1700bSGreg Roach } 25764b90bf1SGreg Roach 258e364afe4SGreg Roach return '<a ' . $link_attributes . '>' . $image . '</a>'; 25964b90bf1SGreg Roach } 26064b90bf1SGreg Roach 2614a9f750fSGreg Roach /** 2624a9f750fSGreg Roach * A list of image attributes 2634a9f750fSGreg Roach * 2644a9f750fSGreg Roach * @return string[] 2654a9f750fSGreg Roach */ 266c1010edaSGreg Roach public function attributes(): array 267c1010edaSGreg Roach { 2684a9f750fSGreg Roach $attributes = []; 26964b90bf1SGreg Roach 2704a9f750fSGreg Roach if (!$this->isExternal() || $this->fileExists()) { 2714a9f750fSGreg Roach $file = $this->folder() . $this->multimedia_file_refn; 2724a9f750fSGreg Roach 2734a9f750fSGreg Roach $attributes['__FILE_SIZE__'] = $this->fileSizeKB(); 2744a9f750fSGreg Roach 2754a9f750fSGreg Roach $imgsize = getimagesize($file); 2764a9f750fSGreg Roach if (is_array($imgsize) && !empty($imgsize['0'])) { 2774a9f750fSGreg Roach $attributes['__IMAGE_SIZE__'] = I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1'])); 2784a9f750fSGreg Roach } 2794a9f750fSGreg Roach } 2804a9f750fSGreg Roach 2814a9f750fSGreg Roach return $attributes; 2824a9f750fSGreg Roach } 2834a9f750fSGreg Roach 2844a9f750fSGreg Roach /** 2854a9f750fSGreg Roach * check if the file exists on this server 2864a9f750fSGreg Roach * 2874a9f750fSGreg Roach * @return bool 2884a9f750fSGreg Roach */ 2898f53f488SRico Sonntag public function fileExists(): bool 290c1010edaSGreg Roach { 291d6641c58SGreg Roach return !$this->isExternal() && file_exists($this->folder() . $this->multimedia_file_refn); 2924a9f750fSGreg Roach } 2934a9f750fSGreg Roach 2944a9f750fSGreg Roach /** 2954a9f750fSGreg Roach * Is the media file actually a URL? 2964a9f750fSGreg Roach */ 297c1010edaSGreg Roach public function isExternal(): bool 298c1010edaSGreg Roach { 2994a9f750fSGreg Roach return strpos($this->multimedia_file_refn, '://') !== false; 3004a9f750fSGreg Roach } 3014a9f750fSGreg Roach 3024a9f750fSGreg Roach /** 3034a9f750fSGreg Roach * Is the media file an image? 3044a9f750fSGreg Roach */ 305c1010edaSGreg Roach public function isImage(): bool 306c1010edaSGreg Roach { 307c1010edaSGreg Roach return in_array($this->extension(), [ 308c1010edaSGreg Roach 'jpeg', 309c1010edaSGreg Roach 'jpg', 310c1010edaSGreg Roach 'gif', 311c1010edaSGreg Roach 'png', 312c1010edaSGreg Roach ]); 3134a9f750fSGreg Roach } 3144a9f750fSGreg Roach 3154a9f750fSGreg Roach /** 31644379edcSGreg Roach * Where is the file stored on disk? 31744379edcSGreg Roach */ 318c1010edaSGreg Roach public function folder(): string 319c1010edaSGreg Roach { 320f4afa648SGreg Roach return WT_DATA_DIR . $this->media->tree()->getPreference('MEDIA_DIRECTORY'); 32144379edcSGreg Roach } 32244379edcSGreg Roach 32344379edcSGreg Roach /** 3244a9f750fSGreg Roach * A user-friendly view of the file size 3254a9f750fSGreg Roach * 3264a9f750fSGreg Roach * @return int 3274a9f750fSGreg Roach */ 328c1010edaSGreg Roach private function fileSizeBytes(): int 329c1010edaSGreg Roach { 3304a9f750fSGreg Roach try { 3314a9f750fSGreg Roach return filesize($this->folder() . $this->multimedia_file_refn); 3322361dfe8SGreg Roach } catch (Throwable $ex) { 3334a9f750fSGreg Roach return 0; 3344a9f750fSGreg Roach } 3354a9f750fSGreg Roach } 3364a9f750fSGreg Roach 3374a9f750fSGreg Roach /** 3384a9f750fSGreg Roach * get the media file size in KB 3394a9f750fSGreg Roach * 3404a9f750fSGreg Roach * @return string 3414a9f750fSGreg Roach */ 3428f53f488SRico Sonntag public function fileSizeKB(): string 343c1010edaSGreg Roach { 344b0b72ea4SGreg Roach $size = $this->fileSizeBytes(); 345cdaafeeeSGreg Roach $size = intdiv($size + 1023, 1024); 3464a9f750fSGreg Roach 347bbb76c12SGreg Roach /* I18N: size of file in KB */ 348bbb76c12SGreg Roach return I18N::translate('%s KB', I18N::number($size)); 3494a9f750fSGreg Roach } 35064b90bf1SGreg Roach 35164b90bf1SGreg Roach /** 3528f5f5da8SGreg Roach * Get the filename on the server - for those (very few!) functions which actually 353bf7c4bf8SGreg Roach * need the filename, such as the PDF reports. 3548f5f5da8SGreg Roach * 3558f5f5da8SGreg Roach * @return string 3568f5f5da8SGreg Roach */ 357e364afe4SGreg Roach public function getServerFilename(): string 358c1010edaSGreg Roach { 359f4afa648SGreg Roach $MEDIA_DIRECTORY = $this->media->tree()->getPreference('MEDIA_DIRECTORY'); 3608f5f5da8SGreg Roach 361bb308685SGreg Roach if ($this->multimedia_file_refn === '' || $this->isExternal()) { 3628f5f5da8SGreg Roach // External image, or (in the case of corrupt GEDCOM data) no image at all 36364b90bf1SGreg Roach return $this->multimedia_file_refn; 364b2ce94c6SRico Sonntag } 365b2ce94c6SRico Sonntag 3668f5f5da8SGreg Roach // Main image 36764b90bf1SGreg Roach return WT_DATA_DIR . $MEDIA_DIRECTORY . $this->multimedia_file_refn; 3688f5f5da8SGreg Roach } 3698f5f5da8SGreg Roach 3708f5f5da8SGreg Roach /** 371e1d1700bSGreg Roach * Generate a URL to download a non-image media file. 372e1d1700bSGreg Roach * 373e1d1700bSGreg Roach * @return string 374e1d1700bSGreg Roach */ 3758f53f488SRico Sonntag public function downloadUrl(): string 376c1010edaSGreg Roach { 377e1d1700bSGreg Roach return route('media-download', [ 378c0935879SGreg Roach 'xref' => $this->media->xref(), 379f4afa648SGreg Roach 'ged' => $this->media->tree()->name(), 380e1d1700bSGreg Roach 'fact_id' => $this->fact_id, 381e1d1700bSGreg Roach ]); 382e1d1700bSGreg Roach } 383e1d1700bSGreg Roach 384e1d1700bSGreg Roach /** 3858f5f5da8SGreg Roach * Generate a URL for an image. 3868f5f5da8SGreg Roach * 3878f5f5da8SGreg Roach * @param int $width Maximum width in pixels 3888f5f5da8SGreg Roach * @param int $height Maximum height in pixels 3898f5f5da8SGreg Roach * @param string $fit "crop" or "contain" 3908f5f5da8SGreg Roach * 3918f5f5da8SGreg Roach * @return string 3928f5f5da8SGreg Roach */ 3938f53f488SRico Sonntag public function imageUrl($width, $height, $fit): string 394c1010edaSGreg Roach { 3958f5f5da8SGreg Roach // Sign the URL, to protect against mass-resize attacks. 3968f5f5da8SGreg Roach $glide_key = Site::getPreference('glide-key'); 3978f5f5da8SGreg Roach if (empty($glide_key)) { 3988f5f5da8SGreg Roach $glide_key = bin2hex(random_bytes(128)); 3998f5f5da8SGreg Roach Site::setPreference('glide-key', $glide_key); 4008f5f5da8SGreg Roach } 4018f5f5da8SGreg Roach 402f4afa648SGreg Roach if (Auth::accessLevel($this->media->tree()) > $this->media->tree()->getPreference('SHOW_NO_WATERMARK')) { 4038f5f5da8SGreg Roach $mark = 'watermark.png'; 4048f5f5da8SGreg Roach } else { 4058f5f5da8SGreg Roach $mark = ''; 4068f5f5da8SGreg Roach } 4078f5f5da8SGreg Roach 408*9b93b7c3SGreg Roach $base_url = app(ServerRequestInterface::class)->getAttribute('base_url'); 409*9b93b7c3SGreg Roach 410*9b93b7c3SGreg Roach $url_builder = UrlBuilderFactory::create($base_url, $glide_key); 4114a9f750fSGreg Roach 4124a9f750fSGreg Roach $url = $url_builder->getUrl('index.php', [ 4134a9f750fSGreg Roach 'route' => 'media-thumbnail', 414c0935879SGreg Roach 'xref' => $this->media->xref(), 415f4afa648SGreg Roach 'ged' => $this->media->tree()->name(), 4164a9f750fSGreg Roach 'fact_id' => $this->fact_id, 4178f5f5da8SGreg Roach 'w' => $width, 4188f5f5da8SGreg Roach 'h' => $height, 4198f5f5da8SGreg Roach 'fit' => $fit, 4208f5f5da8SGreg Roach 'mark' => $mark, 4218f5f5da8SGreg Roach 'markh' => '100h', 4228f5f5da8SGreg Roach 'markw' => '100w', 4238f5f5da8SGreg Roach 'markalpha' => 25, 424c1010edaSGreg Roach 'or' => 0, 425c1010edaSGreg Roach // Intervention uses exif_read_data() which is very buggy. 4268f5f5da8SGreg Roach ]); 4278f5f5da8SGreg Roach 4288f5f5da8SGreg Roach return $url; 4298f5f5da8SGreg Roach } 4308f5f5da8SGreg Roach 4318f5f5da8SGreg Roach /** 4328f5f5da8SGreg Roach * What file extension is used by this file? 4338f5f5da8SGreg Roach * 4348f5f5da8SGreg Roach * @return string 4358f5f5da8SGreg Roach */ 436e364afe4SGreg Roach public function extension(): string 437c1010edaSGreg Roach { 438a99c6938SGreg Roach if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->multimedia_file_refn, $match)) { 4398f5f5da8SGreg Roach return strtolower($match[1]); 4408f5f5da8SGreg Roach } 441b2ce94c6SRico Sonntag 442b2ce94c6SRico Sonntag return ''; 4438f5f5da8SGreg Roach } 4448f5f5da8SGreg Roach 4458f5f5da8SGreg Roach /** 4468f5f5da8SGreg Roach * What is the mime-type of this object? 4478f5f5da8SGreg Roach * For simplicity and efficiency, use the extension, rather than the contents. 4488f5f5da8SGreg Roach * 4498f5f5da8SGreg Roach * @return string 4508f5f5da8SGreg Roach */ 4518f53f488SRico Sonntag public function mimeType(): string 452c1010edaSGreg Roach { 4535225fdfcSGreg Roach return self::MIME_TYPES[$this->extension()] ?? 'application/octet-stream'; 4548f5f5da8SGreg Roach } 4558f5f5da8SGreg Roach} 456