Search code examples
gomime

How to check if a file is a valid image?


I am building a web application.

On one of the pages there is an upload form, where user can upload a file. After the upload is done, I want to check on the server if the uploaded file is an image.

Is it possible to check this beyond simple file extension checking (i.e. not assuming that a *.png filename is actually a PNG image)?

For example, if I edit a JPEG image adding/editing a byte in a random place to make an invalid JPEG file, I want to detect that it is not a JPEG image anymore. I used to do such type of thing via PHP some time ago, using a GD library.

I would like to know if it is possible to do with Go?


Solution

  • What is usually done is checking if the file has the right magic number for the image file format you want. While this test is not super accurate, it is usually good enough. You can use code like this:

    package foo
    
    import "strings"
    
    // image formats and magic numbers
    var magicTable = map[string]string{
        "\xff\xd8\xff":      "image/jpeg",
        "\x89PNG\r\n\x1a\n": "image/png",
        "GIF87a":            "image/gif",
        "GIF89a":            "image/gif",
    }
    
    // mimeFromIncipit returns the mime type of an image file from its first few
    // bytes or the empty string if the file does not look like a known file type
    func mimeFromIncipit(incipit []byte) string {
        incipitStr := []byte(incipit)
        for magic, mime := range magicTable {
            if strings.HasPrefix(incipitStr, magic) {
                return mime
            }
        }
    
        return ""
    }