在我的网站应用程序中,我有一个图片上传模块。 我想检查上传的文件是图像文件还是其他文件。 我在服务器端使用Java。
该图像在Java中被读取为BufferedImage
,然后我使用ImageIO.write()
将其写入磁盘。
我该如何检查BufferedImage
,以确保它是真正的图像而不是其他类型的文件?
任何建议或链接都将不胜感激。
在我的网站应用程序中,我有一个图片上传模块。 我想检查上传的文件是图像文件还是其他文件。 我在服务器端使用Java。
该图像在Java中被读取为BufferedImage
,然后我使用ImageIO.write()
将其写入磁盘。
我该如何检查BufferedImage
,以确保它是真正的图像而不是其他类型的文件?
任何建议或链接都将不胜感激。
ServletContext#getMimeType()
获取MIME类型(内容类型)。只需检查它是否以image/
开头即可。String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
// It's an image.
} else {
// It's not an image.
}
web.xml
文件中定义。例如,在Tomcat中,它位于/conf/web.xml
。您可以通过以下方式在您的Web应用程序的/WEB-INF/web.xml
中扩展/覆盖它:<mime-mapping>
<extension>svg</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
但是这并不能防止用户通过更改文件扩展名来欺骗您。如果您也想覆盖此问题,那么您还可以根据实际文件内容确定mime类型。如果检查only BMP、GIF、JPEG、PNG、TIFF或WBMP类型(但不包括PSD、SVG等)的成本可行,则可以直接将其提供给ImageIO#read()
并检查它是否会抛出异常。
try (InputStream input = uploadedFile.getInputStream()) {
try {
ImageIO.read(input).toString();
// It's an image (only BMP, GIF, JPEG, PNG, TIFF and WBMP are recognized).
} catch (Exception e) {
// It's not an image.
}
}
但是,如果您想涵盖更多的图像类型,那么考虑使用第三方库,该库通过检测文件签名来完成所有工作。例如Apache Tika,它不仅可以识别ImageIO
格式,还可以识别PSD、BPG、WEBP、ICNS和SVG等格式:
Tika tika = new Tika();
try (InputStream input = uploadedFile.getInputStream()) {
String mimeType = tika.detect(input);
if (mimeType.startsWith("image/")) {
// It's an image.
} else {
// It's not an image.
}
}
如果必要的话,您可以使用组合并权衡彼此。
话虽如此,您不一定需要使用ImageIO#write()
将上传的图像保存到磁盘。直接将获取的InputStream
以Java IO的方式写入Path
或任何OutputStream
(例如FileOutputStream
)即可(另请参见在servlet应用程序中保存上传文件的推荐方法):
try (InputStream input = uploadedFile.getInputStream()) {
Files.copy(input, new File(uploadFolder, fileName).toPath());
}
除非您想收集一些图像信息,例如其尺寸和/或想要对其进行操作(裁剪/调整大小/旋转/转换等)。
null
(然后toString()
将抛出NPE)。不支持的格式,如CMYK JPEG的图像实际上会抛出IOException
。 - BalusC在我的情况下,我使用了org.apache.commons.imaging.Imaging。以下是一个检查图像是否为jpeg图像的示例代码。如果上传的文件不是图像,则会抛出ImageReadException。
try {
//image is InputStream
byte[] byteArray = IOUtils.toByteArray(image);
ImageFormat mimeType = Imaging.guessFormat(byteArray);
if (mimeType == ImageFormats.JPEG) {
return;
} else {
// handle image of different format. Ex: PNG
}
} catch (ImageReadException e) {
//not an image
}
这是内置于JDK中的,只需要支持流的支持就可以了。
byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
BufferedImage
。import org.apache.http.entity.ContentType;
...
public void processImage(MultipartFile file) {
if(!Arrays.asList(ContentType.IMAGE_JPEG.getMimeType(), ContentType.IMAGE_PNG.getMimeType(), ContentType.IMAGE_GIF.getMimeType()).contains(file.getContentType())) {
throw new IllegalStateException("File must be an Image");
}
}