From fe15c444f7e6ce7318ef1fe28a7a4d3f3d44eb7a Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 7 Jul 2025 19:47:48 +0800 Subject: [PATCH] up --- gin_ops/def_config/config_temp.yaml | 30 ++++---- gin_ops/models/config.go | 4 + gin_ops/models/config_head.go | 12 +-- gin_ops/routers/routers_flie.go | 115 ++++++++++++++++++++++++---- gin_ops/templates/setting-my.html | 12 ++- 5 files changed, 133 insertions(+), 40 deletions(-) diff --git a/gin_ops/def_config/config_temp.yaml b/gin_ops/def_config/config_temp.yaml index 88a9173..aeefae4 100644 --- a/gin_ops/def_config/config_temp.yaml +++ b/gin_ops/def_config/config_temp.yaml @@ -22,7 +22,7 @@ user: avatar_path: "/static/avatars/def.png" file: - max_size_mb: 50 + max_size: 52428800 pahts: - "./data/avatar/" - "./data/upload/image/" @@ -32,26 +32,26 @@ file: - "./data/upload/other/" allow_image_mime: - - image/jpeg: true - - image/png: true - - image/gif: true - - image/bmp: true + image/jpeg: true + image/png: true + image/gif: true + image/bmp: true allow_video_mime: - - video/mp4: true - - video/x-msvideo: true - - video/quicktime: true - - video/x-flv: true - - video/mpeg: true + video/mp4: true + video/x-msvideo: true + video/quicktime: true + video/x-flv: true + video/mpeg: true allow_music_mime: - - audio/mpeg: true - - audio/aac: true - - audio/wav: true - - audio/flac: true + audio/mpeg: true + audio/aac: true + audio/wav: true + audio/flac: true allow_pdf_mime: - - application/pdf: true + application/pdf: true diff --git a/gin_ops/models/config.go b/gin_ops/models/config.go index 4802d29..3743a9c 100644 --- a/gin_ops/models/config.go +++ b/gin_ops/models/config.go @@ -52,6 +52,10 @@ func All_config_init() { if err != nil { panic(err) } + + //fmt.Println(Configs_file) + //fmt.Println(Allowed_avatar_mime) + //创建file的关键文件夹 for _, value := range Configs_file.Pahts { err := os.MkdirAll(value, 0755) diff --git a/gin_ops/models/config_head.go b/gin_ops/models/config_head.go index abcd332..f707b9a 100644 --- a/gin_ops/models/config_head.go +++ b/gin_ops/models/config_head.go @@ -17,10 +17,10 @@ type Configs_user_t struct { } type Configs_file_t struct { - Max_size_mb uint `mapstructure:"max_size_mb"` - Pahts []string `mapstructure:"pahts"` - Allow_image_mime []map[string]bool `mapstructure:"allow_image_mime"` - Allow_video_mime []map[string]bool `mapstructure:"allow_video_mime"` - Allow_music_mime []map[string]bool `mapstructure:"allow_music_mime"` - Allow_pdf_mime []map[string]bool `mapstructure:"allow_pdf_mime"` + Max_size uint64 `mapstructure:"max_size"` + Pahts []string `mapstructure:"pahts"` + Allow_image_mime map[string]bool `mapstructure:"allow_image_mime"` + Allow_video_mime map[string]bool `mapstructure:"allow_video_mime"` + Allow_music_mime map[string]bool `mapstructure:"allow_music_mime"` + Allow_pdf_mime map[string]bool `mapstructure:"allow_pdf_mime"` } diff --git a/gin_ops/routers/routers_flie.go b/gin_ops/routers/routers_flie.go index 34ec1b7..6055319 100644 --- a/gin_ops/routers/routers_flie.go +++ b/gin_ops/routers/routers_flie.go @@ -3,6 +3,14 @@ package routers //文件路由 import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "net/http" + "path" + "saas/models" + "github.com/gin-gonic/gin" ) @@ -13,40 +21,117 @@ func Router_file(r *gin.RouterGroup) { }) - //先在中间件判断有没有登录 + //先在中间件判断有没有传进cookie r.Use(func(ctx *gin.Context) { cookie_value := ctx.PostForm("cookie") //fmt.Println(cookie_value) - ctx.Set("cookie_value", cookie_value) - Use_login_from_cookie(ctx) - - //先判断有没有登录 - _, is_login := ctx.Get("user_info") - if is_login { - - } else { - Return_json(ctx, "user_no_sign", nil) + if cookie_value != "" { + ctx.Set("cookie_value", cookie_value) } + + Use_login_from_cookie(ctx) //因为需要同步前端cookie,所有只能用ctx + }) upload := r.Group("/upload") //定义上传组 //4大媒体上传接口,严格判断文件类型,可以直接被前端引用 upload.POST("/image", func(ctx *gin.Context) { - Return_json(ctx, "api_ok", nil) + + //先判断有没有登录 + user_info_any, is_login := ctx.Get("user_info") //因为需要读取user_info,避免重复调用 这一步就不在中间件操作了 + if is_login { + user_info := user_info_any.(models.User_info) //直接断言类型,这个值是从数据库直接读取的 理论不会出错 + file, err := ctx.FormFile("file") + if err == nil { + + //限制文件大小 + if file.Size > 512 { + if file.Size < int64(models.Configs_file.Max_size) { + // 2. 安全获取文件名并处理路径问题 + //filename := filepath.Base(file.Filename) // 防御性处理路径分隔符 + // 3. 获取标准后缀名(含点) + //extWithDot := filepath.Ext(filename) + + //判断文件mime是否合法 + // 打开文件流 + src_mime, _ := file.Open() + defer src_mime.Close() + // 读取前512字节用于MIME检测 + buffer := make([]byte, 512) + io.ReadFull(src_mime, buffer) + // 检测MIME类型 + mimeType := http.DetectContentType(buffer) + if models.Configs_file.Allow_image_mime[mimeType] { + // 打开文件流 + src, _ := file.Open() + defer src.Close() + // 创建SHA256哈希器 + hasher := sha256.New() + + // 计算哈希值 + io.Copy(hasher, src) + // 获取哈希结果 + hashBytes := hasher.Sum(nil) + hashString := hex.EncodeToString(hashBytes) + + new_filename := fmt.Sprintf("%d_%s", user_info.UserID, hashString) + file.Filename = new_filename + + //这是上传的真实路径 + dst := path.Join("./data/avatar", file.Filename) + + //判断文件是否存在避免重复保存 + if models.File_exists(dst) { + //fmt.Println("文件存在") + + Return_json(ctx, "api_ok", nil) + } else { + //fmt.Println("文件no存在") + ferr := ctx.SaveUploadedFile(file, dst) + if ferr == nil { + //文件保存成功 + + Return_json(ctx, "api_ok", nil) + } else { + + Return_json(ctx, "file_save_err", nil) + } + } + } else { + + Return_json(ctx, "file_mime_err", nil) + } + + } else { + + Return_json(ctx, "file_size_err", nil) + } + } else { + + Return_json(ctx, "file_size_err", nil) + } + } else { + Return_json(ctx, "file_get_err", nil) + } + + } else { + Return_json(ctx, "user_no_sign", nil) + } + }) upload.POST("/video", func(ctx *gin.Context) { - + Return_json(ctx, "api_ok", nil) }) upload.POST("/music", func(ctx *gin.Context) { - + Return_json(ctx, "api_ok", nil) }) upload.POST("/pdf", func(ctx *gin.Context) { - + Return_json(ctx, "api_ok", nil) }) //其他文件,只能通过用户报告的类型定义,不能直接被前端引用 upload.POST("/other", func(ctx *gin.Context) { - + Return_json(ctx, "api_ok", nil) }) // r.POST("/upload", func(ctx *gin.Context) { diff --git a/gin_ops/templates/setting-my.html b/gin_ops/templates/setting-my.html index e7b69fd..a3ad1e9 100644 --- a/gin_ops/templates/setting-my.html +++ b/gin_ops/templates/setting-my.html @@ -562,13 +562,17 @@ post_file("/image", blob, `avatar_${Date.now()}.jpg`, (c) => { if (c.statusCode == 200) { if (c.data.err_code == 0) { - //save_json("cookie", c.data.return.cookie) - banner_alert('success', "更换成功", 950) + + //banner_alert('success', "更换成功", 950) + showMessage(`✅ 上传成功!`, 'success'); + //avatar_toolt.hide(); } else { - banner_alert('warning', "服务错误", 3000) + showMessage(`❌ 上传失败:`+c.data.err_msg, 'error'); + //banner_alert('warning', "服务错误", 3000) } } else { - banner_alert('danger', "网络连接错误:" + c.statusCode, 3000) + //banner_alert('danger', "网络连接错误:" + c.statusCode, 3000) + showMessage(`❌ 网络连接错误:`+c.statusCode, 'error'); } })