私のWebアプリケーションには、画像アップロードモジュールがあります。アップロードされたファイルが画像ファイルか他のファイルかを確認したい。サーバー側で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.
}
_
デフォルトのMIMEタイプは、問題のservletcontainerの_web.xml
_で定義されています。たとえばTomcatでは、_/conf/web.xml
_にあります。次のように、webappの_/WEB-INF/web.xml
_で拡張/オーバーライドできます:
_<mime-mapping>
<extension>svg</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
_
しかし、これはファイル拡張子を変更することであなたをだましているユーザーを防ぐことはできません。これもカバーしたい場合は、actualファイルの内容に基づいてMIMEタイプを決定することもできます。 BMP、GIF、JPG、またはPNGタイプ(TIF、PSD、SVGなどではない)のみをチェックするのが手頃な場合は、 ImageIO#read()
例外をスローしないかどうかを確認します。
_try (InputStream input = uploadedFile.getInputStream()) {
try {
ImageIO.read(input).toString();
// It's an image (only BMP, GIF, JPG and PNG are recognized).
} catch (Exception e) {
// It's not an image.
}
}
_
しかし、より多くの画像タイプもカバーしたい場合は、 ファイルヘッダーをスニッフィングすることですべての作業を行うサードパーティライブラリの使用を検討してください 。たとえば、 JMimeMagic または Apache Tika は、BMP、GIF、JPG、PNG、TIF、およびPSDの両方をサポートします(SVGはサポートしません)。 Apache Batik はSVGをサポートしています。以下の例では、JMimeMagicを使用しています。
_try (InputStream input = uploadedFile.getInputStream()) {
String mimeType = Magic.getMagicMatch(input, false).getMimeType();
if (mimeType.startsWith("image/")) {
// It's an image.
} else {
// It's not an image.
}
}
_
必要に応じて組み合わせを使用し、一方と他方を上回ることができます。
そうは言っても、アップロードされた画像をディスクに保存するのに、必ずしもImageIO#write()
は必要ありません。取得したInputStream
をPath
またはOutputStream
のようなFileOutputStream
に直接書き込むだけで、通常のJava IO wayで十分です(アップロードされたファイルをサーブレットアプリケーションに保存する推奨方法 も参照してください ):
_try (InputStream input = uploadedFile.getInputStream()) {
Files.copy(input, new File(uploadFolder, fileName).toPath());
}
_
もちろん、寸法などの画像情報を収集したい場合や、操作(トリミング/サイズ変更/回転/変換/その他)したい場合は除きます。
私の場合は 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