From 984c9702eccf5ffa3afee584903885adc8ee35da Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sun, 14 Jun 2020 11:05:55 -0500 Subject: [PATCH] The great MIMEing --- core/basepage.php | 9 +- core/basethemelet.php | 5 +- core/extension.php | 67 +++-- core/filetypes.php | 448 ----------------------------- core/imageboard/event.php | 6 +- core/imageboard/image.php | 50 ++-- core/imageboard/misc.php | 15 +- core/polyfills.php | 3 - ext/admin/main.php | 2 +- ext/alias_editor/main.php | 2 +- ext/auto_tagger/main.php | 2 +- ext/autocomplete/main.php | 2 +- ext/browser_search/main.php | 2 +- ext/bulk_import_export/main.php | 4 +- ext/cron_uploader/main.php | 2 +- ext/danbooru_api/main.php | 6 +- ext/download/main.php | 2 +- ext/et/main.php | 4 +- ext/featured/main.php | 2 +- ext/handle_archive/main.php | 4 +- ext/handle_cbz/main.php | 6 +- ext/handle_flash/main.php | 2 +- ext/handle_ico/main.php | 8 +- ext/handle_mp3/main.php | 7 +- ext/handle_pixel/main.php | 22 +- ext/handle_svg/main.php | 6 +- ext/handle_video/main.php | 40 ++- ext/handle_video/theme.php | 9 +- ext/image/config.php | 8 +- ext/image/main.php | 49 +++- ext/index/info.php | 21 +- ext/index/main.php | 3 - ext/index/theme.php | 73 +++-- ext/media/events.php | 16 +- ext/media/info.php | 1 + ext/media/main.php | 285 +++++------------- ext/media/media_engine.php | 99 ++++--- ext/media/theme.php | 22 -- ext/mime/file_extension.php | 105 +++++++ ext/mime/info.php | 14 + ext/mime/main.php | 85 ++++++ ext/mime/mime_map.php | 256 +++++++++++++++++ ext/mime/mime_type.php | 254 ++++++++++++++++ ext/mime/test.php | 9 + ext/mime/theme.php | 41 +++ ext/ouroboros_api/main.php | 6 +- ext/qr_code/main.php | 2 +- ext/random_image/main.php | 4 +- ext/regen_thumb/main.php | 30 +- ext/regen_thumb/theme.php | 18 +- ext/resize/main.php | 21 +- ext/rotate/main.php | 29 +- ext/rss_comments/main.php | 2 +- ext/rss_comments/test.php | 2 +- ext/rss_images/main.php | 2 +- ext/rss_images/test.php | 10 +- ext/shimmie_api/main.php | 6 +- ext/sitemap/main.php | 4 +- ext/static_files/main.php | 2 +- ext/tag_list/main.php | 2 +- ext/tagger_xml/main.php | 2 +- ext/transcode/config.php | 1 + ext/transcode/main.php | 229 +++++++++------ ext/transcode/script.js | 6 +- ext/transcode/theme.php | 2 +- ext/update/main.php | 2 +- ext/upgrade/main.php | 13 + ext/upload/main.php | 47 ++- ext/upload/theme.php | 4 +- themes/danbooru/view.theme.php | 2 +- themes/danbooru2/view.theme.php | 2 +- themes/lite/view.theme.php | 2 +- themes/rule34v2/themelet.class.php | 4 +- 73 files changed, 1386 insertions(+), 1148 deletions(-) delete mode 100644 core/filetypes.php create mode 100644 ext/mime/file_extension.php create mode 100644 ext/mime/info.php create mode 100644 ext/mime/main.php create mode 100644 ext/mime/mime_map.php create mode 100644 ext/mime/mime_type.php create mode 100644 ext/mime/test.php create mode 100644 ext/mime/theme.php diff --git a/core/basepage.php b/core/basepage.php index d92dafa4..3bd5f550 100644 --- a/core/basepage.php +++ b/core/basepage.php @@ -23,7 +23,7 @@ class BasePage /** @var string */ public $mode = PageMode::PAGE; /** @var string */ - private $type = "text/html; charset=utf-8"; + private $mime; /** * Set what this page should do; "page", "data", or "redirect". @@ -36,13 +36,14 @@ class BasePage /** * Set the page's MIME type. */ - public function set_type(string $type): void + public function set_mime(string $mime): void { - $this->type = $type; + $this->mime = $mime; } public function __construct() { + $this->mime = MimeType::add_parameters(MimeType::HTML, MimeType::CHARSET_UTF8); if (@$_GET["flash"]) { $this->flash[] = $_GET['flash']; unset($_GET["flash"]); @@ -243,7 +244,7 @@ class BasePage { if (!headers_sent()) { header("HTTP/1.0 {$this->code} Shimmie"); - header("Content-type: " . $this->type); + header("Content-type: " . $this->mime); header("X-Powered-By: Shimmie-" . VERSION); foreach ($this->http_headers as $head) { diff --git a/core/basethemelet.php b/core/basethemelet.php index bcae8d9f..b8289ebc 100644 --- a/core/basethemelet.php +++ b/core/basethemelet.php @@ -53,8 +53,9 @@ class BaseThemelet $h_tip = html_escape($image->get_tooltip()); $h_tags = html_escape(strtolower($image->get_tag_list())); - $extArr = array_flip([EXTENSION_FLASH, EXTENSION_SVG, EXTENSION_MP3]); //List of thumbless filetypes - if (!isset($extArr[$image->ext])) { + // TODO: Set up a function for fetching what kind of files are currently thumbnailable + $mimeArr = array_flip([MimeType::MP3]); //List of thumbless filetypes + if (!isset($mimeArr[$image->get_mime()])) { $tsize = get_thumbnail_size($image->width, $image->height); } else { //Use max thumbnail size if using thumbless filetype diff --git a/core/extension.php b/core/extension.php index 18aa9703..c65418c4 100644 --- a/core/extension.php +++ b/core/extension.php @@ -291,11 +291,11 @@ abstract class DataHandlerExtension extends Extension public function onDataUpload(DataUploadEvent $event) { - $supported_ext = $this->supported_ext($event->type); + $supported_mime = $this->supported_mime($event->mime); $check_contents = $this->check_contents($event->tmpname); - if ($supported_ext && $check_contents) { + if ($supported_mime && $check_contents) { $this->move_upload_to_archive($event); - send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); + send_event(new ThumbnailGenerationEvent($event->hash, $event->mime)); /* Check if we are replacing an image */ if (!is_null($event->replace_id)) { @@ -317,8 +317,8 @@ abstract class DataHandlerExtension extends Extension if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); } - if (empty($image->ext)) { - throw new UploadException("Unable to determine extension for ". $event->tmpname); + if (empty($image->get_mime())) { + throw new UploadException("Unable to determine MIME for ". $event->tmpname); } try { send_event(new MediaCheckPropertiesEvent($image)); @@ -333,8 +333,8 @@ abstract class DataHandlerExtension extends Extension if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); } - if (empty($image->ext)) { - throw new UploadException("Unable to determine extension for ". $event->tmpname); + if (empty($image->get_mime())) { + throw new UploadException("Unable to determine MIME for ". $event->tmpname); } try { send_event(new MediaCheckPropertiesEvent($image)); @@ -358,7 +358,7 @@ abstract class DataHandlerExtension extends Extension send_event(new LockSetEvent($image, !empty($locked))); } } - } elseif ($supported_ext && !$check_contents) { + } elseif ($supported_mime && !$check_contents) { // We DO support this extension - but the file looks corrupt throw new UploadException("Invalid or corrupted file"); } @@ -367,15 +367,15 @@ abstract class DataHandlerExtension extends Extension public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { $result = false; - if ($this->supported_ext($event->type)) { + if ($this->supported_mime($event->mime)) { if ($event->force) { - $result = $this->create_thumb($event->hash, $event->type); + $result = $this->create_thumb($event->hash, $event->mime); } else { $outname = warehouse_path(Image::THUMBNAIL_DIR, $event->hash); if (file_exists($outname)) { return; } - $result = $this->create_thumb($event->hash, $event->type); + $result = $this->create_thumb($event->hash, $event->mime); } } if ($result) { @@ -386,7 +386,7 @@ abstract class DataHandlerExtension extends Extension public function onDisplayingImage(DisplayingImageEvent $event) { global $page; - if ($this->supported_ext($event->image->ext)) { + if ($this->supported_mime($event->image->get_mime())) { /** @noinspection PhpPossiblePolymorphicInvocationInspection */ $this->theme->display_image($page, $event->image); } @@ -394,7 +394,7 @@ abstract class DataHandlerExtension extends Extension public function onMediaCheckProperties(MediaCheckPropertiesEvent $event) { - if ($this->supported_ext($event->ext)) { + if ($this->supported_mime($event->mime)) { $this->media_check_properties($event); } } @@ -408,11 +408,11 @@ abstract class DataHandlerExtension extends Extension $image->filesize = $metadata['size']; $image->hash = $metadata['hash']; $image->filename = (($pos = strpos($metadata['filename'], '?')) !== false) ? substr($metadata['filename'], 0, $pos) : $metadata['filename']; - if ($config->get_bool("upload_use_mime")) { - $image->ext = get_extension_for_file($filename); - } - if (empty($image->ext)) { - $image->ext = (($pos = strpos($metadata['extension'], '?')) !== false) ? substr($metadata['extension'], 0, $pos) : $metadata['extension']; + + if (array_key_exists("extension", $metadata)) { + $image->set_mime(MimeType::get_for_file($filename, $metadata["extension"])); + } else { + $image->set_mime(MimeType::get_for_file($filename)); } $image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']); @@ -423,22 +423,35 @@ abstract class DataHandlerExtension extends Extension abstract protected function media_check_properties(MediaCheckPropertiesEvent $event): void; abstract protected function check_contents(string $tmpname): bool; - abstract protected function create_thumb(string $hash, string $type): bool; + abstract protected function create_thumb(string $hash, string $mime): bool; - protected function supported_ext(string $ext): bool + protected function supported_mime(string $mime): bool { - return in_array(get_mime_for_extension($ext), $this->SUPPORTED_MIME); + return MimeType::matches_array($mime, $this->SUPPORTED_MIME); + } + + public static function get_all_supported_mimes(): array + { + $arr = []; + foreach (getSubclassesOf("DataHandlerExtension") as $handler) { + $handler = (new $handler()); + $arr = array_merge($arr, $handler->SUPPORTED_MIME); + } + + // Not sure how to handle this otherwise, don't want to set up a whole other event for this one class + if (class_exists("TranscodeImage")) { + $arr = array_merge($arr, TranscodeImage::get_enabled_mimes()); + } + + $arr = array_unique($arr); + return $arr; } public static function get_all_supported_exts(): array { $arr = []; - foreach (getSubclassesOf("DataHandlerExtension") as $handler) { - $handler = (new $handler()); - - foreach ($handler->SUPPORTED_MIME as $mime) { - $arr = array_merge($arr, get_all_extension_for_mime($mime)); - } + foreach (self::get_all_supported_mimes() as $mime) { + $arr = array_merge($arr, FileExtension::get_all_for_mime($mime)); } $arr = array_unique($arr); return $arr; diff --git a/core/filetypes.php b/core/filetypes.php deleted file mode 100644 index 74d5050c..00000000 --- a/core/filetypes.php +++ /dev/null @@ -1,448 +0,0 @@ - [ - MIME_TYPE_MAP_NAME => "ANI Cursor", - MIME_TYPE_MAP_EXT => [EXTENSION_ANI], - MIME_TYPE_MAP_MIME => [MIME_TYPE_ANI], - ], - MIME_TYPE_AVI => [ - MIME_TYPE_MAP_NAME => "AVI", - MIME_TYPE_MAP_EXT => [EXTENSION_AVI], - MIME_TYPE_MAP_MIME => [MIME_TYPE_AVI,'video/avi','video/msvideo'], - ], - MIME_TYPE_ASF => [ - MIME_TYPE_MAP_NAME => "ASF/WMV", - MIME_TYPE_MAP_EXT => [EXTENSION_ASF,EXTENSION_WMA,EXTENSION_WMV], - MIME_TYPE_MAP_MIME => [MIME_TYPE_ASF,'audio/x-ms-wma','video/x-ms-wmv'], - ], - MIME_TYPE_BMP => [ - MIME_TYPE_MAP_NAME => "BMP", - MIME_TYPE_MAP_EXT => [EXTENSION_BMP], - MIME_TYPE_MAP_MIME => [MIME_TYPE_BMP], - ], - MIME_TYPE_BZIP => [ - MIME_TYPE_MAP_NAME => "BZIP", - MIME_TYPE_MAP_EXT => [EXTENSION_BZIP], - MIME_TYPE_MAP_MIME => [MIME_TYPE_BZIP], - ], - MIME_TYPE_BZIP2 => [ - MIME_TYPE_MAP_NAME => "BZIP2", - MIME_TYPE_MAP_EXT => [EXTENSION_BZIP2], - MIME_TYPE_MAP_MIME => [MIME_TYPE_BZIP2], - ], - MIME_TYPE_COMIC_ZIP => [ - MIME_TYPE_MAP_NAME => "CBZ", - MIME_TYPE_MAP_EXT => [EXTENSION_CBZ], - MIME_TYPE_MAP_MIME => [MIME_TYPE_COMIC_ZIP], - ], - MIME_TYPE_CSS => [ - MIME_TYPE_MAP_NAME => "Cascading Style Sheet", - MIME_TYPE_MAP_EXT => [EXTENSION_CSS], - MIME_TYPE_MAP_MIME => [MIME_TYPE_CSS], - ], - MIME_TYPE_CSV => [ - MIME_TYPE_MAP_NAME => "CSV", - MIME_TYPE_MAP_EXT => [EXTENSION_CSV], - MIME_TYPE_MAP_MIME => [MIME_TYPE_CSV], - ], - MIME_TYPE_FLASH => [ - MIME_TYPE_MAP_NAME => "Flash", - MIME_TYPE_MAP_EXT => [EXTENSION_FLASH], - MIME_TYPE_MAP_MIME => [MIME_TYPE_FLASH], - ], - MIME_TYPE_FLASH_VIDEO => [ - MIME_TYPE_MAP_NAME => "Flash Video", - MIME_TYPE_MAP_EXT => [EXTENSION_FLASH_VIDEO], - MIME_TYPE_MAP_MIME => [MIME_TYPE_FLASH_VIDEO,'video/flv'], - ], - MIME_TYPE_GIF => [ - MIME_TYPE_MAP_NAME => "GIF", - MIME_TYPE_MAP_EXT => [EXTENSION_GIF], - MIME_TYPE_MAP_MIME => [MIME_TYPE_GIF], - ], - MIME_TYPE_GZIP => [ - MIME_TYPE_MAP_NAME => "GZIP", - MIME_TYPE_MAP_EXT => [EXTENSION_GZIP], - MIME_TYPE_MAP_MIME => [MIME_TYPE_TAR], - ], - MIME_TYPE_HTML => [ - MIME_TYPE_MAP_NAME => "HTML", - MIME_TYPE_MAP_EXT => [EXTENSION_HTM, EXTENSION_HTML], - MIME_TYPE_MAP_MIME => [MIME_TYPE_HTML], - ], - MIME_TYPE_ICO => [ - MIME_TYPE_MAP_NAME => "Icon", - MIME_TYPE_MAP_EXT => [EXTENSION_ICO, EXTENSION_CUR], - MIME_TYPE_MAP_MIME => [MIME_TYPE_ICO, MIME_TYPE_WIN_BITMAP], - ], - MIME_TYPE_JPEG => [ - MIME_TYPE_MAP_NAME => "JPEG", - MIME_TYPE_MAP_EXT => [EXTENSION_JPG, EXTENSION_JPEG, EXTENSION_JFIF, EXTENSION_JFI], - MIME_TYPE_MAP_MIME => [MIME_TYPE_JPEG], - ], - MIME_TYPE_JS => [ - MIME_TYPE_MAP_NAME => "JavaScript", - MIME_TYPE_MAP_EXT => [EXTENSION_JS], - MIME_TYPE_MAP_MIME => [MIME_TYPE_JS], - ], - MIME_TYPE_JSON => [ - MIME_TYPE_MAP_NAME => "JSON", - MIME_TYPE_MAP_EXT => [EXTENSION_JSON], - MIME_TYPE_MAP_MIME => [MIME_TYPE_JSON], - ], - MIME_TYPE_MKV => [ - MIME_TYPE_MAP_NAME => "Matroska", - MIME_TYPE_MAP_EXT => [EXTENSION_MKV], - MIME_TYPE_MAP_MIME => [MIME_TYPE_MKV], - ], - MIME_TYPE_MP3 => [ - MIME_TYPE_MAP_NAME => "MP3", - MIME_TYPE_MAP_EXT => [EXTENSION_MP3], - MIME_TYPE_MAP_MIME => [MIME_TYPE_MP3], - ], - MIME_TYPE_MP4_AUDIO => [ - MIME_TYPE_MAP_NAME => "MP4 Audio", - MIME_TYPE_MAP_EXT => [EXTENSION_M4A], - MIME_TYPE_MAP_MIME => [MIME_TYPE_MP4_AUDIO,"audio/m4a"], - ], - MIME_TYPE_MP4_VIDEO => [ - MIME_TYPE_MAP_NAME => "MP4 Video", - MIME_TYPE_MAP_EXT => [EXTENSION_MP4,EXTENSION_M4V], - MIME_TYPE_MAP_MIME => [MIME_TYPE_MP4_VIDEO,'video/x-m4v'], - ], - MIME_TYPE_MPEG => [ - MIME_TYPE_MAP_NAME => "MPEG", - MIME_TYPE_MAP_EXT => [EXTENSION_MPG,EXTENSION_MPEG], - MIME_TYPE_MAP_MIME => [MIME_TYPE_MPEG], - ], - MIME_TYPE_PDF => [ - MIME_TYPE_MAP_NAME => "PDF", - MIME_TYPE_MAP_EXT => [EXTENSION_PDF], - MIME_TYPE_MAP_MIME => [MIME_TYPE_PDF], - ], - MIME_TYPE_PHP => [ - MIME_TYPE_MAP_NAME => "PHP", - MIME_TYPE_MAP_EXT => [EXTENSION_PHP,EXTENSION_PHP5], - MIME_TYPE_MAP_MIME => [MIME_TYPE_PHP], - ], - MIME_TYPE_PNG => [ - MIME_TYPE_MAP_NAME => "PNG", - MIME_TYPE_MAP_EXT => [EXTENSION_PNG], - MIME_TYPE_MAP_MIME => [MIME_TYPE_PNG], - ], - MIME_TYPE_PSD => [ - MIME_TYPE_MAP_NAME => "PSD", - MIME_TYPE_MAP_EXT => [EXTENSION_PSD], - MIME_TYPE_MAP_MIME => [MIME_TYPE_PSD], - ], - MIME_TYPE_OGG_AUDIO => [ - MIME_TYPE_MAP_NAME => "Ogg Vorbis", - MIME_TYPE_MAP_EXT => [EXTENSION_OGG_AUDIO,EXTENSION_OGG], - MIME_TYPE_MAP_MIME => [MIME_TYPE_OGG_AUDIO,MIME_TYPE_OGG], - ], - MIME_TYPE_OGG_VIDEO => [ - MIME_TYPE_MAP_NAME => "Ogg Theora", - MIME_TYPE_MAP_EXT => [EXTENSION_OGG_VIDEO], - MIME_TYPE_MAP_MIME => [MIME_TYPE_OGG_VIDEO], - ], - MIME_TYPE_QUICKTIME => [ - MIME_TYPE_MAP_NAME => "Quicktime", - MIME_TYPE_MAP_EXT => [EXTENSION_MOV], - MIME_TYPE_MAP_MIME => [MIME_TYPE_QUICKTIME], - ], - MIME_TYPE_RSS => [ - MIME_TYPE_MAP_NAME => "RSS", - MIME_TYPE_MAP_EXT => [EXTENSION_RSS], - MIME_TYPE_MAP_MIME => [MIME_TYPE_RSS], - ], - MIME_TYPE_SVG => [ - MIME_TYPE_MAP_NAME => "SVG", - MIME_TYPE_MAP_EXT => [EXTENSION_SVG], - MIME_TYPE_MAP_MIME => [MIME_TYPE_SVG], - ], - MIME_TYPE_TAR => [ - MIME_TYPE_MAP_NAME => "TAR", - MIME_TYPE_MAP_EXT => [EXTENSION_TAR], - MIME_TYPE_MAP_MIME => [MIME_TYPE_TAR], - ], - MIME_TYPE_TEXT => [ - MIME_TYPE_MAP_NAME => "Text", - MIME_TYPE_MAP_EXT => [EXTENSION_TEXT, EXTENSION_ASC], - MIME_TYPE_MAP_MIME => [MIME_TYPE_TEXT], - ], - MIME_TYPE_TIFF => [ - MIME_TYPE_MAP_NAME => "TIFF", - MIME_TYPE_MAP_EXT => [EXTENSION_TIF,EXTENSION_TIFF], - MIME_TYPE_MAP_MIME => [MIME_TYPE_TIFF], - ], - MIME_TYPE_WAV => [ - MIME_TYPE_MAP_NAME => "Wave", - MIME_TYPE_MAP_EXT => [EXTENSION_WAV], - MIME_TYPE_MAP_MIME => [MIME_TYPE_WAV], - ], - MIME_TYPE_WEBM => [ - MIME_TYPE_MAP_NAME => "WebM", - MIME_TYPE_MAP_EXT => [EXTENSION_WEBM], - MIME_TYPE_MAP_MIME => [MIME_TYPE_WEBM], - ], - MIME_TYPE_WEBP => [ - MIME_TYPE_MAP_NAME => "WebP", - MIME_TYPE_MAP_EXT => [EXTENSION_WEBP], - MIME_TYPE_MAP_MIME => [MIME_TYPE_WEBP], - ], - MIME_TYPE_XML => [ - MIME_TYPE_MAP_NAME => "XML", - MIME_TYPE_MAP_EXT => [EXTENSION_XML], - MIME_TYPE_MAP_MIME => [MIME_TYPE_XML,MIME_TYPE_XML_APPLICATION], - ], - MIME_TYPE_XSL => [ - MIME_TYPE_MAP_NAME => "XSL", - MIME_TYPE_MAP_EXT => [EXTENSION_XSL], - MIME_TYPE_MAP_MIME => [MIME_TYPE_XSL], - ], - MIME_TYPE_ZIP => [ - MIME_TYPE_MAP_NAME => "ZIP", - MIME_TYPE_MAP_EXT => [EXTENSION_ZIP], - MIME_TYPE_MAP_MIME => [MIME_TYPE_ZIP], - ], -]; - -/** - * Returns the mimetype that matches the provided extension. - */ -function get_mime_for_extension(string $ext): ?string -{ - $ext = strtolower($ext); - - foreach (MIME_TYPE_MAP as $key=>$value) { - if (in_array($ext, $value[MIME_TYPE_MAP_EXT])) { - return $key; - } - } - return null; -} - -/** - * Returns the mimetype for the specified file, trying file inspection methods before falling back on extension-based detection. - * @param String $file - * @param String $ext The files extension, for if the current filename somehow lacks the extension - * @return String The extension that was found. - */ -function get_mime(string $file, string $ext=""): string -{ - if (!file_exists($file)) { - throw new SCoreException("File not found: ".$file); - } - - $type = false; - - if (extension_loaded('fileinfo')) { - $finfo = finfo_open(FILEINFO_MIME_TYPE); - try { - $type = finfo_file($finfo, $file); - } finally { - finfo_close($finfo); - } - } elseif (function_exists('mime_content_type')) { - // If anyone is still using mime_content_type() - $type = trim(mime_content_type($file)); - } - - if ($type===false || empty($type)) { - // Checking by extension is our last resort - if ($ext==null||strlen($ext) == 0) { - $ext = pathinfo($file, PATHINFO_EXTENSION); - } - - $type = get_mime_for_extension($ext); - } - - if ($type !== false && strlen($type) > 0) { - return $type; - } - - return MIME_TYPE_OCTET_STREAM; -} - -/** - * Returns the file extension associated with the specified mimetype. - */ -function get_extension(?string $mime_type): ?string -{ - if (empty($mime_type)) { - return null; - } - - if ($mime_type==MIME_TYPE_OCTET_STREAM) { - return null; - } - - foreach (MIME_TYPE_MAP as $key=>$value) { - if (in_array($mime_type, $value[MIME_TYPE_MAP_MIME])) { - return $value[MIME_TYPE_MAP_EXT][0]; - } - } - return null; -} - -/** - * Returns all of the file extensions associated with the specified mimetype. - */ -function get_all_extension_for_mime(?string $mime_type): array -{ - $output = []; - if (empty($mime_type)) { - return $output; - } - - foreach (MIME_TYPE_MAP as $key=>$value) { - if (in_array($mime_type, $value[MIME_TYPE_MAP_MIME])) { - $output = array_merge($output, $value[MIME_TYPE_MAP_EXT]); - } - } - return $output; -} - -/** - * Gets an the extension defined in MIME_TYPE_MAP for a file. - * - * @param String $file_path - * @return String The extension that was found, or null if one can not be found. - */ -function get_extension_for_file(String $file_path): ?String -{ - $mime = get_mime($file_path); - if (!empty($mime)) { - if ($mime==MIME_TYPE_OCTET_STREAM) { - return null; - } else { - $ext = get_extension($mime); - } - if (!empty($ext)) { - return $ext; - } - } - return null; -} diff --git a/core/imageboard/event.php b/core/imageboard/event.php index 27a00f96..a6fa55b0 100644 --- a/core/imageboard/event.php +++ b/core/imageboard/event.php @@ -91,7 +91,7 @@ class ThumbnailGenerationEvent extends Event /** @var string */ public $hash; /** @var string */ - public $type; + public $mime; /** @var bool */ public $force; @@ -101,11 +101,11 @@ class ThumbnailGenerationEvent extends Event /** * Request a thumbnail be made for an image object */ - public function __construct(string $hash, string $type, bool $force=false) + public function __construct(string $hash, string $mime, bool $force=false) { parent::__construct(); $this->hash = $hash; - $this->type = $type; + $this->mime = $mime; $this->force = $force; $this->generated = false; } diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 6b786472..e4fa0c5d 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -34,7 +34,10 @@ class Image public $filename; /** @var string */ - public $ext; + private $ext; + + /** @var string */ + private $mime; /** @var string[]|null */ public $tag_array; @@ -396,22 +399,22 @@ class Image "INSERT INTO images( owner_id, owner_ip, filename, filesize, - hash, ext, + hash, mime, ext, width, height, posted, source ) VALUES ( :owner_id, :owner_ip, :filename, :filesize, - :hash, :ext, + :hash, :mime, :ext, 0, 0, now(), :source )", [ "owner_id" => $user->id, "owner_ip" => $_SERVER['REMOTE_ADDR'], "filename" => $cut_name, "filesize" => $this->filesize, - "hash" => $this->hash, "ext" => strtolower($this->ext), - "source" => $this->source + "hash" => $this->hash, "mime" => strtolower($this->mime), + "ext" => strtolower($this->ext), "source" => $this->source ] ); $this->id = $database->get_last_insert_id('images_id_seq'); @@ -419,12 +422,13 @@ class Image $database->execute( "UPDATE images SET ". "filename = :filename, filesize = :filesize, hash = :hash, ". - "ext = :ext, width = 0, height = 0, source = :source ". + "mime = :mime, ext = :ext, width = 0, height = 0, source = :source ". "WHERE id = :id", [ "filename" => $cut_name, "filesize" => $this->filesize, "hash" => $this->hash, + "mime" => strtolower($this->mime), "ext" => strtolower($this->ext), "source" => $this->source, "id" => $this->id, @@ -503,7 +507,8 @@ class Image public function get_thumb_link(): string { global $config; - $ext = $config->get_string(ImageConfig::THUMB_TYPE); + $mime = $config->get_string(ImageConfig::THUMB_MIME); + $ext = FileExtension::get_for_mime($mime); return $this->get_link(ImageConfig::TLINK, '_thumbs/$hash/thumb.'.$ext, 'thumb/$id.'.$ext); } @@ -566,21 +571,34 @@ class Image } /** - * Get the image's mime type. - */ - public function get_mime_type(): string - { - return get_mime($this->get_image_filename(), $this->get_ext()); - } - - /** - * Get the image's filename extension + * Get the image's extension. */ public function get_ext(): string { return $this->ext; } + /** + * Get the image's mime type. + */ + public function get_mime(): string + { + if ($this->mime===MimeType::WEBP&&$this->lossless) { + return MimeType::WEBP_LOSSLESS; + } + return $this->mime; + } + + /** + * Set the image's mime type. + */ + public function set_mime($mime): void + { + $this->mime = $mime; + $this->ext = FileExtension::get_for_mime($this->get_mime()); + } + + /** * Get the image's source URL */ diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index 7d588955..dc9b8231 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -136,7 +136,7 @@ function get_thumbnail_max_size_scaled(): array } -function create_image_thumb(string $hash, string $type, string $engine = null) +function create_image_thumb(string $hash, string $mime, string $engine = null) { global $config; @@ -147,7 +147,7 @@ function create_image_thumb(string $hash, string $type, string $engine = null) $inname, $outname, $tsize, - $type, + $mime, $engine, $config->get_string(ImageConfig::THUMB_FIT) ); @@ -155,7 +155,7 @@ function create_image_thumb(string $hash, string $type, string $engine = null) -function create_scaled_image(string $inname, string $outname, array $tsize, string $type, ?string $engine = null, ?string $resize_type = null) +function create_scaled_image(string $inname, string $outname, array $tsize, string $mime, ?string $engine = null, ?string $resize_type = null) { global $config; if (empty($engine)) { @@ -165,20 +165,17 @@ function create_scaled_image(string $inname, string $outname, array $tsize, stri $resize_type = $config->get_string(ImageConfig::THUMB_FIT); } - $output_format = $config->get_string(ImageConfig::THUMB_TYPE); - if ($output_format==EXTENSION_WEBP) { - $output_format = Media::WEBP_LOSSY; - } + $output_mime = $config->get_string(ImageConfig::THUMB_MIME); send_event(new MediaResizeEvent( $engine, $inname, - $type, + $mime, $outname, $tsize[0], $tsize[1], $resize_type, - $output_format, + $output_mime, $config->get_int(ImageConfig::THUMB_QUALITY), true, true diff --git a/core/polyfills.php b/core/polyfills.php index 7a744eb3..328ebca2 100644 --- a/core/polyfills.php +++ b/core/polyfills.php @@ -3,9 +3,6 @@ * Things which should be in the core API * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -require_once "filetypes.php"; - - /** * Return the unique elements of an array, case insensitively */ diff --git a/ext/admin/main.php b/ext/admin/main.php index 6e41e952..91dbc5e2 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -103,7 +103,7 @@ class AdminPage extends Extension $uid = $event->args[0]; $image = Image::by_id_or_hash($uid); if ($image) { - send_event(new ThumbnailGenerationEvent($image->hash, $image->ext, true)); + send_event(new ThumbnailGenerationEvent($image->hash, $image->get_mime(), true)); } else { print("No post with ID '$uid'\n"); } diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index f3d4f979..73eb94f0 100644 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -96,7 +96,7 @@ class AliasEditor extends Extension $this->theme->display_aliases($t->table($t->query()), $t->paginator()); } elseif ($event->get_arg(0) == "export") { $page->set_mode(PageMode::DATA); - $page->set_type(MIME_TYPE_CSV); + $page->set_mime(MimeType::CSV); $page->set_filename("aliases.csv"); $page->set_data($this->get_alias_csv($database)); } elseif ($event->get_arg(0) == "import") { diff --git a/ext/auto_tagger/main.php b/ext/auto_tagger/main.php index dade5b69..c534ebbf 100644 --- a/ext/auto_tagger/main.php +++ b/ext/auto_tagger/main.php @@ -102,7 +102,7 @@ class AutoTagger extends Extension $this->theme->display_auto_tagtable($t->table($t->query()), $t->paginator()); } elseif ($event->get_arg(0) == "export") { $page->set_mode(PageMode::DATA); - $page->set_type(MIME_TYPE_CSV); + $page->set_mime(MimeType::CSV); $page->set_filename("auto_tag.csv"); $page->set_data($this->get_auto_tag_csv($database)); } elseif ($event->get_arg(0) == "import") { diff --git a/ext/autocomplete/main.php b/ext/autocomplete/main.php index 4d459651..0ede9244 100644 --- a/ext/autocomplete/main.php +++ b/ext/autocomplete/main.php @@ -20,7 +20,7 @@ class AutoComplete extends Extension } $page->set_mode(PageMode::DATA); - $page->set_type(MIME_TYPE_JSON); + $page->set_mime(MimeType::JSON); $s = strtolower($_GET["s"]); if ( diff --git a/ext/browser_search/main.php b/ext/browser_search/main.php index c3965896..4781c9a2 100644 --- a/ext/browser_search/main.php +++ b/ext/browser_search/main.php @@ -42,7 +42,7 @@ class BrowserSearch extends Extension // And now to send it to the browser $page->set_mode(PageMode::DATA); - $page->set_type(MIME_TYPE_XML); + $page->set_mime(MimeType::XML); $page->set_data($xml); } elseif ($event->page_matches("browser_search")) { $suggestions = $config->get_string("search_suggestions_results_order"); diff --git a/ext/bulk_import_export/main.php b/ext/bulk_import_export/main.php index b9ae1b4d..f4dffdc4 100644 --- a/ext/bulk_import_export/main.php +++ b/ext/bulk_import_export/main.php @@ -5,14 +5,14 @@ class BulkImportExport extends DataHandlerExtension { const EXPORT_ACTION_NAME = "bulk_export"; const EXPORT_INFO_FILE_NAME = "export.json"; - protected $SUPPORTED_MIME = [MIME_TYPE_ZIP]; + protected $SUPPORTED_MIME = [MimeType::ZIP]; public function onDataUpload(DataUploadEvent $event) { global $user, $database; - if ($this->supported_ext($event->type) && + if ($this->supported_mime($event->mime) && $user->can(Permissions::BULK_IMPORT)) { $zip = new ZipArchive; diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index fc94ab78..f43c12dd 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -545,7 +545,7 @@ class CronUploader extends Extension global $page; $page->set_mode(PageMode::MANUAL); - $page->set_type(MIME_TYPE_TEXT); + $page->set_mime(MimeType::TEXT); $page->send_headers(); } } diff --git a/ext/danbooru_api/main.php b/ext/danbooru_api/main.php index 085a7cc1..df845532 100644 --- a/ext/danbooru_api/main.php +++ b/ext/danbooru_api/main.php @@ -10,13 +10,13 @@ class DanbooruApi extends Extension if ($event->page_matches("api/danbooru/add_post") || $event->page_matches("api/danbooru/post/create.xml")) { // No XML data is returned from this function - $page->set_type(MIME_TYPE_TEXT); + $page->set_mime(MimeType::TEXT); $this->api_add_post(); } elseif ($event->page_matches("api/danbooru/find_posts") || $event->page_matches("api/danbooru/post/index.xml")) { - $page->set_type(MIME_TYPE_XML_APPLICATION); + $page->set_mime(MimeType::XML_APPLICATION); $page->set_data($this->api_find_posts()); } elseif ($event->page_matches("api/danbooru/find_tags")) { - $page->set_type(MIME_TYPE_XML_APPLICATION); + $page->set_mime(MimeType::XML_APPLICATION); $page->set_data($this->api_find_tags()); } diff --git a/ext/download/main.php b/ext/download/main.php index 8aefec47..23aa6092 100644 --- a/ext/download/main.php +++ b/ext/download/main.php @@ -15,7 +15,7 @@ class Download extends Extension { global $page; - $page->set_type($event->mime); + $page->set_mime($event->mime); $page->set_mode(PageMode::FILE); diff --git a/ext/et/main.php b/ext/et/main.php index f95da649..9ca4fbae 100644 --- a/ext/et/main.php +++ b/ext/et/main.php @@ -76,7 +76,7 @@ class ET extends Extension "extensions" => [ "core" => $core_exts, "extra" => $extra_exts, - "handled_extensions" => DataHandlerExtension::get_all_supported_exts(), + "handled_mimes" => DataHandlerExtension::get_all_supported_mimes(), ], "stats" => [ 'images' => (int)$database->get_one("SELECT COUNT(*) FROM images"), @@ -94,7 +94,7 @@ class ET extends Extension "width" => $config->get_int(ImageConfig::THUMB_WIDTH), "height" => $config->get_int(ImageConfig::THUMB_HEIGHT), "scaling" => $config->get_int(ImageConfig::THUMB_SCALING), - "type" => $config->get_string(ImageConfig::THUMB_TYPE), + "mime" => $config->get_string(ImageConfig::THUMB_MIME), ], ]; diff --git a/ext/featured/main.php b/ext/featured/main.php index 5979ba21..18f90470 100644 --- a/ext/featured/main.php +++ b/ext/featured/main.php @@ -30,7 +30,7 @@ class Featured extends Extension $image = Image::by_id($config->get_int("featured_id")); if (!is_null($image)) { $page->set_mode(PageMode::DATA); - $page->set_type($image->get_mime_type()); + $page->set_mime($image->get_mime()); $page->set_data(file_get_contents($image->get_image_filename())); } } diff --git a/ext/handle_archive/main.php b/ext/handle_archive/main.php index c1e1effb..d6a57098 100644 --- a/ext/handle_archive/main.php +++ b/ext/handle_archive/main.php @@ -2,7 +2,7 @@ class ArchiveFileHandler extends DataHandlerExtension { - protected $SUPPORTED_MIME = [MIME_TYPE_ZIP]; + protected $SUPPORTED_MIME = [MimeType::ZIP]; public function onInitExt(InitExtEvent $event) { @@ -21,7 +21,7 @@ class ArchiveFileHandler extends DataHandlerExtension public function onDataUpload(DataUploadEvent $event) { - if ($this->supported_ext($event->type)) { + if ($this->supported_mime($event->mime)) { global $config, $page; $tmp = sys_get_temp_dir(); $tmpdir = "$tmp/shimmie-archive-{$event->hash}"; diff --git a/ext/handle_cbz/main.php b/ext/handle_cbz/main.php index c6ce429e..eaf7503d 100644 --- a/ext/handle_cbz/main.php +++ b/ext/handle_cbz/main.php @@ -2,7 +2,7 @@ class CBZFileHandler extends DataHandlerExtension { - public $SUPPORTED_MIME = [MIME_TYPE_COMIC_ZIP]; + protected $SUPPORTED_MIME = [MimeType::COMIC_ZIP]; protected function media_check_properties(MediaCheckPropertiesEvent $event): void { @@ -20,14 +20,14 @@ class CBZFileHandler extends DataHandlerExtension unlink($tmp); } - protected function create_thumb(string $hash, string $type): bool + protected function create_thumb(string $hash, string $mime): bool { $cover = $this->get_representative_image(warehouse_path(Image::IMAGE_DIR, $hash)); create_scaled_image( $cover, warehouse_path(Image::THUMBNAIL_DIR, $hash), get_thumbnail_max_size_scaled(), - get_extension(get_mime($cover)), + MimeType::get_for_file($cover), null ); return true; diff --git a/ext/handle_flash/main.php b/ext/handle_flash/main.php index 2bad8e3e..b4b0969c 100644 --- a/ext/handle_flash/main.php +++ b/ext/handle_flash/main.php @@ -2,7 +2,7 @@ class FlashFileHandler extends DataHandlerExtension { - protected $SUPPORTED_MIME = [MIME_TYPE_FLASH]; + protected $SUPPORTED_MIME = [MimeType::FLASH]; protected function media_check_properties(MediaCheckPropertiesEvent $event): void { diff --git a/ext/handle_ico/main.php b/ext/handle_ico/main.php index 50e570fd..10d91ea1 100644 --- a/ext/handle_ico/main.php +++ b/ext/handle_ico/main.php @@ -2,14 +2,14 @@ class IcoFileHandler extends DataHandlerExtension { - protected $SUPPORTED_MIME = [MIME_TYPE_ICO, MIME_TYPE_ANI]; + protected $SUPPORTED_MIME = [MimeType::ICO, MimeType::ANI, MimeType::WIN_BITMAP]; protected function media_check_properties(MediaCheckPropertiesEvent $event): void { $event->image->lossless = true; $event->image->video = false; $event->image->audio = false; - $event->image->image = ($event->ext!="ani"); + $event->image->image = ($event->mime!= MimeType::ANI); $fp = fopen($event->file_name, "r"); try { @@ -25,10 +25,10 @@ class IcoFileHandler extends DataHandlerExtension $event->image->height = $height == 0 ? 256 : $height; } - protected function create_thumb(string $hash, string $type): bool + protected function create_thumb(string $hash, string $mime): bool { try { - create_image_thumb($hash, $type, MediaEngine::IMAGICK); + create_image_thumb($hash, $mime, MediaEngine::IMAGICK); return true; } catch (MediaException $e) { log_warning("handle_ico", "Could not generate thumbnail. " . $e->getMessage()); diff --git a/ext/handle_mp3/main.php b/ext/handle_mp3/main.php index 17123bff..48663bc9 100644 --- a/ext/handle_mp3/main.php +++ b/ext/handle_mp3/main.php @@ -1,8 +1,11 @@ ext, Media::LOSSLESS_FORMATS)) { - $event->image->lossless = true; - } elseif ($event->ext==EXTENSION_WEBP) { - $event->image->lossless = Media::is_lossless_webp($event->file_name); - } - - if ($event->image->lossless==null) { - $event->image->lossless = false; - } + $event->image->lossless = Media::is_lossless($event->file_name, $event->mime); $event->image->audio = false; - switch ($event->ext) { - case EXTENSION_GIF: - $event->image->video = Media::is_animated_gif($event->file_name); + switch ($event->mime) { + case MimeType::GIF: + $event->image->video = MimeType::is_animated_gif($event->file_name); break; - case EXTENSION_WEBP: - $event->image->video = Media::is_animated_webp($event->file_name); + case MimeType::WEBP: + $event->image->video = MimeType::is_animated_webp($event->file_name); break; default: $event->image->video = false; diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index 7b366a4a..1c8cafb3 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -3,7 +3,7 @@ use enshrined\svgSanitize\Sanitizer; class SVGFileHandler extends DataHandlerExtension { - protected $SUPPORTED_MIME = [MIME_TYPE_SVG]; + protected $SUPPORTED_MIME = [MimeType::SVG]; /** @var SVGFileHandlerTheme */ protected $theme; @@ -16,7 +16,7 @@ class SVGFileHandler extends DataHandlerExtension $image = Image::by_id($id); $hash = $image->hash; - $page->set_type(MIME_TYPE_SVG); + $page->set_mime(MimeType::SVG); $page->set_mode(PageMode::DATA); $sanitizer = new Sanitizer(); @@ -67,7 +67,7 @@ class SVGFileHandler extends DataHandlerExtension protected function check_contents(string $file): bool { - if (get_mime($file)!==MIME_TYPE_SVG) { + if (MimeType::get_for_file($file)!==MimeType::SVG) { return false; } diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index 4fd5d80a..b5b53465 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -11,14 +11,14 @@ abstract class VideoFileHandlerConfig class VideoFileHandler extends DataHandlerExtension { public const SUPPORTED_MIME = [ - MIME_TYPE_ASF, - MIME_TYPE_AVI, - MIME_TYPE_FLASH_VIDEO, - MIME_TYPE_MKV, - MIME_TYPE_MP4_VIDEO, - MIME_TYPE_OGG_VIDEO, - MIME_TYPE_QUICKTIME, - MIME_TYPE_WEBM, + MimeType::ASF, + MimeType::AVI, + MimeType::FLASH_VIDEO, + MimeType::MKV, + MimeType::MP4_VIDEO, + MimeType::OGG_VIDEO, + MimeType::QUICKTIME, + MimeType::WEBM, ]; protected $SUPPORTED_MIME = self::SUPPORTED_MIME; @@ -31,15 +31,15 @@ class VideoFileHandler extends DataHandlerExtension $config->set_default_bool(VideoFileHandlerConfig::PLAYBACK_MUTE, false); $config->set_default_array( VideoFileHandlerConfig::ENABLED_FORMATS, - [MIME_TYPE_FLASH_VIDEO, MIME_TYPE_MP4_VIDEO, MIME_TYPE_OGG_VIDEO, MIME_TYPE_WEBM] + [MimeType::FLASH_VIDEO, MimeType::MP4_VIDEO, MimeType::OGG_VIDEO, MimeType::WEBM] ); } private function get_options(): array { $output = []; - foreach ($this->SUPPORTED_MIME as $format) { - $output[MIME_TYPE_MAP[$format][MIME_TYPE_MAP_NAME]] = $format; + foreach ($this->SUPPORTED_MIME as $mime) { + $output[MimeMap::get_name_for_mime($mime)] = $mime; } return $output; } @@ -108,17 +108,13 @@ class VideoFileHandler extends DataHandlerExtension } } - protected function supported_ext(string $ext): bool + protected function supported_mime(string $mime): bool { global $config; $enabled_formats = $config->get_array(VideoFileHandlerConfig::ENABLED_FORMATS); - foreach ($enabled_formats as $format) { - if (in_array($ext, MIME_TYPE_MAP[$format][MIME_TYPE_MAP_EXT])) { - return true; - } - } - return false; + + return MimeType::matches_array($mime, $enabled_formats, true); } protected function create_thumb(string $hash, string $type): bool @@ -131,13 +127,11 @@ class VideoFileHandler extends DataHandlerExtension global $config; if (file_exists($tmpname)) { - $mime = get_mime($tmpname); + $mime = MimeType::get_for_file($tmpname); $enabled_formats = $config->get_array(VideoFileHandlerConfig::ENABLED_FORMATS); - foreach ($enabled_formats as $format) { - if (in_array($mime, MIME_TYPE_MAP[$format][MIME_TYPE_MAP_MIME])) { - return true; - } + if (MimeType::matches_array($mime, $enabled_formats)) { + return true; } } return false; diff --git a/ext/handle_video/theme.php b/ext/handle_video/theme.php index 446dfce5..8dd4eb60 100644 --- a/ext/handle_video/theme.php +++ b/ext/handle_video/theme.php @@ -7,7 +7,7 @@ class VideoFileHandlerTheme extends Themelet global $config; $ilink = $image->get_image_link(); $thumb_url = make_http($image->get_thumb_link()); //used as fallback image - $ext = strtolower($image->get_ext()); + $mime = strtolower($image->get_mime()); $full_url = make_http($ilink); $autoplay = $config->get_bool(VideoFileHandlerConfig::PLAYBACK_AUTOPLAY); $loop = $config->get_bool(VideoFileHandlerConfig::PLAYBACK_LOOP); @@ -26,11 +26,10 @@ class VideoFileHandlerTheme extends Themelet $html = "Video not playing? Click here to download the file.
"; //Browser media format support: https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats - $mime = get_mime_for_extension($ext); - if (in_array($mime, VideoFileHandler::SUPPORTED_MIME)) { + if (MimeType::matches_array($mime, VideoFileHandler::SUPPORTED_MIME)) { //FLV isn't supported by