英文:
How to check if a file is a valid image?
问题
我正在构建一个网络应用程序。
在其中一个页面上,有一个上传表单,用户可以上传文件。上传完成后,我想在服务器上检查上传的文件是否为图像。
除了简单的文件扩展名检查(即不假设*.png
文件名实际上是PNG图像)之外,是否有可能进行更深入的检查?
例如,如果我编辑一个JPEG图像,在随机位置添加/编辑一个字节,使其成为无效的JPEG文件,我希望能够检测到它不再是JPEG图像。我以前使用PHP和GD库来完成这样的操作。
我想知道是否可以使用Go来实现这个功能?
英文:
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?
答案1
得分: 35
DetectContentType比手动魔术数字检查要好得多。使用方法很简单:
clientFile, _, _ := r.FormFile("img") // 或者从文件系统中获取文件
defer clientFile.Close()
buff := make([]byte, 512) // 文档中说只考虑前512个字节
if _, err = clientFile.Read(buff); err != nil {
fmt.Println(err) // 处理错误
return
}
fmt.Println(http.DetectContentType(buff)) // 根据检测结果进行相应操作。
使用这种方法,你需要知道仍然不能保证得到一个正确的文件。所以我建议对该文件进行一些图像处理(比如调整大小),以确保它确实是一个图像。
英文:
DetectContentType is way better than a manual magic number checking. The use is simple:
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.
Using this method you need to know that you still are not guaranteed to have a correct file. So I would recommend to do some image manipulation with that file (like resize it to make sure this is really an image).
答案2
得分: 23
http包可以为您完成这个任务:
func DetectContentType(data []byte) string
DetectContentType函数实现了在http://mimesniff.spec.whatwg.org/中描述的算法,用于确定给定数据的Content-Type。它最多考虑数据的前512个字节。DetectContentType始终返回一个有效的MIME类型:如果无法确定更具体的类型,则返回"application/octet-stream"。
代码:https://golang.org/src/net/http/sniff.go
英文:
The http package can do this for you:
> func DetectContentType(data []byte) string
> DetectContentType implements the algorithm described at
> http://mimesniff.spec.whatwg.org/ to determine the Content-Type of the
> given data. It considers at most the first 512 bytes of data.
> DetectContentType always returns a valid MIME type: if it cannot
> determine a more specific one, it returns "application/octet-stream".
答案3
得分: 13
通常的做法是检查文件是否具有所需的图像文件格式的正确魔数。虽然这个测试不是非常准确,但通常已经足够好了。你可以使用以下代码:
package foo
import "strings"
// 图像格式和魔数
var magicTable = map[string]string{
"\xff\xd8\xff": "image/jpeg",
"\x89PNG\r\n\x1a\n": "image/png",
"GIF87a": "image/gif",
"GIF89a": "image/gif",
}
// 从开头几个字节返回图像文件的 MIME 类型,如果文件不像已知的文件类型,则返回空字符串
func mimeFromIncipit(incipit []byte) string {
incipitStr := string(incipit)
for magic, mime := range magicTable {
if strings.HasPrefix(incipitStr, magic) {
return mime
}
}
return ""
}
英文:
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 ""
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论