github.com/webx-top/com@v1.2.12/url.go (about)

     1  // Copyright 2013 com authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package com
    16  
    17  import (
    18  	"encoding/base64"
    19  	"math"
    20  	"net/url"
    21  	"path"
    22  	"regexp"
    23  	"strings"
    24  )
    25  
    26  // URLEncode url encode string, is + not %20
    27  func URLEncode(str string) string {
    28  	return url.QueryEscape(str)
    29  }
    30  
    31  // URLDecode url decode string
    32  func URLDecode(str string) (string, error) {
    33  	return url.QueryUnescape(str)
    34  }
    35  
    36  // RawURLEncode rawurlencode()
    37  func RawURLEncode(str string) string {
    38  	return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
    39  }
    40  
    41  // RawURLDecode rawurldecode()
    42  func RawURLDecode(str string) (string, error) {
    43  	return url.QueryUnescape(str)
    44  }
    45  
    46  // Base64Encode base64 encode
    47  func Base64Encode(str string) string {
    48  	return base64.StdEncoding.EncodeToString([]byte(str))
    49  }
    50  
    51  // Base64Decode base64 decode
    52  func Base64Decode(str string) (string, error) {
    53  	s, e := base64.StdEncoding.DecodeString(str)
    54  	return string(s), e
    55  }
    56  
    57  var urlSafeBase64EncodeReplacer = strings.NewReplacer(`/`, `_`, `+`, `-`)
    58  var urlSafeBase64DecodeReplacer = strings.NewReplacer(`_`, `/`, `-`, `+`)
    59  
    60  // URLSafeBase64 base64字符串编码为URL友好的字符串
    61  func URLSafeBase64(str string, encode bool) string {
    62  	if encode { // 编码后处理
    63  		str = strings.TrimRight(str, `=`)
    64  		str = urlSafeBase64EncodeReplacer.Replace(str)
    65  		return str
    66  	}
    67  	// 解码前处理
    68  	str = urlSafeBase64DecodeReplacer.Replace(str)
    69  	var missing = (4 - len(str)%4) % 4
    70  	if missing > 0 {
    71  		str += strings.Repeat(`=`, missing)
    72  	}
    73  	return str
    74  }
    75  
    76  // SafeBase64Encode base64 encode
    77  func SafeBase64Encode(str string) string {
    78  	str = base64.URLEncoding.EncodeToString([]byte(str))
    79  	str = strings.TrimRight(str, `=`)
    80  	return str
    81  }
    82  
    83  // SafeBase64Decode base64 decode
    84  func SafeBase64Decode(str string) (string, error) {
    85  	var missing = (4 - len(str)%4) % 4
    86  	if missing > 0 {
    87  		str += strings.Repeat(`=`, missing)
    88  	}
    89  	b, err := base64.URLEncoding.DecodeString(str)
    90  	if err != nil {
    91  		return ``, err
    92  	}
    93  	return string(b), nil
    94  }
    95  
    96  // TotalPages 总页数
    97  func TotalPages(totalRows uint, limit uint) uint {
    98  	return uint(math.Ceil(float64(totalRows) / float64(limit)))
    99  }
   100  
   101  // Offset 根据页码计算偏移值
   102  func Offset(page uint, limit uint) uint {
   103  	if page == 0 {
   104  		page = 1
   105  	}
   106  	return (page - 1) * limit
   107  }
   108  
   109  // AbsURL 获取页面内相对网址的绝对路径
   110  func AbsURL(pageURL string, relURL string) string {
   111  	if strings.Contains(relURL, `://`) {
   112  		return relURL
   113  	}
   114  	urlInfo, err := url.Parse(pageURL)
   115  	if err != nil {
   116  		return ``
   117  	}
   118  	return AbsURLx(urlInfo, relURL, true)
   119  }
   120  
   121  func AbsURLx(pageURLInfo *url.URL, relURL string, onlyRelative ...bool) string {
   122  	if (len(onlyRelative) == 0 || !onlyRelative[0]) && strings.Contains(relURL, `://`) {
   123  		return relURL
   124  	}
   125  	siteURL := pageURLInfo.Scheme + `://` + pageURLInfo.Host
   126  	if strings.HasPrefix(relURL, `/`) {
   127  		return siteURL + relURL
   128  	}
   129  	for strings.HasPrefix(relURL, `./`) {
   130  		relURL = strings.TrimPrefix(relURL, `./`)
   131  	}
   132  	urlPath := path.Dir(pageURLInfo.Path)
   133  	for strings.HasPrefix(relURL, `../`) {
   134  		urlPath = path.Dir(urlPath)
   135  		relURL = strings.TrimPrefix(relURL, `../`)
   136  	}
   137  	return siteURL + path.Join(urlPath, relURL)
   138  }
   139  
   140  func URLSeparator(pageURL string) string {
   141  	sep := `?`
   142  	if strings.Contains(pageURL, sep) {
   143  		sep = `&`
   144  	}
   145  	return sep
   146  }
   147  
   148  var localIPRegexp = regexp.MustCompile(`^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$`)
   149  
   150  // IsLocalhost 是否是本地主机
   151  func IsLocalhost(host string) bool {
   152  	switch host {
   153  	case `localhost`:
   154  		return true
   155  	case `[::1]`:
   156  		return true
   157  	default:
   158  		return localIPRegexp.MatchString(host)
   159  	}
   160  }
   161  
   162  // SplitHost localhost:8080 => localhost
   163  func SplitHost(hostport string) string {
   164  	host, _ := SplitHostPort(hostport)
   165  	return host
   166  }
   167  
   168  func SplitHostPort(hostport string) (host string, port string) {
   169  	if strings.HasSuffix(hostport, `]`) {
   170  		host = hostport
   171  		return
   172  	}
   173  	sep := `]:`
   174  	pos := strings.LastIndex(hostport, sep)
   175  	if pos > -1 {
   176  		host = hostport[0 : pos+1]
   177  		if len(hostport) > pos+2 {
   178  			port = hostport[pos+2:]
   179  		}
   180  		return
   181  	}
   182  	sep = `:`
   183  	pos = strings.LastIndex(hostport, sep)
   184  	if pos > -1 {
   185  		host = hostport[0:pos]
   186  		if len(hostport) > pos+1 {
   187  			port = hostport[pos+1:]
   188  		}
   189  		return
   190  	}
   191  	host = hostport
   192  	return
   193  }
   194  
   195  func WithURLParams(urlStr string, key string, value string, args ...string) string {
   196  	if strings.Contains(urlStr, `?`) {
   197  		urlStr += `&`
   198  	} else {
   199  		urlStr += `?`
   200  	}
   201  	urlStr += key + `=` + url.QueryEscape(value)
   202  	var k string
   203  	for i, j := 0, len(args); i < j; i++ {
   204  		if i%2 == 0 {
   205  			k = args[i]
   206  			continue
   207  		}
   208  		urlStr += `&` + k + `=` + url.QueryEscape(args[i])
   209  		k = ``
   210  	}
   211  	if len(k) > 0 {
   212  		urlStr += `&` + k + `=`
   213  	}
   214  	return urlStr
   215  }
   216  
   217  func FullURL(domianURL string, myURL string) string {
   218  	if IsFullURL(myURL) {
   219  		return myURL
   220  	}
   221  	if !strings.HasPrefix(myURL, `/`) && !strings.HasSuffix(domianURL, `/`) {
   222  		myURL = `/` + myURL
   223  	}
   224  	myURL = domianURL + myURL
   225  	return myURL
   226  }
   227  
   228  func IsFullURL(purl string) bool {
   229  	if len(purl) == 0 {
   230  		return false
   231  	}
   232  	if purl[0] == '/' {
   233  		return false
   234  	}
   235  	// find "://"
   236  	firstPos := strings.Index(purl, `/`)
   237  	if firstPos < 0 || firstPos == len(purl)-1 {
   238  		return false
   239  	}
   240  	if firstPos > 1 && purl[firstPos-1] == ':' && purl[firstPos+1] == '/' {
   241  		return true
   242  	}
   243  	return false
   244  }