mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve uploading file feature for ghttp.Server; improve package gfile/gstr/gdebug
This commit is contained in:
@ -9,6 +9,7 @@ package ghttp
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
"github.com/gogf/gf/encoding/gurl"
|
||||
@ -302,5 +303,19 @@ func (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {
|
||||
if v := form.File[name+"[]"]; len(v) > 0 {
|
||||
return v
|
||||
}
|
||||
// Support "name[0]","name[1]","name[2]", etc. as array parameter.
|
||||
key := ""
|
||||
files := make([]*multipart.FileHeader, 0)
|
||||
for i := 0; ; i++ {
|
||||
key = fmt.Sprintf(`%s[%d]`, name, i)
|
||||
if v := form.File[key]; len(v) > 0 {
|
||||
files = append(files, v[0])
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(files) > 0 {
|
||||
return files
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ type UploadFile struct {
|
||||
// UploadFiles is array type for *UploadFile.
|
||||
type UploadFiles []*UploadFile
|
||||
|
||||
// Save saves the single uploading file to specified path.
|
||||
// Save saves the single uploading file to specified path and returns the saved file name.
|
||||
// The parameter path can be either a directory or a file path. If <path> is a directory,
|
||||
// it saves the uploading file to the directory using its original name. If <path> is a
|
||||
// file path, it saves the uploading file to the file path.
|
||||
@ -35,56 +35,61 @@ type UploadFiles []*UploadFile
|
||||
// make sense if the <path> is a directory.
|
||||
//
|
||||
// Note that it will overwrite the target file if there's already a same name file exist.
|
||||
func (f *UploadFile) Save(path string, randomlyRename ...bool) error {
|
||||
func (f *UploadFile) Save(path string, randomlyRename ...bool) (filename string, err error) {
|
||||
if f == nil {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
file, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
filePath := path
|
||||
if gfile.IsDir(path) {
|
||||
filename := gfile.Basename(f.Filename)
|
||||
name := gfile.Basename(f.Filename)
|
||||
if len(randomlyRename) > 0 && randomlyRename[0] {
|
||||
filename = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
|
||||
filename = filename + gfile.Ext(f.Filename)
|
||||
name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
|
||||
name = name + gfile.Ext(f.Filename)
|
||||
}
|
||||
filePath = gfile.Join(path, filename)
|
||||
filePath = gfile.Join(path, name)
|
||||
}
|
||||
newFile, err := gfile.Create(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
defer newFile.Close()
|
||||
intlog.Printf(`save upload file: %s`, filePath)
|
||||
if _, err := io.Copy(newFile, file); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
return nil
|
||||
return gfile.Basename(filePath), nil
|
||||
}
|
||||
|
||||
// Save saves all uploading files to specified directory path.
|
||||
// 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) error {
|
||||
func (fs UploadFiles) Save(dirPath string, randomlyRename ...bool) (filenames []string, err error) {
|
||||
if len(fs) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
if !gfile.IsDir(dirPath) {
|
||||
return errors.New(`parameter "dirPath" should be a directory path`)
|
||||
if !gfile.Exists(dirPath) {
|
||||
if err = gfile.Mkdir(dirPath); err != nil {
|
||||
return
|
||||
}
|
||||
} else if !gfile.IsDir(dirPath) {
|
||||
return nil, errors.New(`parameter "dirPath" should be a directory path`)
|
||||
}
|
||||
var err error
|
||||
for _, f := range fs {
|
||||
if err = f.Save(dirPath, randomlyRename...); err != nil {
|
||||
return err
|
||||
if filename, err := f.Save(dirPath, randomlyRename...); err != nil {
|
||||
return filenames, err
|
||||
} else {
|
||||
filenames = append(filenames, filename)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
// GetUploadFile retrieves and returns the uploading file with specified form name.
|
||||
|
||||
146
net/ghttp/ghttp_unit_param_file_test.go
Normal file
146
net/ghttp/ghttp_unit_param_file_test.go
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). 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_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Params_File_Single(t *testing.T) {
|
||||
dstDirPath := gfile.Join(gfile.TempDir(), gtime.TimestampNanoStr())
|
||||
err := gfile.Mkdir(dstDirPath)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
p := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/upload/single", func(r *ghttp.Request) {
|
||||
file := r.GetUploadFile("file")
|
||||
if file == nil {
|
||||
r.Response.WriteExit("upload file cannot be empty")
|
||||
}
|
||||
|
||||
if name, err := file.Save(dstDirPath, r.GetBool("randomlyRename")); err == nil {
|
||||
r.Response.WriteExit(name)
|
||||
}
|
||||
r.Response.WriteExit("upload failed")
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// normal name
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
srcPath := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file1.txt")
|
||||
dstPath := gfile.Join(dstDirPath, "file1.txt")
|
||||
content := client.PostContent("/upload/single", g.Map{
|
||||
"file": "@file:" + srcPath,
|
||||
})
|
||||
gtest.AssertNE(content, "")
|
||||
gtest.AssertNE(content, "upload file cannot be empty")
|
||||
gtest.AssertNE(content, "upload failed")
|
||||
gtest.Assert(content, "file1.txt")
|
||||
gtest.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))
|
||||
})
|
||||
// randomly rename.
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
srcPath := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file2.txt")
|
||||
content := client.PostContent("/upload/single", g.Map{
|
||||
"file": "@file:" + srcPath,
|
||||
"randomlyRename": true,
|
||||
})
|
||||
dstPath := gfile.Join(dstDirPath, content)
|
||||
gtest.AssertNE(content, "")
|
||||
gtest.AssertNE(content, "upload file cannot be empty")
|
||||
gtest.AssertNE(content, "upload failed")
|
||||
gtest.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_File_Batch(t *testing.T) {
|
||||
dstDirPath := gfile.Join(gfile.TempDir(), gtime.TimestampNanoStr())
|
||||
err := gfile.Mkdir(dstDirPath)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
p := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/upload/batch", func(r *ghttp.Request) {
|
||||
files := r.GetUploadFiles("file")
|
||||
if files == nil {
|
||||
r.Response.WriteExit("upload file cannot be empty")
|
||||
}
|
||||
|
||||
if names, err := files.Save(dstDirPath, r.GetBool("randomlyRename")); err == nil {
|
||||
r.Response.WriteExit(gstr.Join(names, ","))
|
||||
}
|
||||
r.Response.WriteExit("upload failed")
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// normal name
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
srcPath1 := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file1.txt")
|
||||
srcPath2 := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file2.txt")
|
||||
dstPath1 := gfile.Join(dstDirPath, "file1.txt")
|
||||
dstPath2 := gfile.Join(dstDirPath, "file2.txt")
|
||||
content := client.PostContent("/upload/batch", g.Map{
|
||||
"file[0]": "@file:" + srcPath1,
|
||||
"file[1]": "@file:" + srcPath2,
|
||||
})
|
||||
gtest.AssertNE(content, "")
|
||||
gtest.AssertNE(content, "upload file cannot be empty")
|
||||
gtest.AssertNE(content, "upload failed")
|
||||
gtest.Assert(content, "file1.txt,file2.txt")
|
||||
gtest.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))
|
||||
gtest.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))
|
||||
})
|
||||
// randomly rename.
|
||||
gtest.Case(t, func() {
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
srcPath1 := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file1.txt")
|
||||
srcPath2 := gfile.Join(gdebug.CallerDirectory(), "testdata", "upload", "file2.txt")
|
||||
content := client.PostContent("/upload/batch", g.Map{
|
||||
"file[0]": "@file:" + srcPath1,
|
||||
"file[1]": "@file:" + srcPath2,
|
||||
"randomlyRename": true,
|
||||
})
|
||||
gtest.AssertNE(content, "")
|
||||
gtest.AssertNE(content, "upload file cannot be empty")
|
||||
gtest.AssertNE(content, "upload failed")
|
||||
|
||||
array := gstr.SplitAndTrim(content, ",")
|
||||
gtest.Assert(len(array), 2)
|
||||
dstPath1 := gfile.Join(dstDirPath, array[0])
|
||||
dstPath2 := gfile.Join(dstDirPath, array[1])
|
||||
gtest.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))
|
||||
gtest.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))
|
||||
})
|
||||
}
|
||||
1
net/ghttp/testdata/upload/file1.txt
vendored
Normal file
1
net/ghttp/testdata/upload/file1.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
file1.txt: This file is for uploading unit test case.
|
||||
1
net/ghttp/testdata/upload/file2.txt
vendored
Normal file
1
net/ghttp/testdata/upload/file2.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
file2.txt: This file is for uploading unit test case.
|
||||
Reference in New Issue
Block a user