파일이나 확장자가 이미지, 오디오, 동영상이며, MIME 타입이 전혀 다른 경우에만 확장자를 고치도록 수정

direct가 아닌 첨부파일 본문 삽입시의 오류 수정
이미지, 오디오, 동영상 MIME 타입을 mime_content_type()의 반환값으로 수정
This commit is contained in:
conory 2019-10-03 23:40:55 +09:00
parent ac9141b4f2
commit 6db830c4c4
9 changed files with 122 additions and 100 deletions

View file

@ -97,7 +97,7 @@ class FilenameFilter
*/ */
public static function isDirectDownload($filename) public static function isDirectDownload($filename)
{ {
if (preg_match('/\.(as[fx]|avi|flac|flv|gif|jpe?g|m4[av]|midi?|mkv|moov|mov|mp[1234]|mpe?g|ogg|png|qt|ram?|rmm?|wav|web[mp]|wm[av])$/i', $filename)) if (preg_match('/\.(as[fx]|avi|flac|flv|gif|jpe?g|m4[av]|midi?|mkv|moov|mov|mp[1234]|mpe?g|og[gv]|png|qt|ram?|rmm?|wav|web[mp]|wm[av])$/i', $filename))
{ {
return true; return true;
} }

View file

@ -63,11 +63,20 @@ class Image
{ {
return false; return false;
} }
$img_type = [
IMG_GIF => 'gif',
IMG_JPG => 'jpg',
// jpeg is the same as jpg
IMG_PNG => 'png',
IMG_WEBP => 'webp',
IMG_WBMP => 'wbmp',
IMG_XPM => 'xpm',
(defined('IMG_BMP') ? IMG_BMP : 64) => 'bmp',
];
return [ return [
'width' => $image_info[0], 'width' => $image_info[0],
'height' => $image_info[1], 'height' => $image_info[1],
'type' => image_type_to_extension($image_info[2], false), 'type' => $img_type[$image_info[2]],
'mime' => $image_info['mime'],
'bits' => $image_info['bits'] ?? null, 'bits' => $image_info['bits'] ?? null,
'channels' => $image_info['channels'] ?? null, 'channels' => $image_info['channels'] ?? null,
]; ];

View file

@ -16,7 +16,7 @@ class MIME
public static function getTypeByExtension($extension) public static function getTypeByExtension($extension)
{ {
$extension = strtolower($extension); $extension = strtolower($extension);
return array_key_exists($extension, self::$_types) ? self::$_types[$extension] : self::$_default; return array_key_exists($extension, self::$_types) ? self::$_types[$extension][0] : self::$_default;
} }
/** /**
@ -30,7 +30,7 @@ class MIME
$extension = strrchr($filename, '.'); $extension = strrchr($filename, '.');
if ($extension === false) return self::$_default; if ($extension === false) return self::$_default;
$extension = strtolower(substr($extension, 1)); $extension = strtolower(substr($extension, 1));
return array_key_exists($extension, self::$_types) ? self::$_types[$extension] : self::$_default; return array_key_exists($extension, self::$_types) ? self::$_types[$extension][0] : self::$_default;
} }
/** /**
@ -41,9 +41,12 @@ class MIME
*/ */
public static function getExtensionByType($type) public static function getExtensionByType($type)
{ {
foreach (self::$_types as $extension => $mime) foreach (self::$_types as $extension => $mimes)
{ {
if (!strncasecmp($type, $mime, strlen($type))) return $extension; foreach ($mimes as $mime)
{
if (!strncasecmp($type, $mime, strlen($type))) return $extension;
}
} }
return false; return false;
} }
@ -59,96 +62,106 @@ class MIME
protected static $_types = array( protected static $_types = array(
// Text-based document formats. // Text-based document formats.
'html' => 'text/html', 'html' => ['text/html'],
'htm' => 'text/html', 'htm' => ['text/html'],
'shtml' => 'text/html', 'shtml' => ['text/html'],
'txt' => 'text/plain', 'txt' => ['text/plain'],
'text' => 'text/plain', 'text' => ['text/plain'],
'log' => 'text/plain', 'log' => ['text/plain'],
'md' => 'text/markdown', 'md' => ['text/markdown'],
'markdown' => 'text/markdown', 'markdown' => ['text/markdown'],
'rtf' => 'text/rtf', 'rtf' => ['text/rtf'],
'xml' => 'text/xml', 'xml' => ['text/xml'],
'xsl' => 'text/xml', 'xsl' => ['text/xml'],
'css' => 'text/css', 'css' => ['text/css'],
'csv' => 'text/csv', 'csv' => ['text/csv'],
// Binary document formats. // Binary document formats.
'doc' => 'application/msword', 'doc' => ['application/msword'],
'dot' => 'application/msword', 'dot' => ['application/msword'],
'xls' => 'application/vnd.ms-excel', 'xls' => ['application/vnd.ms-excel'],
'ppt' => 'application/vnd.ms-powerpoint', 'ppt' => ['application/vnd.ms-powerpoint'],
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
'odt' => 'application/vnd.oasis.opendocument.text', 'odt' => ['application/vnd.oasis.opendocument.text'],
'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'ods' => ['application/vnd.oasis.opendocument.spreadsheet'],
'odp' => 'application/vnd.oasis.opendocument.presentation', 'odp' => ['application/vnd.oasis.opendocument.presentation'],
'odg' => 'application/vnd.oasis.opendocument.graphics', 'odg' => ['application/vnd.oasis.opendocument.graphics'],
'odb' => 'application/vnd.oasis.opendocument.database', 'odb' => ['application/vnd.oasis.opendocument.database'],
'pdf' => 'application/pdf', 'pdf' => ['application/pdf'],
'dvi' => ['application/x-dvi'],
// Images. // Images.
'bmp' => 'image/bmp', 'bmp' => ['image/bmp'],
'gif' => 'image/gif', 'gif' => ['image/gif'],
'jpg' => 'image/jpeg', 'jpg' => ['image/jpeg'],
'jpeg' => 'image/jpeg', 'jpeg' => ['image/jpeg'],
'jpe' => 'image/jpeg', 'jpe' => ['image/jpeg'],
'png' => 'image/png', 'png' => ['image/png'],
'svg' => 'image/svg+xml', 'webp' => ['image/webp'],
'tiff' => 'image/tiff', 'svg' => ['image/svg+xml'],
'tif' => 'image/tiff', 'tiff' => ['image/tiff'],
'ico' => 'image/vnd.microsoft.icon', 'tif' => ['image/tiff'],
'ico' => ['image/x-icon'],
// Audio. // Audio.
'mid' => 'audio/midi', 'mid' => ['audio/midi'],
'midi' => 'audio/midi', 'midi' => ['audio/midi'],
'mpga' => 'audio/mpeg', 'mp3' => ['audio/mpeg'],
'mp2' => 'audio/mpeg', 'mpga' => ['audio/mpeg'],
'mp3' => 'audio/mpeg', 'mp2' => ['audio/mpeg'],
'aif' => 'audio/x-aiff', 'aif' => ['audio/x-aiff'],
'aiff' => 'audio/x-aiff', 'aiff' => ['audio/x-aiff'],
'ra' => 'audio/x-realaudio', 'ra' => ['audio/x-realaudio'],
'wav' => 'audio/x-wav', 'wav' => ['audio/x-wav'],
'ogg' => 'audio/ogg', 'ogg' => ['audio/ogg'],
'm4a' => ['audio/x-m4a'],
// Video. // Video.
'avi' => 'video/x-msvideo', 'avi' => ['video/x-msvideo'],
'flv' => 'video/x-flv', 'flv' => ['video/x-flv'],
'mpeg' => 'video/mpeg', 'mpg' => ['video/mpeg'],
'mpg' => 'video/mpeg', 'mpeg' => ['video/mpeg'],
'mpe' => 'video/mpeg', 'mpe' => ['video/mpeg'],
'mp4' => 'video/mpeg', 'mp4' => ['video/mp4'],
'qt' => 'video/quicktime', 'webm' => ['video/webm'],
'mov' => 'video/quicktime', 'ogv' => ['video/ogg'],
'movie' => 'video/x-sgi-movie', 'mov' => ['video/quicktime'],
'rv' => 'video/vnd.rn-realvideo', 'moov' => ['video/quicktime'],
'dvi' => 'application/x-dvi', 'qt' => ['video/quicktime'],
'movie' => ['video/x-sgi-movie'],
'rv' => ['video/vnd.rn-realvideo'],
'mkv' => ['video/x-matroska'],
'wmv' => ['video/x-ms-asf'],
'wma' => ['video/x-ms-asf'],
'asf' => ['video/x-ms-asf'],
'm4v' => ['video/x-m4v'],
// Other multimedia file formats. // Other multimedia file formats.
'psd' => 'application/x-photoshop', 'psd' => ['application/x-photoshop'],
'swf' => 'application/x-shockwave-flash', 'swf' => ['application/x-shockwave-flash'],
'ai' => 'application/postscript', 'ai' => ['application/postscript'],
'eps' => 'application/postscript', 'eps' => ['application/postscript'],
'ps' => 'application/postscript', 'ps' => ['application/postscript'],
'mif' => 'application/vnd.mif', 'mif' => ['application/vnd.mif'],
'xul' => 'application/vnd.mozilla.xul+xml', 'xul' => ['application/vnd.mozilla.xul+xml'],
// Source code formats. // Source code formats.
'phps' => 'application/x-httpd-php-source', 'phps' => ['application/x-httpd-php-source'],
'js' => 'application/x-javascript', 'js' => ['application/x-javascript'],
// Archives. // Archives.
'bz2' => 'application/x-bzip', 'bz2' => ['application/x-bzip'],
'gz' => 'application/x-gzip', 'gz' => ['application/x-gzip'],
'tar' => 'application/x-tar', 'tar' => ['application/x-tar'],
'tgz' => 'application/x-tar', 'tgz' => ['application/x-tar'],
'gtar' => 'application/x-gtar', 'gtar' => ['application/x-gtar'],
'rar' => 'application/x-rar-compressed', 'rar' => ['application/x-rar-compressed'],
'zip' => 'application/x-zip', 'zip' => ['application/x-zip'],
// RFC822 email message. // RFC822 email message.
'eml' => 'message/rfc822', 'eml' => ['message/rfc822'],
); );
} }

