web-dev-qa-db-ja.com

アップロードされたファイルが画像であるか他のファイルであるかを確認する方法は?

私のWebアプリケーションには、画像アップロードモジュールがあります。アップロードされたファイルが画像ファイルか他のファイルかを確認したい。サーバー側でJavaを使用しています。

イメージは、JavaでBufferedImageとして読み取られ、ImageIO.write()を使用してディスクに書き込みます。

本当に画像なのか他の何かなのか、どのようにBufferedImageをチェックするのでしょうか?

任意の提案やリンクをいただければ幸いです。

27
user405398

これをサーブレットコンテキストで実行していると仮定しています。ファイル拡張子のみに基づいてコンテンツタイプを確認するのが手頃な場合は、 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()は必要ありません。取得したInputStreamPathまたはOutputStreamのようなFileOutputStreamに直接書き込むだけで、通常のJava IO wayで十分です(アップロードされたファイルをサーブレットアプリケーションに保存する推奨方法 も参照してください ):

_try (InputStream input = uploadedFile.getInputStream()) {
    Files.copy(input, new File(uploadFolder, fileName).toPath());
}
_

もちろん、寸法などの画像情報を収集したい場合や、操作(トリミング/サイズ変更/回転/変換/その他)したい場合は除きます。

92
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
    }
3
gagan bopanna

これはJDKに組み込まれており、単に以下をサポートするストリームが必要です。

byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
2
gcstang