package zciyon import ( "io" "mime/multipart" "net/http" "regexp" "strings" ) const ( CIYPOST_ALLOW_TEXT = 0 //禁止任何html代码 CIYPOST_ALLOW_HTML = 1 //允许合法html代码,但不允许js脚本 CIYPOST_ALLOW_ALL = 2 //全部放行 ) type CiyPost struct { kv map[string]any W http.ResponseWriter R *http.Request err error } func NewCiyPost(w http.ResponseWriter, r *http.Request) *CiyPost { post := &CiyPost{} post.W = w post.R = r post.kv = map[string]any{} if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") { err := r.ParseMultipartForm(1024 * 5) //1024 * 1024 * 1024 * if err != nil { post.err = err } else { for k, v := range r.Form { post.kv[k] = v[0] } if r.MultipartForm != nil && r.MultipartForm.File != nil { for k, files := range r.MultipartForm.File { post.kv[k] = files[0] } } } } else if r.Method == "POST" { body, err := io.ReadAll(r.Body) if err != nil { post.err = err } else { post.kv = Byte_JSON(body) if len(post.kv) == 0 { post.kv = map[string]any{"body": string(body)} } } } for k, v := range r.URL.Query() { post.kv[k] = v[0] } if len(post.kv) == 0 { post.kv[""] = r.URL.RawQuery } return post } func (thos *CiyPost) Is(key string) bool { _, ok := thos.kv[key] return ok } func (thos *CiyPost) Getany(key string) any { return thos.kv[key] } func (thos *CiyPost) Getobj(key string) map[string]any { if arr, ok := thos.kv[key].(map[string]any); ok { return arr } return map[string]any{} } func (thos *CiyPost) Getint(key string, argdef ...int) int { return Toint(thos.kv[key], argdef...) } func (thos *CiyPost) Getfloat(key string, argdef ...float64) float64 { return Tofloat(thos.kv[key], argdef...) } func (thos *CiyPost) Getbool(key string, argdef ...bool) bool { return Tobool(thos.kv[key], argdef...) } func (thos *CiyPost) Getdate(key string) int { return Tostamp(Tostr(thos.kv[key])) } func (thos *CiyPost) GetIP() string { xForwardedFor := thos.R.Header.Get("X-Forwarded-For") if xForwardedFor != "" { return strings.TrimSpace(strings.Split(xForwardedFor, ",")[0]) } xRealIP := thos.R.Header.Get("X-Real-IP") if xRealIP != "" { return xRealIP } return thos.R.RemoteAddr } func (thos *CiyPost) IsWeixin() bool { useragent := thos.R.Header.Get("HTTP_USER_AGENT") useragent = strings.ToLower(useragent) return strings.Contains(useragent, "micromessenger") } func (thos *CiyPost) Get(key string, args ...any) string { allow := CIYPOST_ALLOW_TEXT defval := "" for _, arg := range args { switch v := arg.(type) { case int: allow = v case string: defval = v } } str := Tostr(thos.kv[key]) if allow == CIYPOST_ALLOW_TEXT { str = strings.TrimSpace(thos.triptotext(str)) } else if allow == CIYPOST_ALLOW_HTML { str = thos.triptohtml(str) //str = template.HTMLEscapeString(str) //str = template.JSEscapeString(str) } if str == "" { return defval } return str } func (thos *CiyPost) Gets(key string, args ...any) []string { allow := CIYPOST_ALLOW_TEXT for _, arg := range args { switch v := arg.(type) { case int: allow = v } } switch v := thos.kv[key].(type) { case []any: strs := make([]string, len(v)) for i, s := range v { str := Tostr(s) if allow == CIYPOST_ALLOW_TEXT { str = strings.TrimSpace(thos.triptotext(str)) } else if allow == CIYPOST_ALLOW_HTML { str = thos.triptohtml(str) } strs[i] = str } return strs } return []string{""} } func (thos *CiyPost) Getfile(argkey ...string) *multipart.FileHeader { key := "" if len(argkey) > 0 { key = argkey[0] } if key != "" { switch v := thos.kv[key].(type) { case *multipart.FileHeader: return v } } else { for _, kv := range thos.kv { switch v := kv.(type) { case *multipart.FileHeader: return v } } } return nil } func (thos *CiyPost) triptotext(str string) string { //去掉所有html标签和控制字符 re, _ := regexp.Compile(`\<[\S\s]+?\>`) //标签小写 str = re.ReplaceAllStringFunc(str, strings.ToLower) re, _ = regexp.Compile(`\`) //删除style str = re.ReplaceAllString(str, "") re, _ = regexp.Compile(`\`) //删除script str = re.ReplaceAllString(str, "") re, _ = regexp.Compile(`\<[\S\s]+?\>`) //删除标签 str = re.ReplaceAllString(str, "") return str } func (thos *CiyPost) triptohtml(str string) string { //保留html标签和style属性。去掉所有事件、style、script re, _ := regexp.Compile(`\<[\S\s]+?\>`) //标签小写 str = re.ReplaceAllStringFunc(str, strings.ToLower) re, _ = regexp.Compile(`\`) //删除style str = re.ReplaceAllString(str, "") re, _ = regexp.Compile(`\`) //删除script str = re.ReplaceAllString(str, "") reOnEvent := regexp.MustCompile(` on\w+="[^"]*"`) //删除双引号事件 str = reOnEvent.ReplaceAllString(str, "") reOnEvent2 := regexp.MustCompile(` on\w+='[^"]*'`) //删除单引号事件 str = reOnEvent2.ReplaceAllString(str, "") reOnEvent3 := regexp.MustCompile(` on\w+=`) //破坏事件代码 str = reOnEvent3.ReplaceAllString(str, " ") return str }