fixes #2550 checks MIME type against each uploaded file

This commit is contained in:
plegall
2026-04-21 16:39:04 +02:00
parent d21b530cb0
commit 8cec3cc305
5 changed files with 153 additions and 33 deletions
+25
View File
@@ -3662,6 +3662,31 @@ SELECT
} }
} }
/**
* Displays a page warning if no MIME type is defined for an upload-authorized file extension
*
* @since 17.0.0
*/
function check_authorized_file_extension_mime_types()
{
global $conf, $page;
if (!is_webmaster())
{
return;
}
$authorized_file_extensions = $conf['upload_form_all_types'] ? $conf['file_ext'] : $conf['picture_ext'];
foreach ($authorized_file_extensions as $ext)
{
if (!isset($conf['mime_types_for_ext'][$ext]))
{
$page['warnings'][] = 'File extension "'.$ext.'" is authorized for upload but there is no $conf[\'mime_types_for_ext\'][\''.$ext.'\'] defined. Fix this.';
}
}
}
/** /**
* Return latest news from piwigo.org. * Return latest news from piwigo.org.
* *
+67 -32
View File
@@ -231,44 +231,34 @@ SELECT
$filename_wo_ext = $date_string.'-'.$random_string; $filename_wo_ext = $date_string.'-'.$random_string;
$file_path = $upload_dir.'/'.$filename_wo_ext.'.'; $file_path = $upload_dir.'/'.$filename_wo_ext.'.';
list($width, $height, $type) = getimagesize($source_filepath); $authorized_file_extensions = $conf['upload_form_all_types'] ? $conf['file_ext'] : $conf['picture_ext'];
if (IMAGETYPE_PNG == $type) $original_extension = strtolower(get_extension($original_filename));
{
$file_path.= 'png';
}
elseif (IMAGETYPE_GIF == $type)
{
$file_path.= 'gif';
}
elseif (IMAGETYPE_JPEG == $type)
{
$file_path.= 'jpg';
}
elseif (IMAGETYPE_WEBP == $type)
{
$file_path.= 'webp';
}
elseif (isset($conf['upload_form_all_types']) and $conf['upload_form_all_types'])
{
$original_extension = strtolower(get_extension($original_filename));
if (in_array($original_extension, $conf['file_ext'])) if (!in_array($original_extension, $authorized_file_extensions))
{
$file_path.= $original_extension;
}
else
{
unlink($source_filepath);
die('unexpected file type');
}
}
else
{ {
unlink($source_filepath); unlink($source_filepath);
die('forbidden file type');
$error_msg = 'forbidden file type';
if (defined('IN_WS'))
{
global $service;
$service->sendResponse(new PwgError(415, $error_msg));
exit;
}
die($error_msg);
} }
pwg_check_real_extension($source_filepath, $original_filename, true);
$file_extension_replace_by = array(
'jpeg' => 'jpg',
);
$file_path .= $file_extension_replace_by[$original_extension] ?? $original_extension;
prepare_directory($upload_dir); prepare_directory($upload_dir);
$file_path_pattern = $file_path; $file_path_pattern = $file_path;
@@ -979,6 +969,51 @@ function pwg_image_infos($path)
); );
} }
function pwg_check_real_extension($source_filepath, $original_filename, $die_on_error=true)
{
global $conf, $logger;
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$finfo_type = finfo_file($finfo, $source_filepath);
finfo_close($finfo);
$original_extension = strtolower(get_extension($original_filename));
if (!isset($conf['mime_types_for_ext'][$original_extension]))
{
// not a situation we like: the extension is authorized for upload but
// not listed for MIME type check. See function check_authorized_file_extension_mime_types
return true;
}
if (!in_array($finfo_type, $conf['mime_types_for_ext'][$original_extension]))
{
$error_msg = 'File extension "'.$original_extension.'" for file "'.$original_filename.'" does not match file MIME type "'.$finfo_type.'"';
$logger->info(__FUNCTION__.' '.$error_msg);
if ($die_on_error)
{
unlink($source_filepath);
if (defined('IN_WS'))
{
global $service;
$service->sendResponse(new PwgError(415, $error_msg));
exit;
}
die($error_msg);
}
return false;
}
$logger->info(__FUNCTION__.' file_ext='.$original_extension.' Vs finfo_type='.$finfo_type);
return true;
}
function is_valid_image_extension($extension) function is_valid_image_extension($extension)
{ {
global $conf; global $conf;
+1
View File
@@ -92,6 +92,7 @@ if ($locked_album > 0)
} }
fs_quick_check(); fs_quick_check();
check_authorized_file_extension_mime_types();
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
// | template init | // | template init |
+2
View File
@@ -160,5 +160,7 @@ $template->assign(array(
'str_format_ext' => implode(', ', $conf['format_ext']), 'str_format_ext' => implode(', ', $conf['format_ext']),
)); ));
check_authorized_file_extension_mime_types();
$template->assign_var_from_handle('ADMIN_CONTENT', 'photos_add'); $template->assign_var_from_handle('ADMIN_CONTENT', 'photos_add');
?> ?>
+57
View File
@@ -56,6 +56,63 @@ $conf['file_ext'] = array_merge(
array('tiff', 'tif', 'mpg','zip','avi','mp3','ogg','pdf','svg', 'heic') array('tiff', 'tif', 'mpg','zip','avi','mp3','ogg','pdf','svg', 'heic')
); );
// mime_types_for_ext : list of valid/expected MIME types for each file extension.
//
// Every permitted file extension authorized for upload should be listed.
// Otherwise Piwigo won't be able to check.
$conf['mime_types_for_ext'] = array(
'3gp' => ['video/3gpp', 'audio/3gpp'],
'ai' => ['application/postscript'],
'avi' => ['video/x-msvideo'],
'avif' => ['image/avif'],
'bmp' => ['image/bmp'],
'cr2' => ['image/x-canon-cr2'],
'dng' => ['image/x-adobe-dng'],
'doc' => ['application/msword'],
'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'eps' => ['application/postscript'],
'flv' => ['video/x-flv'],
'gif' => ['image/gif'],
'gp3' => ['video/3gpp'],
'gp4' => ['video/3gpp'],
'gpx' => ['application/gpx+xml'],
'heic' => ['image/heic', 'image/heif'],
'ico' => ['image/x-icon'],
'indd' => ['application/x-indesign'],
'jpeg' => ['image/jpeg'],
'jpg' => ['image/jpeg'],
'm4a' => ['audio/mp4', 'audio/x-m4a'],
'm4v' => ['video/x-m4v'],
'mkv' => ['video/x-matroska'],
'mov' => ['video/quicktime'],
'mp3' => ['audio/mpeg'],
'mp4' => ['video/mp4'],
'mpeg' => ['video/mpeg'],
'mpg' => ['video/mpeg'],
'nef' => ['image/x-nikon-nef'],
'odt' => ['application/vnd.oasis.opendocument.text'],
'ogg' => ['audio/ogg', 'application/ogg'],
'ogv' => ['video/ogg'],
'pdf' => ['application/pdf'],
'png' => ['image/png'],
'ppt' => ['application/vnd.ms-powerpoint'],
'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
'psd' => ['image/vnd.adobe.photoshop'],
'rar' => ['application/x-rar-compressed', 'application/vnd.rar'],
'strm' => ['application/x-ms-wmp'],
'svg' => ['image/svg', 'image/svg+xml'],
'tif' => ['image/tiff'],
'tiff' => ['image/tiff'],
'txt' => ['text/plain'],
'wav' => ['audio/wav', 'audio/x-wav'],
'webm' => ['video/webm'],
'webp' => ['image/webp'],
'wmv' => ['video/x-ms-wmv'],
'xls' => ['application/vnd.ms-excel'],
'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
'zip' => ['application/zip'],
);
// enable_formats: should Piwigo search for multiple formats? // enable_formats: should Piwigo search for multiple formats?
$conf['enable_formats'] = false; $conf['enable_formats'] = false;