这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天
背景
在青训营的项目开发过程中,我们遇到了需要判断上传文件的类型的需求,对于这个需求,我们队伍作了一些思考
方法
通过文件后缀名判断
第一种方法是通过文件后缀名判断文件类型。这种方法的优点是简单容易,只需要获取上传文件的文件名,然后根据文件名的最后一个点后面的字符串来判断文件类型。
但是这种方法的缺点是不够安全,因为用户可以修改文件的后缀名来欺骗系统。比如,用户可以将一个恶意的.exe文件改成.jpg文件进行上传,然后通过访问该图片链接来执行恶意代码。
简单的代码实现如下:
// 获取上传文件的文件名
filename := header.Filename
// 获取最后一个点的位置
index := strings.LastIndex(filename, ".")
// 如果没有找到点,说明没有后缀名
if index < 0 {
fmt.Println("无效的文件类型")
return
}
// 截取最后一个点后面的字符串作为后缀名
suffix := filename[index+1:]
// 根据不同的后缀名进行判断和处理
switch suffix {
case "jpg", "jpeg", "png", "gif":
fmt.Println("图片类型")
// 处理图片逻辑...
case "txt", "doc", "docx", "pdf":
fmt.Println("文档类型")
// 处理文档逻辑...
case "mp3", "wav", "ogg":
fmt.Println("音频类型")
// 处理音频逻辑...
default:
fmt.Println("不支持的文件类型")
return
}
通过Content-Type判断
第二种方法是通过Content-Type判断文件类型。这种方法是通过获取上传文件的MIME类型进行判断,MIME类型是一种标准化的方式来表示文件的内容和格式。
但是这种方法也不够安全,因为MIME类型取决于文件扩展名,而文件扩展名可能被修改。比如,用户可以将一个恶意的.exe文件改成.jpg文件进行上传,然后修改请求头中的Content-Type为image/jpeg来欺骗系统。
简单的代码实现如下:
// 获取上传文件的MIME类型
contentType := header.Header.Get("Content-Type")
// 根据不同的MIME类型进行判断和处理
switch contentType {
case "image/jpeg", "image/png", "image/gif":
fmt.Println("图片类型")
// 处理图片逻辑...
case "text/plain", "application/msword", "application/pdf":
fmt.Println("文档类型")
// 处理文档逻辑...
case "audio/mpeg", "audio/x-wav", "audio/ogg":
fmt.Println("音频类型")
// 处理音频逻辑...
default:
fmt.Println("不支持的文件类型")
return
}
通过读取文件头部的二进制编码判断
第三种方法是通过文件流判断文件头来识别文件类型。这种方法比较精准和安全,因为每种文件类型都有固定的头部编码,也就是文件的前几个字节。我们可以通过读取上传文件的前几个字节,然后转换成16进制字符串,再与已知的头部编码进行匹配,从而判断文件类型。
这种方法的优点是不容易被欺骗,因为修改文件的后缀名或者MIME类型并不会改变文件的头部编码。但是这种方法的缺点是需要维护一个头部编码和文件类型的对照表,并且可能存在一些特殊情况,比如某些文本文件没有固定的头部编码。
简单的代码实现如下:
// 获取上传文件
file, err := header.Open()
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
// 读取上传文件的前4个字节
buffer := make([]byte, 4)
_, err = file.Read(buffer)
if err != nil {
fmt.Println(err)
return
}
// 转换成16进制字符串
hexStr := hex.EncodeToString(buffer)
// 根据不同的头部编码进行判断和处理
switch hexStr {
case "ffd8ffe0", "ffd8ffe1", "ffd8ffe2":
fmt.Println("图片类型:jpg")
// 处理图片逻辑...
case "89504e47":
fmt.Println("图片类型:png")
// 处理图片逻辑...
case "47494638":
fmt.Println("图片类型:gif")
// 处理图片逻辑...
case "25504446":
fmt.Println("文档类型:pdf")
// 处理文档逻辑...
case "4944333b", "4944333a", "49443339":
fmt.Println("音频类型:mp3")
// 处理音频逻辑...
default:
fmt.Println("不支持或者未知的文件类型")
return
}