Golang如何从base64解码后的字节切片获取文件扩展名
解决方案
现有方案失效原因
你用到的通用文件类型检测库识别粒度不足,核心问题集中在两类高频格式:
.doc/.xls属于OLE2复合文件格式,通用检测只会返回通用OLE类型,不会细分是Word还是Excel文件.docx/.xlsx属于ZIP打包的OOXML格式,通用检测只会识别为ZIP压缩包,需要读取ZIP内部结构才能区分具体文档类型- 部分检测库默认设置了匹配字节长度限制,大文件头部信息读取不全也会导致匹配失败
替换实现方案
下面是纯Go无额外依赖的自定义检测实现,直接替换你原来的filetype.Match相关代码即可,覆盖你提到的所有格式:
首先新增需要导入的包:
import ( "archive/zip" "bytes" "fmt" "strings" )
替换后的业务代码:
// 配置支持的文件类型规则,可按需扩展 var fileTypeRules = []struct { ext string magic []byte offset int }{ {ext: "wav", magic: []byte("RIFF"), offset: 0}, {ext: "mp4", magic: []byte{0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70}, offset: 0}, {ext: "ogg", magic: []byte("OggS"), offset: 0}, // OLE复合文件通用魔数,后续二次判断细分 {ext: "ole", magic: []byte{0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1}, offset: 0}, // ZIP/OOXML通用魔数,后续二次判断细分 {ext: "zip", magic: []byte("PK"), offset: 0}, } var ext string var matchErr = fmt.Errorf("unsupported file type") // 第一轮基础魔数匹配 for _, rule := range fileTypeRules { if len(contents) < rule.offset+len(rule.magic) { continue } if bytes.Equal(contents[rule.offset:rule.offset+len(rule.magic)], rule.magic) { switch rule.ext { case "ole": // 二次判断OLE类型是doc还是xls if bytes.Contains(contents[:512], []byte("Word.Document")) { ext = "doc" } else if bytes.Contains(contents[:512], []byte("Excel.Sheet")) { ext = "xls" } case "zip": // 二次判断ZIP是docx还是xlsx r, err := zip.NewReader(bytes.NewReader(contents), int64(len(contents))) if err == nil { for _, f := range r.File { if strings.HasPrefix(f.Name, "word/") { ext = "docx" break } if strings.HasPrefix(f.Name, "xl/") { ext = "xlsx" break } } } default: ext = rule.ext } if ext != "" { matchErr = nil break } } } if matchErr != nil { service.logger.Println(matchErr) return nil, echo.NewHTTPError(http.StatusBadRequest, map[string]interface{}{ "description": "Unknown extension given.", "reason": matchErr.Error(), }) }
后续生成文件名的代码直接替换kind.Extension为ext即可:
filename := fmt.Sprintf( "%s.%s", uuid.New().String(), ext, )
补充优化建议
- 如需支持更多格式,只需在
fileTypeRules中添加对应文件的魔数和偏移量即可 - 如果不想自行维护规则,可使用
mimetype库,调用mimetype.SetLimit(0)取消匹配长度限制,再手动添加OLE、OOXML的细分匹配规则即可 - 对文件类型校验要求极高的场景,可以在检测到扩展名后,调用对应格式的解析库做二次合法性校验,避免恶意构造的文件绕过魔数检测
内容的提问来源于stack exchange,提问作者nrgx
相关产品推荐
相关产品推荐