View file

@ -154,10 +154,10 @@
if(/\.(jpe?g|png|gif|webp)$/i.test(result.source_filename)) { if(/\.(jpe?g|png|gif|webp)$/i.test(result.source_filename)) {
temp_code += '<img src="' + result.download_url + '" alt="' + result.source_filename + '" editor_component="image_link" data-file-srl="' + result.file_srl + '" />'; temp_code += '<img src="' + result.download_url + '" alt="' + result.source_filename + '" editor_component="image_link" data-file-srl="' + result.file_srl + '" />';
} }
else if(/\.(mp3)$/i.test(result.source_filename)) { else if(/\.(mp3|ogg|wav)$/i.test(result.source_filename)) {
temp_code += '<audio src="' + result.download_url + '" controls data-file-srl="' + result.file_srl + '" />'; temp_code += '<audio src="' + result.download_url + '" controls data-file-srl="' + result.file_srl + '" />';
} }
else if(/\.(mp4|webm|ogg)$/i.test(result.source_filename)) { else if(/\.(mp4|webm|ogv)$/i.test(result.source_filename)) {
if(result.original_type === 'image/gif') { if(result.original_type === 'image/gif') {
temp_code += '<video src="' + result.download_url + '" autoplay loop muted data-file-srl="' + result.file_srl + '" />'; temp_code += '<video src="' + result.download_url + '" autoplay loop muted data-file-srl="' + result.file_srl + '" />';
} else { } else {
@ -326,10 +326,10 @@
if(/\.(jpe?g|png|gif|webp)$/i.test(result.source_filename)) { if(/\.(jpe?g|png|gif|webp)$/i.test(result.source_filename)) {
temp_code += '<img src="' + result.download_url + '" alt="' + result.source_filename + '" editor_component="image_link" data-file-srl="' + result.file_srl + '" />'; temp_code += '<img src="' + result.download_url + '" alt="' + result.source_filename + '" editor_component="image_link" data-file-srl="' + result.file_srl + '" />';
} }
else if(/\.(mp3)$/i.test(result.source_filename)) { else if(/\.(mp3|ogg|wav)$/i.test(result.source_filename)) {
temp_code += '<audio src="' + result.download_url + '" controls data-file-srl="' + result.file_srl + '" />'; temp_code += '<audio src="' + result.download_url + '" controls data-file-srl="' + result.file_srl + '" />';
} }
else if(/\.(mp4|webm|ogg)$/i.test(result.source_filename)) { else if(/\.(mp4|webm|ogv)$/i.test(result.source_filename)) {
if(result.original_type === 'image/gif') { if(result.original_type === 'image/gif') {
temp_code += '<video src="' + result.download_url + '" autoplay loop muted data-file-srl="' + result.file_srl + '" />'; temp_code += '<video src="' + result.download_url + '" autoplay loop muted data-file-srl="' + result.file_srl + '" />';
} else { } else {
@ -343,7 +343,7 @@
} }
} }
if(temp_code === '') { if(temp_code === '') {
temp_code += '<a href="' + fileinfo.download_url + '" data-file-srl="' + fileinfo.file_srl + '">' + fileinfo.source_filename + "</a>\n"; temp_code += '<a href="' + result.download_url + '" data-file-srl="' + result.file_srl + '">' + result.source_filename + "</a>\n";
} }
_getCkeInstance(data.editorSequence).insertHtml(temp_code, "unfiltered_html"); _getCkeInstance(data.editorSequence).insertHtml(temp_code, "unfiltered_html");
}); });
@ -437,7 +437,7 @@
file.source_filename = file.source_filename.replace("&amp;", "&"); file.source_filename = file.source_filename.replace("&amp;", "&");
if(file.thumbnail_filename) { if(file.thumbnail_filename) {
file.download_url = file.thumbnail_filename; file.download_url = file.thumbnail_filename;
if(/\.(mp4|webm|ogg)$/i.test(file.source_filename)) { if(/\.(mp4|webm|ogv)$/i.test(file.source_filename)) {
result_image.push(template_fileimte_video(file)); result_image.push(template_fileimte_video(file));
} else { } else {
result_image.push(template_fileimte_image(file)); result_image.push(template_fileimte_image(file));

View file

@ -884,17 +884,13 @@ class fileController extends file
$file_info['converted'] = false; $file_info['converted'] = false;
// Correct extension // Correct extension
if($extension_by_type = Rhymix\Framework\MIME::getExtensionByType($file_info['type'])) if($file_info['extension'])
{ {
$target_types = ['image', 'audio', 'video']; $type_by_extension = Rhymix\Framework\MIME::getTypeByExtension($file_info['extension']);
if(in_array(array_shift(explode('/', $file_info['type'])), $target_types)) if(!in_array($type_by_extension, [$file_info['type'], 'application/octet-stream']))
{ {
$file_info['extension'] = $extension_by_type; $extension_by_type = Rhymix\Framework\MIME::getExtensionByType($file_info['type']);
} if($extension_by_type && preg_match('@^(?:image|audio|video)/@m', $file_info['type'] . PHP_EOL . $type_by_extension))
elseif($file_info['extension'])
{
$type_by_extension = Rhymix\Framework\MIME::getTypeByExtension($file_info['extension']);
if(in_array(array_shift(explode('/', $type_by_extension)), $target_types))
{ {
$file_info['extension'] = $extension_by_type; $file_info['extension'] = $extension_by_type;
} }
@ -924,7 +920,7 @@ class fileController extends file
} }
// video // video
if(in_array($file_info['extension'], ['mp4', 'webm', 'ogg'])) if(in_array($file_info['extension'], ['mp4', 'webm', 'ogv']))
{ {
$file_info = $this->adjustUploadedVideo($file_info, $config); $file_info = $this->adjustUploadedVideo($file_info, $config);
} }
@ -1123,7 +1119,7 @@ class fileController extends file
} }
// Adjust image rotation // Adjust image rotation
if ($config->image_autorotate && in_array($image_info['type'], ['jpg', 'jpeg']) && function_exists('exif_read_data')) if ($config->image_autorotate && $image_info['type'] === 'jpg' && function_exists('exif_read_data'))
{ {
$exif = @exif_read_data($file_info['tmp_name']); $exif = @exif_read_data($file_info['tmp_name']);
if($exif && isset($exif['Orientation'])) if($exif && isset($exif['Orientation']))

View file

@ -98,4 +98,5 @@ $lang->video_mp4_gif_time = 'Treat as GIF';
$lang->about_video_mp4_gif_time = 'treat silent MP4 videos with duration less than the set time as GIF images, and play with auto and loop.'; $lang->about_video_mp4_gif_time = 'treat silent MP4 videos with duration less than the set time as GIF images, and play with auto and loop.';
$lang->ffmpeg_path = 'FFmpeg path'; $lang->ffmpeg_path = 'FFmpeg path';
$lang->ffprobe_path = 'FFprobe path'; $lang->ffprobe_path = 'FFprobe path';
$lang->msg_cannot_use_ffmpeg = 'FFmpeg and FFprobe must can be executed by PHP'; $lang->msg_cannot_use_ffmpeg = 'FFmpeg and FFprobe must can be executed by PHP.';
$lang->msg_cannot_use_exif = 'PHP Exif module is required.';

View file

@ -100,3 +100,4 @@ $lang->about_video_mp4_gif_time = '설정된 시간 이하의 길이를 가진
$lang->ffmpeg_path = 'FFmpeg 경로'; $lang->ffmpeg_path = 'FFmpeg 경로';
$lang->ffprobe_path = 'FFprobe 경로'; $lang->ffprobe_path = 'FFprobe 경로';
$lang->msg_cannot_use_ffmpeg = 'PHP에서 FFmpeg 및 FFprobe를 실행할 수 있어야 합니다.'; $lang->msg_cannot_use_ffmpeg = 'PHP에서 FFmpeg 및 FFprobe를 실행할 수 있어야 합니다.';
$lang->msg_cannot_use_exif = 'PHP Exif 모듈이 필요합니다.';

View file

@ -112,6 +112,7 @@
{$lang->cmd_no} {$lang->cmd_no}
</label> </label>
<p class="x_help-block">{$lang->about_image_autorotate}</p> <p class="x_help-block">{$lang->about_image_autorotate}</p>
<p class="x_text-info" cond="!function_exists('exif_read_data')">{$lang->msg_cannot_use_exif}</p>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">

View file

@ -92,6 +92,7 @@
{$lang->cmd_no} {$lang->cmd_no}
</label> </label>
<p class="x_help-block">{$lang->about_image_autorotate}</p> <p class="x_help-block">{$lang->about_image_autorotate}</p>
<p class="x_text-info" cond="!function_exists('exif_read_data')">{$lang->msg_cannot_use_exif}</p>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">