-
Notifications
You must be signed in to change notification settings - Fork 0
/
web.go
141 lines (118 loc) · 3.43 KB
/
web.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Package web provides helpers to work with website.
package web
import (
"errors"
"fmt"
"github.com/choonsiong/golib/v2/stringx"
"io"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
// UploadedFile is a struct used to save information about an uploaded file.
type UploadedFile struct {
FileSize int64
NewFileName string
OriginalFileName string
}
var (
AllowedFileTypes []string
MaxUploadFileSize int
)
// UploadFiles uploads one or more files to the specified directory with
// random file names. If rename is true, then original file names are use.
func UploadFiles(r *http.Request, uploadDir string, rename ...bool) ([]*UploadedFile, error) {
renameFile := true
if len(rename) > 0 {
renameFile = rename[0]
}
var uploadedFiles []*UploadedFile
if MaxUploadFileSize == 0 {
MaxUploadFileSize = 1024 * 1024 * 1024
}
err := r.ParseMultipartForm(int64(MaxUploadFileSize))
if err != nil {
return nil, errors.New("upload file size too big")
}
for _, fileHeaders := range r.MultipartForm.File {
for _, fh := range fileHeaders {
uploadedFiles, err = func(uploadedFiles []*UploadedFile) ([]*UploadedFile, error) {
var uploadedFile UploadedFile
f, err := fh.Open()
if err != nil {
return nil, err
}
defer f.Close()
buff := make([]byte, 512)
_, err = f.Read(buff)
if err != nil {
return nil, err
}
allowed := false
fileType := http.DetectContentType(buff)
if len(AllowedFileTypes) > 0 {
for _, allowedFileType := range AllowedFileTypes {
if strings.EqualFold(fileType, allowedFileType) {
allowed = true
}
}
} else {
allowed = true
}
if !allowed {
return nil, errors.New("upload file type is not supported")
}
_, err = f.Seek(0, 0)
if err != nil {
return nil, err
}
if renameFile {
uploadedFile.NewFileName = fmt.Sprintf("%s%s", stringx.RandomStringIgnoreError(25), filepath.Ext(fh.Filename))
} else {
uploadedFile.NewFileName = fh.Filename
}
uploadedFile.OriginalFileName = fh.Filename
var outputFile *os.File
defer outputFile.Close()
if outputFile, err = os.Create(filepath.Join(uploadDir, uploadedFile.NewFileName)); err != nil {
return nil, err
} else {
fileSize, err := io.Copy(outputFile, f)
if err != nil {
return nil, err
}
uploadedFile.FileSize = fileSize
}
uploadedFiles = append(uploadedFiles, &uploadedFile)
return uploadedFiles, nil
}(uploadedFiles)
if err != nil {
return uploadedFiles, err
}
}
}
return uploadedFiles, nil
}
// UploadFile uploads one file to the specified directory with random file
// name. If rename is true, then original file name is use.
func UploadFile(r *http.Request, uploadDir string, rename ...bool) (*UploadedFile, error) {
renameFile := true
if len(rename) > 0 {
renameFile = rename[0]
}
files, err := UploadFiles(r, uploadDir, renameFile)
if err != nil {
return nil, err
}
return files[0], nil
}
// DownloadStaticFile downloads a file, and force the browser to avoid
// displaying it in the browser window by setting content disposition.
// It also allows specification of the display name.
func DownloadStaticFile(w http.ResponseWriter, r *http.Request, filePath, fileName, newFileName string) {
fp := path.Join(filePath, fileName)
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", newFileName))
http.ServeFile(w, r, fp)
}