BookStack/app/Util/WebSafeMimeSniffer.php
Dan Brown 31f1dca8a8
Added detection and thumbnail bypass for apng images
Adds apng sniffing when generating thumbnails with retained ratios to
serve the original image files, as we do for GIF images, to prevent
the image being resized to a static version.

Is more tricky than GIF since apng file mimes and extensions
are the same as png, we have to detect part of the file header
to sniff the type. Means we have to sniff at a later stage
than GIF since we have to load the image file data.

Made some changes to the image thubmnail caching while doing
this work to fit in with this handling.

Added test to cover.
For #3136.
2022-01-04 13:10:35 +00:00

65 lines
1.5 KiB
PHP

<?php
namespace BookStack\Util;
use finfo;
/**
* Helper class to sniff out the mime-type of content resulting in
* a mime-type that's relatively safe to serve to a browser.
*/
class WebSafeMimeSniffer
{
/**
* @var string[]
*/
protected $safeMimes = [
'application/json',
'application/octet-stream',
'application/pdf',
'image/apng',
'image/bmp',
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'image/avif',
'image/heic',
'text/css',
'text/csv',
'text/javascript',
'text/json',
'text/plain',
'video/x-msvideo',
'video/mp4',
'video/mpeg',
'video/ogg',
'video/webm',
'video/vp9',
'video/h264',
'video/av1',
];
/**
* Sniff the mime-type from the given file content while running the result
* through an allow-list to ensure a web-safe result.
* Takes the content as a reference since the value may be quite large.
*/
public function sniff(string &$content): string
{
$fInfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $fInfo->buffer($content) ?: 'application/octet-stream';
if (in_array($mime, $this->safeMimes)) {
return $mime;
}
[$category] = explode('/', $mime, 2);
if ($category === 'text') {
return 'text/plain';
}
return 'application/octet-stream';
}
}