kra/pkg/upload/local.go

101 lines
2.2 KiB
Go

package upload
import (
"errors"
"io"
"mime/multipart"
"os"
"path/filepath"
"strings"
"sync"
"time"
"kra/pkg/utils"
)
var mu sync.Mutex
// Local 本地存储
type Local struct {
StorePath string
BasePath string
}
// NewLocal 创建本地存储
func NewLocal(storePath, basePath string) *Local {
return &Local{
StorePath: storePath,
BasePath: basePath,
}
}
// UploadFile 上传文件
func (l *Local) UploadFile(file *multipart.FileHeader) (string, string, error) {
// 读取文件后缀
ext := filepath.Ext(file.Filename)
// 读取文件名并加密
name := strings.TrimSuffix(file.Filename, ext)
name = utils.MD5V([]byte(name))
// 拼接新文件名
filename := name + "_" + time.Now().Format("20060102150405") + ext
// 尝试创建此路径
mkdirErr := os.MkdirAll(l.StorePath, os.ModePerm)
if mkdirErr != nil {
return "", "", errors.New("function os.MkdirAll() failed, err:" + mkdirErr.Error())
}
// 拼接路径和文件名
p := l.StorePath + "/" + filename
filePath := l.BasePath + "/" + filename
f, openError := file.Open() // 读取文件
if openError != nil {
return "", "", errors.New("function file.Open() failed, err:" + openError.Error())
}
defer f.Close()
out, createErr := os.Create(p)
if createErr != nil {
return "", "", errors.New("function os.Create() failed, err:" + createErr.Error())
}
defer out.Close()
_, copyErr := io.Copy(out, f) // 传输(拷贝)文件
if copyErr != nil {
return "", "", errors.New("function io.Copy() failed, err:" + copyErr.Error())
}
return filePath, filename, nil
}
// DeleteFile 删除文件
func (l *Local) DeleteFile(key string) error {
// 检查 key 是否为空
if key == "" {
return errors.New("key不能为空")
}
// 验证 key 是否包含非法字符或尝试访问存储路径之外的文件
if strings.Contains(key, "..") || strings.ContainsAny(key, `\/:*?"<>|`) {
return errors.New("非法的key")
}
p := filepath.Join(l.StorePath, key)
// 检查文件是否存在
if _, err := os.Stat(p); os.IsNotExist(err) {
return errors.New("文件不存在")
}
// 使用文件锁防止并发删除
mu.Lock()
defer mu.Unlock()
err := os.Remove(p)
if err != nil {
return errors.New("文件删除失败: " + err.Error())
}
return nil
}