web-dev-qa-db-fra.com

Comment vérifier un fichier téléchargé qu'il s'agisse d'une image ou d'un autre fichier?

Dans mon application Web, j'ai un module de téléchargement d'images. Je souhaite vérifier le fichier téléchargé, qu'il s'agisse d'un fichier image ou de tout autre fichier. J'utilise Java côté serveur.

L'image est lue comme BufferedImage dans Java puis je l'écris sur le disque avec ImageIO.write()

Comment vérifier le BufferedImage, que ce soit vraiment une image ou autre chose?

Toutes suggestions ou liens seraient appréciés.

28
user405398

Je suppose que vous exécutez cela dans un contexte de servlet. S'il est abordable de vérifier le type de contenu en fonction de l'extension du fichier, utilisez ServletContext#getMimeType() pour obtenir le type MIME (type de contenu). Vérifiez simplement s'il commence par image/.

String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
    // It's an image.
}

Les types MIME par défaut sont définis dans le web.xml Du servletcontainer en question. Dans Tomcat par exemple, il est situé dans /conf/web.xml. Vous pouvez l'étendre/le remplacer dans le /WEB-INF/web.xml De votre webapp comme suit:

<mime-mapping>
    <extension>svg</extension>
    <mime-type>image/svg+xml</mime-type>
</mime-mapping>

Mais cela ne vous empêche pas d'utilisateurs qui vous trompent en changeant l'extension de fichier. Si vous souhaitez également couvrir cela, vous pouvez également déterminer le type MIME en fonction du contenu du fichier réel . S'il est abordable de vérifier uniquement les types BMP, GIF, JPG ou PNG (mais pas TIF, PSD, SVG, etc.), vous pouvez simplement le nourrir directement dans ImageIO#read() et vérifiez s'il ne lève pas d'exception.

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.
    }
}

Mais si vous souhaitez également couvrir plus de types d'images, envisagez d'utiliser une bibliothèque tierce qui fait tout le travail en reniflant les en-têtes de fichier . Par exemple JMimeMagic ou Apache Tika qui prennent en charge à la fois BMP, GIF, JPG, PNG, TIF et PSD (mais pas SVG). Apache Batik prend en charge SVG. L'exemple ci-dessous utilise 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.
    }
}

Vous pouvez si nécessaire utiliser des combinaisons et l'emporter sur l'une et l'autre.

Cela dit, vous n'avez pas nécessairement besoin de ImageIO#write() pour enregistrer l'image téléchargée sur le disque. Il suffit d'écrire le InputStream obtenu directement dans un Path ou n'importe quel OutputStream comme FileOutputStream l'habituel Java IO est plus que suffisante (voir aussi Méthode recommandée pour enregistrer les fichiers téléchargés dans une application de servlet ):

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

À moins que vous ne souhaitiez recueillir des informations sur l'image comme ses dimensions et/ou que vous souhaitiez les manipuler (recadrer/redimensionner/faire pivoter/convertir/etc.) bien sûr.

92
BalusC

J'ai utilisé org.Apache.commons.imaging.Imaging dans mon cas. Voici un exemple de code pour vérifier si une image est une image jpeg ou non. Il lève ImageReadException si le fichier téléchargé n'est pas une image.

    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

Ceci est intégré au JDK et nécessite simplement un flux avec le support de

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