gf/net/ghttp/ghttp_request_param_file.go
2022-05-23 22:09:11 +08:00

143 lines
4.4 KiB
Go

// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package ghttp
import (
"context"
"io"
"mime/multipart"
"strconv"
"strings"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
)
// UploadFile wraps the multipart uploading file with more and convenient features.
type UploadFile struct {
*multipart.FileHeader `json:"-"`
ctx context.Context
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (f UploadFile) MarshalJSON() ([]byte, error) {
return json.Marshal(f.FileHeader)
}
// UploadFiles is an array type of *UploadFile.
type UploadFiles []*UploadFile
// Save saves the single uploading file to directory path and returns the saved file name.
//
// The parameter `dirPath` should be a directory path, or it returns error.
//
// Note that it will OVERWRITE the target file if there's already a same name file exist.
func (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename string, err error) {
if f == nil {
return "", gerror.NewCode(
gcode.CodeMissingParameter,
"file is empty, maybe you retrieve it from invalid field name or form enctype",
)
}
if !gfile.Exists(dirPath) {
if err = gfile.Mkdir(dirPath); err != nil {
return
}
} else if !gfile.IsDir(dirPath) {
return "", gerror.NewCode(gcode.CodeInvalidParameter, `parameter "dirPath" should be a directory path`)
}
file, err := f.Open()
if err != nil {
err = gerror.Wrapf(err, `UploadFile.Open failed`)
return "", err
}
defer file.Close()
name := gfile.Basename(f.Filename)
if len(randomlyRename) > 0 && randomlyRename[0] {
name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
name = name + gfile.Ext(f.Filename)
}
filePath := gfile.Join(dirPath, name)
newFile, err := gfile.Create(filePath)
if err != nil {
return "", err
}
defer newFile.Close()
intlog.Printf(f.ctx, `save upload file: %s`, filePath)
if _, err = io.Copy(newFile, file); err != nil {
err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, f.Filename, filePath)
return "", err
}
return gfile.Basename(filePath), nil
}
// Save saves all uploading files to specified directory path and returns the saved file names.
//
// The parameter `dirPath` should be a directory path or it returns error.
//
// The parameter `randomlyRename` specifies whether randomly renames all the file names.
func (fs UploadFiles) Save(dirPath string, randomlyRename ...bool) (filenames []string, err error) {
if len(fs) == 0 {
return nil, gerror.NewCode(
gcode.CodeMissingParameter,
"file array is empty, maybe you retrieve it from invalid field name or form enctype",
)
}
for _, f := range fs {
if filename, err := f.Save(dirPath, randomlyRename...); err != nil {
return filenames, err
} else {
filenames = append(filenames, filename)
}
}
return
}
// GetUploadFile retrieves and returns the uploading file with specified form name.
// This function is used for retrieving single uploading file object, which is
// uploaded using multipart form content type.
//
// It returns nil if retrieving failed or no form file with given name posted.
//
// Note that the `name` is the file field name of the multipart form from client.
func (r *Request) GetUploadFile(name string) *UploadFile {
uploadFiles := r.GetUploadFiles(name)
if len(uploadFiles) > 0 {
return uploadFiles[0]
}
return nil
}
// GetUploadFiles retrieves and returns multiple uploading files with specified form name.
// This function is used for retrieving multiple uploading file objects, which are
// uploaded using multipart form content type.
//
// It returns nil if retrieving failed or no form file with given name posted.
//
// Note that the `name` is the file field name of the multipart form from client.
func (r *Request) GetUploadFiles(name string) UploadFiles {
multipartFiles := r.GetMultipartFiles(name)
if len(multipartFiles) > 0 {
uploadFiles := make(UploadFiles, len(multipartFiles))
for k, v := range multipartFiles {
uploadFiles[k] = &UploadFile{
ctx: r.Context(),
FileHeader: v,
}
}
return uploadFiles
}
return nil
}