/**
* Checks if the file can be uploaded
*
* @param array $file File information
* @param string $component The option name for the component storing the parameters
* @param string $allowedExecutables Array of executable file types that shall be whitelisted
*
* @return boolean
*
* @since 3.2
*/
public function canUpload($file, $component = 'com_media', $allowedExecutables = array())
{
$app = Factory::getApplication();
$params = ComponentHelper::getParams($component);
if (empty($file['name'])) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_UPLOAD_INPUT'), 'error');
return false;
}
if ($file['name'] !== File::makeSafe($file['name'])) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILENAME'), 'error');
return false;
}
$filetypes = explode('.', $file['name']);
if (\count($filetypes) < 2) {
// There seems to be no extension
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILETYPE'), 'error');
return false;
}
array_shift($filetypes);
// Media file names should never have executable extensions buried in them.
$executables = array_merge(self::EXECUTABLES, InputFilter::FORBIDDEN_FILE_EXTENSIONS);
// Remove allowed executables from array
if (count($allowedExecutables)) {
$executables = array_diff($executables, $allowedExecutables);
}
$check = array_intersect($filetypes, $executables);
if (!empty($check)) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILETYPE'), 'error');
return false;
}
$filetype = array_pop($filetypes);
$allowable = array_map('trim', explode(',', $params->get('restrict_uploads_extensions', 'bmp,gif,jpg,jpeg,png,webp,ico,mp3,m4a,mp4a,ogg,mp4,mp4v,mpeg,mov,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,csv')));
$ignored = array_map('trim', explode(',', $params->get('ignore_extensions', '')));
if ($filetype == '' || $filetype == false || !\in_array($filetype, $allowable) && !\in_array($filetype, $ignored)) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILETYPE'), 'error');
return false;
}
$maxSize = (int) ($params->get('upload_maxsize', 0) * 1024 * 1024);
if ($maxSize > 0 && (int) $file['size'] > $maxSize) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILETOOLARGE'), 'error');
return false;
}
if ($params->get('restrict_uploads', 1)) {
$allowedExtensions = array_map('trim', explode(',', $params->get('restrict_uploads_extensions', 'bmp,gif,jpg,jpeg,png,webp,ico,mp3,m4a,mp4a,ogg,mp4,mp4v,mpeg,mov,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,csv')));
if (\in_array($filetype, $allowedExtensions)) {
// If tmp_name is empty, then the file was bigger than the PHP limit
if (!empty($file['tmp_name'])) {
// Get the mime type this is an image file
$mime = static::getMimeType($file['tmp_name'], true);
// Did we get anything useful?
if ($mime != false) {
$result = $this->checkMimeType($mime, $component);
// If the mime type is not allowed we don't upload it and show the mime code error to the user
if ($result === false) {
$app->enqueueMessage(Text::sprintf('JLIB_MEDIA_ERROR_WARNINVALID_MIMETYPE', $mime), 'error');
return false;
}
} else {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNINVALID_IMG'), 'error');
return false;
}
} else {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNFILETOOLARGE'), 'error');
return false;
}
} elseif (!\in_array($filetype, $ignored)) {
// Get the mime type this is not an image file
$mime = static::getMimeType($file['tmp_name'], false);
// Did we get anything useful?
if ($mime != false) {
$result = $this->checkMimeType($mime, $component);
// If the mime type is not allowed we don't upload it and show the mime code error to the user
if ($result === false) {
$app->enqueueMessage(Text::sprintf('JLIB_MEDIA_ERROR_WARNINVALID_MIMETYPE', $mime), 'error');
return false;
}
} else {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNINVALID_MIME'), 'error');
return false;
}
if (!Factory::getUser()->authorise('core.manage', $component)) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNNOTADMIN'), 'error');
return false;
}
}
}
if ($filetype === 'svg') {
$sanitizer = new Sanitizer();
$isValid = $sanitizer->sanitize(file_get_contents($file['tmp_name']));
$svgErrors = $sanitizer->getXmlIssues();
// We allow comments
foreach ($svgErrors as $i => $error) {
if ($error['message'] === 'Suspicious node \'#comment\'') {
unset($svgErrors[$i]);
}
}
if ($isValid === false || count($svgErrors)) {
$app->enqueueMessage(Text::_('JLIB_MEDIA_ERROR_WARNIEXSS'), 'error');
return false;
}
}
return true;
}