utils.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. package utils
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "database/sql"
  6. "encoding/hex"
  7. "fmt"
  8. "html/template"
  9. "math"
  10. "mime/quotedprintable"
  11. "net/http"
  12. "net/smtp"
  13. "os"
  14. "regexp"
  15. "strconv"
  16. "strings"
  17. "time"
  18. "unicode/utf16"
  19. "golang-fave/engine/assets"
  20. "golang-fave/engine/consts"
  21. )
  22. func Trim(str string) string {
  23. return strings.TrimSpace(str)
  24. }
  25. func IsFileExists(filename string) bool {
  26. if _, err := os.Stat(filename); !os.IsNotExist(err) {
  27. if err == nil {
  28. return true
  29. }
  30. }
  31. return false
  32. }
  33. func IsRegularFileExists(filename string) bool {
  34. if st, err := os.Stat(filename); !os.IsNotExist(err) {
  35. if err == nil {
  36. if !st.Mode().IsDir() {
  37. return true
  38. }
  39. }
  40. }
  41. return false
  42. }
  43. func IsDir(filename string) bool {
  44. if st, err := os.Stat(filename); !os.IsNotExist(err) {
  45. if err == nil {
  46. if st.Mode().IsDir() {
  47. return true
  48. }
  49. }
  50. }
  51. return false
  52. }
  53. func IsDirExists(path string) bool {
  54. if IsFileExists(path) && IsDir(path) {
  55. return true
  56. }
  57. return false
  58. }
  59. func IsNumeric(str string) bool {
  60. if _, err := strconv.Atoi(str); err == nil {
  61. return true
  62. }
  63. return false
  64. }
  65. func IsFloat(str string) bool {
  66. if _, err := strconv.ParseFloat(str, 64); err == nil {
  67. return true
  68. }
  69. return false
  70. }
  71. func IsValidMobile(str string) bool {
  72. regexpeChars := regexp.MustCompile(`^\+([0-9]{7,18})$`)
  73. return regexpeChars.MatchString(str)
  74. }
  75. func IsValidEmail(email string) bool {
  76. regexpe := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
  77. return regexpe.MatchString(email)
  78. }
  79. func IsValidAlias(alias string) bool {
  80. // Control panel
  81. regexpeCP := regexp.MustCompile(`^\/cp\/`)
  82. if alias == "/cp" || regexpeCP.MatchString(alias) {
  83. return false
  84. }
  85. // Blog module
  86. regexpeBlog := regexp.MustCompile(`^\/blog\/`)
  87. if alias == "/blog" || regexpeBlog.MatchString(alias) {
  88. return false
  89. }
  90. // Shop module
  91. regexpeShop := regexp.MustCompile(`^\/shop\/`)
  92. if alias == "/shop" || regexpeShop.MatchString(alias) {
  93. return false
  94. }
  95. // API module
  96. regexpeApi := regexp.MustCompile(`^\/api\/`)
  97. if alias == "/api" || regexpeApi.MatchString(alias) {
  98. return false
  99. }
  100. regexpeSlash := regexp.MustCompile(`[\/]{2,}`)
  101. regexpeChars := regexp.MustCompile(`^\/([a-zA-Z0-9\/\-_\.]+)\/?$`)
  102. return (!regexpeSlash.MatchString(alias) && regexpeChars.MatchString(alias)) || alias == "/"
  103. }
  104. func IsValidSingleAlias(alias string) bool {
  105. regexpeChars := regexp.MustCompile(`^([a-zA-Z0-9\-_]{1,})$`)
  106. return regexpeChars.MatchString(alias)
  107. }
  108. func FixPath(path string) string {
  109. newPath := strings.TrimSpace(path)
  110. if len(newPath) <= 0 {
  111. return newPath
  112. }
  113. if newPath[len(newPath)-1] == '/' || newPath[len(newPath)-1] == '\\' {
  114. newPath = newPath[0 : len(newPath)-1]
  115. }
  116. return newPath
  117. }
  118. func ExtractHostPort(host string, https bool) (string, string) {
  119. h := host
  120. p := "80"
  121. if https {
  122. p = "443"
  123. }
  124. i := strings.Index(h, ":")
  125. if i > -1 {
  126. p = h[i+1:]
  127. h = h[0:i]
  128. }
  129. return h, p
  130. }
  131. func GetFileSize(filename string) int64 {
  132. if st, err := os.Stat(filename); !os.IsNotExist(err) {
  133. if err == nil {
  134. if !st.Mode().IsDir() {
  135. return st.Size()
  136. }
  137. }
  138. }
  139. return 0
  140. }
  141. func GetAssetsUrl(filename string) string {
  142. return "/" + filename + "?v=" + consts.ServerVersion
  143. }
  144. func GetTmplSystemData(cpmod, cpsubmod string) consts.TmplSystem {
  145. return consts.TmplSystem{
  146. CpSubModule: cpsubmod,
  147. InfoVersion: consts.ServerVersion,
  148. PathCssBootstrap: GetAssetsUrl(consts.AssetsBootstrapCss),
  149. PathCssCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorCss),
  150. PathCssCpStyles: GetAssetsUrl(consts.AssetsCpStylesCss),
  151. PathCssCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellCss),
  152. PathCssLightGallery: GetAssetsUrl(consts.AssetsLightGalleryCss),
  153. PathCssStyles: GetAssetsUrl(consts.AssetsSysStylesCss),
  154. PathIcoFav: GetAssetsUrl(consts.AssetsSysFaveIco),
  155. PathJsBootstrap: GetAssetsUrl(consts.AssetsBootstrapJs),
  156. PathJsCpCodeMirror: GetAssetsUrl(consts.AssetsCpCodeMirrorJs),
  157. PathJsCpScripts: GetAssetsUrl(consts.AssetsCpScriptsJs),
  158. PathJsCpWysiwygPell: GetAssetsUrl(consts.AssetsCpWysiwygPellJs),
  159. PathJsJquery: GetAssetsUrl(consts.AssetsJqueryJs),
  160. PathJsLightGallery: GetAssetsUrl(consts.AssetsLightGalleryJs),
  161. PathJsPopper: GetAssetsUrl(consts.AssetsPopperJs),
  162. PathSvgLogo: GetAssetsUrl(consts.AssetsSysLogoSvg),
  163. PathThemeScripts: "/assets/theme/scripts.js?v=" + consts.ServerVersion,
  164. PathThemeStyles: "/assets/theme/styles.css?v=" + consts.ServerVersion,
  165. CpModule: cpmod,
  166. }
  167. }
  168. func GetTmplError(err error) consts.TmplError {
  169. return consts.TmplError{
  170. ErrorMessage: err.Error(),
  171. }
  172. }
  173. func GetMd5(str string) string {
  174. hasher := md5.New()
  175. hasher.Write([]byte(str))
  176. return hex.EncodeToString(hasher.Sum(nil))
  177. }
  178. func GetCurrentUnixTimestamp() int64 {
  179. return int64(time.Now().Unix())
  180. }
  181. func SystemRenderTemplate(w http.ResponseWriter, c []byte, d interface{}, cpmod, cpsubmod string) {
  182. tmpl, err := template.New("template").Parse(string(c))
  183. if err != nil {
  184. SystemErrorPageEngine(w, err)
  185. return
  186. }
  187. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  188. w.Header().Set("Content-Type", "text/html")
  189. tmpl.Execute(w, consts.TmplData{
  190. System: GetTmplSystemData(cpmod, cpsubmod),
  191. Data: d,
  192. })
  193. }
  194. func SystemErrorPageEngine(w http.ResponseWriter, err error) {
  195. if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorEngine)); e == nil {
  196. w.WriteHeader(http.StatusInternalServerError)
  197. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  198. w.Header().Set("Content-Type", "text/html")
  199. tmpl.Execute(w, consts.TmplData{
  200. System: GetTmplSystemData("error", "engine"),
  201. Data: GetTmplError(err),
  202. })
  203. return
  204. }
  205. w.WriteHeader(http.StatusInternalServerError)
  206. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  207. w.Header().Set("Content-Type", "text/html")
  208. w.Write([]byte("<h1>Critical engine error</h1>"))
  209. w.Write([]byte("<h2>" + err.Error() + "</h2>"))
  210. }
  211. func SystemErrorPageTemplate(w http.ResponseWriter, err error) {
  212. if tmpl, e := template.New("template").Parse(string(assets.TmplPageErrorTmpl)); e == nil {
  213. w.WriteHeader(http.StatusInternalServerError)
  214. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  215. w.Header().Set("Content-Type", "text/html")
  216. tmpl.Execute(w, consts.TmplData{
  217. System: GetTmplSystemData("error", "template"),
  218. Data: GetTmplError(err),
  219. })
  220. return
  221. }
  222. w.WriteHeader(http.StatusInternalServerError)
  223. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  224. w.Header().Set("Content-Type", "text/html")
  225. w.Write([]byte("<h1>Critical engine error</h1>"))
  226. w.Write([]byte("<h2>" + err.Error() + "</h2>"))
  227. }
  228. func SystemErrorPage404(w http.ResponseWriter) {
  229. tmpl, err := template.New("template").Parse(string(assets.TmplPageError404))
  230. if err != nil {
  231. SystemErrorPageEngine(w, err)
  232. return
  233. }
  234. w.WriteHeader(http.StatusNotFound)
  235. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  236. w.Header().Set("Content-Type", "text/html")
  237. tmpl.Execute(w, consts.TmplData{
  238. System: GetTmplSystemData("error", "404"),
  239. Data: nil,
  240. })
  241. }
  242. func UrlToArray(url string) []string {
  243. url_buff := url
  244. // Remove GET parameters
  245. i := strings.Index(url_buff, "?")
  246. if i > -1 {
  247. url_buff = url_buff[:i]
  248. }
  249. // Cut slashes
  250. if len(url_buff) >= 1 && url_buff[:1] == "/" {
  251. url_buff = url_buff[1:]
  252. }
  253. if len(url_buff) >= 1 && url_buff[len(url_buff)-1:] == "/" {
  254. url_buff = url_buff[:len(url_buff)-1]
  255. }
  256. // Explode
  257. if url_buff == "" {
  258. return []string{}
  259. } else {
  260. return strings.Split(url_buff, "/")
  261. }
  262. }
  263. func IntToStr(num int) string {
  264. return fmt.Sprintf("%d", num)
  265. }
  266. func Int64ToStr(num int64) string {
  267. return fmt.Sprintf("%d", num)
  268. }
  269. func StrToInt(str string) int {
  270. num, err := strconv.Atoi(str)
  271. if err == nil {
  272. return num
  273. }
  274. return 0
  275. }
  276. func Float64ToStr(num float64) string {
  277. return fmt.Sprintf("%.2f", num)
  278. }
  279. func Float64ToStrF(num float64, format string) string {
  280. return fmt.Sprintf(format, num)
  281. }
  282. func StrToFloat64(str string) float64 {
  283. num, err := strconv.ParseFloat(str, 64)
  284. if err == nil {
  285. return num
  286. }
  287. return 0
  288. }
  289. func GenerateAlias(str string) string {
  290. if str == "" {
  291. return ""
  292. }
  293. strc := utf16.Encode([]rune(str))
  294. lat := []string{"EH", "I", "i", "#", "eh", "A", "B", "V", "G", "D", "E", "JO", "ZH", "Z", "I", "JJ", "K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "F", "KH", "C", "CH", "SH", "SHH", "'", "Y", "", "EH", "YU", "YA", "a", "b", "v", "g", "d", "e", "jo", "zh", "z", "i", "jj", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "f", "kh", "c", "ch", "sh", "shh", "", "y", "", "eh", "yu", "ya", "", "", "-", "-", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "-", "-", ":", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M"}
  295. cyr := []string{"Є", "І", "і", "№", "є", "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", "З", "И", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "Ь", "Э", "Ю", "Я", "а", "б", "в", "г", "д", "е", "ё", "ж", "з", "и", "й", "к", "л", "м", "н", "о", "п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ы", "ь", "э", "ю", "я", "«", "»", "—", " ", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "", "", "a", "s", "d", "f", "g", "h", "j", "k", "l", "", "", "z", "x", "c", "v", "b", "n", "m", "", "", "", "(", ")", "", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M"}
  296. var alias string = ""
  297. for i := 0; i < len(strc); i++ {
  298. for j := 0; j < len(cyr); j++ {
  299. if string(strc[i]) == cyr[j] {
  300. alias += lat[j]
  301. }
  302. }
  303. }
  304. alias = strings.ToLower(alias)
  305. // Cut repeated chars "-"
  306. if reg, err := regexp.Compile("[\\-]+"); err == nil {
  307. alias = strings.Trim(reg.ReplaceAllString(alias, "-"), "-")
  308. }
  309. alias = "/" + alias + "/"
  310. // Cut repeated chars "/"
  311. if reg, err := regexp.Compile("[/]+"); err == nil {
  312. alias = reg.ReplaceAllString(alias, "/")
  313. }
  314. return alias
  315. }
  316. func GenerateSingleAlias(str string) string {
  317. alias := GenerateAlias(str)
  318. if len(alias) > 1 && alias[0] == '/' {
  319. alias = alias[1:]
  320. }
  321. if len(alias) > 1 && alias[len(alias)-1] == '/' {
  322. alias = alias[:len(alias)-1]
  323. }
  324. return alias
  325. }
  326. func UnixTimestampToMySqlDateTime(sec int64) string {
  327. return time.Unix(sec, 0).Format("2006-01-02 15:04:05")
  328. }
  329. func UnixTimestampToFormat(sec int64, format string) string {
  330. return time.Unix(sec, 0).Format(format)
  331. }
  332. func ExtractGetParams(str string) string {
  333. i := strings.Index(str, "?")
  334. if i == -1 {
  335. return ""
  336. }
  337. return "?" + str[i+1:]
  338. }
  339. func JavaScriptVarValue(str string) string {
  340. return strings.Replace(
  341. strings.Replace(str, `'`, `&rsquo;`, -1),
  342. `"`,
  343. `&rdquo;`,
  344. -1,
  345. )
  346. }
  347. func InArrayInt(slice []int, value int) bool {
  348. for _, item := range slice {
  349. if item == value {
  350. return true
  351. }
  352. }
  353. return false
  354. }
  355. func InArrayString(slice []string, value string) bool {
  356. for _, item := range slice {
  357. if item == value {
  358. return true
  359. }
  360. }
  361. return false
  362. }
  363. func GetPostArrayInt(name string, r *http.Request) []int {
  364. var ids []int
  365. if arr, ok := r.PostForm[name]; ok {
  366. for _, el := range arr {
  367. if IsNumeric(el) {
  368. if !InArrayInt(ids, StrToInt(el)) {
  369. ids = append(ids, StrToInt(el))
  370. }
  371. }
  372. }
  373. }
  374. return ids
  375. }
  376. func GetPostArrayString(name string, r *http.Request) []string {
  377. var ids []string
  378. if arr, ok := r.PostForm[name]; ok {
  379. for _, el := range arr {
  380. if !InArrayString(ids, el) {
  381. ids = append(ids, el)
  382. }
  383. }
  384. }
  385. return ids
  386. }
  387. func ArrayOfIntToArrayOfString(arr []int) []string {
  388. var res []string
  389. for _, el := range arr {
  390. res = append(res, IntToStr(el))
  391. }
  392. return res
  393. }
  394. func ArrayOfStringToArrayOfInt(arr []string) []int {
  395. var res []int
  396. for _, el := range arr {
  397. if IsNumeric(el) {
  398. res = append(res, StrToInt(el))
  399. }
  400. }
  401. return res
  402. }
  403. func TemplateAdditionalFuncs() template.FuncMap {
  404. return template.FuncMap{
  405. "plus": func(a, b int) int {
  406. return a + b
  407. },
  408. "minus": func(a, b int) int {
  409. return a - b
  410. },
  411. "multiply": func(a, b int) int {
  412. return a * b
  413. },
  414. "divide": func(a, b int) int {
  415. return a / b
  416. },
  417. "repeat": func(a string, n int) template.HTML {
  418. out := ""
  419. for i := 1; i <= n; i++ {
  420. out += a
  421. }
  422. return template.HTML(out)
  423. },
  424. }
  425. }
  426. func SqlNullStringToString(arr *[]sql.NullString) *[]string {
  427. values := make([]string, len(*arr))
  428. for key, value := range *arr {
  429. values[key] = value.String
  430. }
  431. return &values
  432. }
  433. func GetImagePlaceholderSrc() string {
  434. return "/" + consts.AssetsSysPlaceholderPng
  435. }
  436. func FormatProductPrice(price float64, format, round int) string {
  437. p := price
  438. if round == 1 {
  439. p = math.Ceil(p)
  440. } else if round == 2 {
  441. p = math.Floor(p)
  442. }
  443. if format == 1 {
  444. return Float64ToStrF(p, "%.1f")
  445. } else if format == 2 {
  446. return Float64ToStrF(p, "%.2f")
  447. } else if format == 3 {
  448. return Float64ToStrF(p, "%.3f")
  449. } else if format == 4 {
  450. return Float64ToStrF(p, "%.4f")
  451. }
  452. return Float64ToStrF(p, "%.0f")
  453. }
  454. func SMTPSend(host, port, user, pass, subject, msg string, receivers []string) error {
  455. header := make(map[string]string)
  456. header["From"] = user
  457. header["To"] = strings.Join(receivers, ", ")
  458. header["Subject"] = subject
  459. header["MIME-Version"] = "1.0"
  460. header["Content-Type"] = fmt.Sprintf("%s; charset=\"utf-8\"", "text/html")
  461. header["Content-Transfer-Encoding"] = "quoted-printable"
  462. header["Content-Disposition"] = "inline"
  463. message := ""
  464. for key, value := range header {
  465. message += fmt.Sprintf("%s: %s\r\n", key, value)
  466. }
  467. var encodedMessage bytes.Buffer
  468. finalMessage := quotedprintable.NewWriter(&encodedMessage)
  469. finalMessage.Write([]byte(msg))
  470. finalMessage.Close()
  471. message += "\r\n" + encodedMessage.String()
  472. return smtp.SendMail(
  473. host+":"+port,
  474. smtp.PlainAuth("", user, pass, host),
  475. user,
  476. receivers,
  477. []byte(message),
  478. )
  479. }
  480. func SafeFilePath(path string) string {
  481. result := path
  482. if reg, err := regexp.Compile("([/]+\\.\\.)|(\\.\\.[/]+)"); err == nil {
  483. result = reg.ReplaceAllString(result, "/")
  484. }
  485. if reg, err := regexp.Compile("([/]+[\\.]+[/]+)"); err == nil {
  486. result = reg.ReplaceAllString(result, "/")
  487. }
  488. if reg, err := regexp.Compile("([/]+)"); err == nil {
  489. result = reg.ReplaceAllString(result, "/")
  490. }
  491. return result
  492. }
  493. func IsValidTemplateFileName(str string) bool {
  494. regexpeChars := regexp.MustCompile(`^[0-9A-Za-z-]+$`)
  495. return regexpeChars.MatchString(str)
  496. }