如何检查文件是否是有效图像?

Dmi*_*pka 14 mime go

我正在构建一个Web应用程序.

在其中一个页面上有一个上传表单,用户可以在其中上传文件.上传完成后,我想检查服务器上传的文件是否为图像.

除了简单的文件扩展名检查(即不假设*.png文件名实际上是PNG图像),是否可以检查这一点?

例如,如果我编辑JPEG图像在随机位置添加/编辑一个字节以生成无效的JPEG文件,我想要检测它不再是JPEG图像.我曾经使用GD库通过PHP做过类似的事情.

我想知道Go是否可以做到?

小智 18

http包可以为您执行此操作:

func DetectContentType(data []byte) string
Run Code Online (Sandbox Code Playgroud)

DetectContentType实现http://mimesniff.spec.whatwg.org/中描述的算法, 以确定给定数据的Content-Type.它最多考虑前512个字节的数据.DetectContentType始终返回有效的MIME类型:如果它无法确定更具体的MIME类型,则返回"application/octet-stream".

代码:https://golang.org/src/net/http/sniff.go


Sal*_*ali 15

DetectContentType比手动幻数检查更好.用法很简单:

clientFile, _, _ := r.FormFile("img") // or get your file from a file system
defer clientFile.Close()
buff := make([]byte, 512) // docs tell that it take only first 512 bytes into consideration
if _, err = clientFile.Read(buff); err != nil {
     fmt.Println(err) // do something with that error
     return
}

fmt.Println(http.DetectContentType(buff)) // do something based on your detection.
Run Code Online (Sandbox Code Playgroud)

使用此方法您需要知道仍然无法保证拥有正确的文件.所以我建议用该文件进行一些图像处理(比如调整它以确保它真的是一个图像).


fuz*_*fuz 10

通常做的是检查文件是否具有所需图像文件格式的正确幻数.虽然这个测试不是非常准确,但通常都足够好.你可以使用这样的代码:

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 ""
}
Run Code Online (Sandbox Code Playgroud)

  • 确实!没有原始的安全散列,您无法检测到良性修改.但是,*如果需要*(正如您的答案所说,只是标题通常足够好)您可以检查完整数据是否代表有效图像(假设相关图像解码报告错误/无效输入错误而不仅仅是返回损坏图像没有错误;例如只要包含原始像素数据的简单图像格式只要存在正确的字节数就会很好地解码,而我希望类似JPEG解码器的东西对它的压缩输入更加挑剔. (3认同)
  • 如果由于某种原因检查标题还不够,您可以加载所有相关图像包(`image/png`、`image/gif`、`image/jpeg`、`golang.org/x/image/bmp`、等)并使用 `image.DecodeConfig` 或 [`image.Decode`](https://golang.org/pkg/image/#Decode) 并检查错误。但要小心针对解码器中的错误的恶意数据。 (2认同)