commit
e175faed7e
30 changed files with 2545 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||||||
|
# Default ignored files |
||||||
|
/shelf/ |
||||||
|
/workspace.xml |
||||||
|
# Editor-based HTTP Client requests |
||||||
|
/httpRequests/ |
||||||
|
# Datasource local storage ignored files |
||||||
|
/dataSources/ |
||||||
|
/dataSources.local.xml |
@ -0,0 +1,9 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<module type="WEB_MODULE" version="4"> |
||||||
|
<component name="Go" enabled="true" /> |
||||||
|
<component name="NewModuleRootManager"> |
||||||
|
<content url="file://$MODULE_DIR$" /> |
||||||
|
<orderEntry type="inheritedJdk" /> |
||||||
|
<orderEntry type="sourceFolder" forTests="false" /> |
||||||
|
</component> |
||||||
|
</module> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="MarkdownSettingsMigration"> |
||||||
|
<option name="stateVersion" value="1" /> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="ProjectModuleManager"> |
||||||
|
<modules> |
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/go-common.iml" filepath="$PROJECT_DIR$/.idea/go-common.iml" /> |
||||||
|
</modules> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,32 @@ |
|||||||
|
package captcha |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mojocn/base64Captcha" |
||||||
|
) |
||||||
|
|
||||||
|
func GetCaptcha() (string, string) { |
||||||
|
//config struct for Character
|
||||||
|
//字符,公式,验证码配置
|
||||||
|
var configC = base64Captcha.ConfigCharacter{ |
||||||
|
Height: 30, |
||||||
|
Width: 80, |
||||||
|
//const CaptchaModeNumber:数字,CaptchaModeAlphabet:字母,CaptchaModeArithmetic:算术,CaptchaModeNumberAlphabet:数字字母混合.
|
||||||
|
Mode: base64Captcha.CaptchaModeNumber, |
||||||
|
ComplexOfNoiseText: base64Captcha.CaptchaComplexLower, |
||||||
|
ComplexOfNoiseDot: base64Captcha.CaptchaComplexLower, |
||||||
|
IsUseSimpleFont: true, |
||||||
|
IsShowHollowLine: false, |
||||||
|
IsShowNoiseDot: false, |
||||||
|
IsShowNoiseText: false, |
||||||
|
IsShowSlimeLine: false, |
||||||
|
IsShowSineLine: false, |
||||||
|
CaptchaLen: 4, |
||||||
|
} |
||||||
|
idKeyC, capC := base64Captcha.GenerateCaptcha("", configC) |
||||||
|
base64stringC := base64Captcha.CaptchaWriteToBase64Encoding(capC) |
||||||
|
return idKeyC, base64stringC |
||||||
|
} |
||||||
|
|
||||||
|
func Verify(idKey, verifyValue string) bool { |
||||||
|
return base64Captcha.VerifyCaptcha(idKey, verifyValue) |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
package consumer |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/nsqio/go-nsq" |
||||||
|
"sync" |
||||||
|
) |
||||||
|
|
||||||
|
type baseConsumerService struct { |
||||||
|
consumers []*BaseConsumer |
||||||
|
} |
||||||
|
|
||||||
|
func New() *baseConsumerService { |
||||||
|
return &baseConsumerService{ |
||||||
|
consumers: []*BaseConsumer{}, |
||||||
|
} |
||||||
|
} |
||||||
|
func (s *baseConsumerService) Register(b *BaseConsumer) { |
||||||
|
s.consumers = append(s.consumers, b) |
||||||
|
} |
||||||
|
func (s *baseConsumerService) Run() error { |
||||||
|
for _, v := range s.consumers { |
||||||
|
if err := v.Run(); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *baseConsumerService) Stop() error { |
||||||
|
for _, v := range s.consumers { |
||||||
|
if err := v.Stop(); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type BaseConsumer struct { |
||||||
|
host, topic, consumerChan string |
||||||
|
wg *sync.WaitGroup |
||||||
|
consumer *nsq.Consumer |
||||||
|
} |
||||||
|
|
||||||
|
func (s *BaseConsumer) Stop() error { |
||||||
|
s.consumer.Stop() |
||||||
|
s.wg.Wait() |
||||||
|
return nil |
||||||
|
} |
||||||
|
func (s *BaseConsumer) Run() error { |
||||||
|
return s.consumer.ConnectToNSQD(s.host) |
||||||
|
} |
||||||
|
|
||||||
|
func NewBaseConsumer(host, topic, consumerChan string, fun func(msg *nsq.Message) error) *BaseConsumer { |
||||||
|
resp := &BaseConsumer{ |
||||||
|
wg: &sync.WaitGroup{}, |
||||||
|
consumer: nil, |
||||||
|
host: host, |
||||||
|
topic: topic, |
||||||
|
consumerChan: consumerChan, |
||||||
|
} |
||||||
|
consumer, err := nsq.NewConsumer(topic, consumerChan, nsq.NewConfig()) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
consumer.AddHandler(nsq.HandlerFunc(func(msg *nsq.Message) error { |
||||||
|
resp.wg.Add(1) |
||||||
|
defer resp.wg.Done() |
||||||
|
return fun(msg) |
||||||
|
})) |
||||||
|
resp.consumer = consumer |
||||||
|
return resp |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
module git.diulo.com/mogfee/go-common |
||||||
|
|
||||||
|
go 1.20 |
||||||
|
|
||||||
|
require ( |
||||||
|
github.com/PuerkitoBio/goquery v1.8.1 |
||||||
|
github.com/gin-gonic/gin v1.9.0 |
||||||
|
github.com/mojocn/base64Captcha v1.2.2 |
||||||
|
github.com/nsqio/go-nsq v1.1.0 |
||||||
|
github.com/pkg/errors v0.9.1 |
||||||
|
) |
||||||
|
|
||||||
|
require ( |
||||||
|
github.com/andybalholm/cascadia v1.3.1 // indirect |
||||||
|
github.com/bytedance/sonic v1.8.0 // indirect |
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect |
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect |
||||||
|
github.com/go-playground/locales v0.14.1 // indirect |
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect |
||||||
|
github.com/go-playground/validator/v10 v10.11.2 // indirect |
||||||
|
github.com/goccy/go-json v0.10.0 // indirect |
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect |
||||||
|
github.com/golang/snappy v0.0.1 // indirect |
||||||
|
github.com/json-iterator/go v1.1.12 // indirect |
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect |
||||||
|
github.com/leodido/go-urn v1.2.1 // indirect |
||||||
|
github.com/mattn/go-isatty v0.0.17 // indirect |
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect |
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect |
||||||
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect |
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect |
||||||
|
github.com/ugorji/go/codec v1.2.9 // indirect |
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect |
||||||
|
golang.org/x/crypto v0.5.0 // indirect |
||||||
|
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75 // indirect |
||||||
|
golang.org/x/net v0.7.0 // indirect |
||||||
|
golang.org/x/sys v0.5.0 // indirect |
||||||
|
golang.org/x/text v0.7.0 // indirect |
||||||
|
google.golang.org/protobuf v1.28.1 // indirect |
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect |
||||||
|
) |
@ -0,0 +1,124 @@ |
|||||||
|
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= |
||||||
|
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= |
||||||
|
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= |
||||||
|
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= |
||||||
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= |
||||||
|
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= |
||||||
|
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= |
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= |
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= |
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= |
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= |
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= |
||||||
|
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= |
||||||
|
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= |
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= |
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= |
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= |
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= |
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= |
||||||
|
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= |
||||||
|
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= |
||||||
|
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= |
||||||
|
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= |
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= |
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= |
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= |
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= |
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= |
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= |
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= |
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= |
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= |
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= |
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= |
||||||
|
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= |
||||||
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= |
||||||
|
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= |
||||||
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= |
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= |
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= |
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= |
||||||
|
github.com/mojocn/base64Captcha v1.2.2 h1:NTFnThPVrb3tR66JO/N8/ZHsyFrNc7ho+xRpxBUEIlo= |
||||||
|
github.com/mojocn/base64Captcha v1.2.2/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY= |
||||||
|
github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE= |
||||||
|
github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= |
||||||
|
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= |
||||||
|
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= |
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||||
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= |
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= |
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= |
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= |
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= |
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= |
||||||
|
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= |
||||||
|
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= |
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= |
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= |
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= |
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= |
||||||
|
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= |
||||||
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= |
||||||
|
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75 h1:TbGuee8sSq15Iguxu4deQ7+Bqq/d2rsQejGcEtADAMQ= |
||||||
|
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= |
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= |
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
||||||
|
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= |
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= |
||||||
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= |
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= |
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= |
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= |
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= |
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= |
||||||
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= |
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= |
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= |
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= |
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= |
||||||
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= |
||||||
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= |
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= |
@ -0,0 +1,7 @@ |
|||||||
|
package php_session_decoder |
||||||
|
|
||||||
|
import "git.diulo.com/mogfee/go-common/php_session_decoder/php_serialize" |
||||||
|
|
||||||
|
const SEPARATOR_VALUE_NAME rune = '|' |
||||||
|
|
||||||
|
type PhpSession map[string]php_serialize.PhpValue |
@ -0,0 +1,66 @@ |
|||||||
|
package php_session_decoder |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"git.diulo.com/mogfee/go-common/php_session_decoder/php_serialize" |
||||||
|
"io" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
type PhpDecoder struct { |
||||||
|
source *strings.Reader |
||||||
|
decoder *php_serialize.UnSerializer |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhpDecoder(phpSession string) *PhpDecoder { |
||||||
|
decoder := &PhpDecoder{ |
||||||
|
source: strings.NewReader(phpSession), |
||||||
|
decoder: php_serialize.NewUnSerializer(""), |
||||||
|
} |
||||||
|
decoder.decoder.SetReader(decoder.source) |
||||||
|
return decoder |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpDecoder) SetSerializedDecodeFunc(f php_serialize.SerializedDecodeFunc) { |
||||||
|
self.decoder.SetSerializedDecodeFunc(f) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpDecoder) Decode() (PhpSession, error) { |
||||||
|
var ( |
||||||
|
name string |
||||||
|
err error |
||||||
|
value php_serialize.PhpValue |
||||||
|
) |
||||||
|
res := make(PhpSession) |
||||||
|
|
||||||
|
for { |
||||||
|
if name, err = self.readName(); err != nil { |
||||||
|
break |
||||||
|
} |
||||||
|
if value, err = self.decoder.Decode(); err != nil { |
||||||
|
break |
||||||
|
} |
||||||
|
res[name] = value |
||||||
|
} |
||||||
|
|
||||||
|
if err == io.EOF { |
||||||
|
err = nil |
||||||
|
} |
||||||
|
return res, err |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpDecoder) readName() (string, error) { |
||||||
|
var ( |
||||||
|
token rune |
||||||
|
err error |
||||||
|
) |
||||||
|
buf := bytes.NewBuffer([]byte{}) |
||||||
|
for { |
||||||
|
if token, _, err = self.source.ReadRune(); err != nil || token == SEPARATOR_VALUE_NAME { |
||||||
|
break |
||||||
|
} else { |
||||||
|
buf.WriteRune(token) |
||||||
|
} |
||||||
|
} |
||||||
|
return buf.String(), err |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package php_session_decoder |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"fmt" |
||||||
|
"git.diulo.com/mogfee/go-common/php_session_decoder/php_serialize" |
||||||
|
) |
||||||
|
|
||||||
|
type PhpEncoder struct { |
||||||
|
data PhpSession |
||||||
|
encoder *php_serialize.Serializer |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhpEncoder(data PhpSession) *PhpEncoder { |
||||||
|
return &PhpEncoder{ |
||||||
|
data: data, |
||||||
|
encoder: php_serialize.NewSerializer(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpEncoder) SetSerializedEncodeFunc(f php_serialize.SerializedEncodeFunc) { |
||||||
|
self.encoder.SetSerializedEncodeFunc(f) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpEncoder) Encode() (string, error) { |
||||||
|
if self.data == nil { |
||||||
|
return "", nil |
||||||
|
} |
||||||
|
var ( |
||||||
|
err error |
||||||
|
val string |
||||||
|
) |
||||||
|
buf := bytes.NewBuffer([]byte{}) |
||||||
|
|
||||||
|
for k, v := range self.data { |
||||||
|
buf.WriteString(k) |
||||||
|
buf.WriteRune(SEPARATOR_VALUE_NAME) |
||||||
|
if val, err = self.encoder.Encode(v); err != nil { |
||||||
|
err = fmt.Errorf("php_session: error during encode value for %q: %v", k, err) |
||||||
|
break |
||||||
|
} |
||||||
|
buf.WriteString(val) |
||||||
|
} |
||||||
|
|
||||||
|
return buf.String(), err |
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
package php_serialize |
||||||
|
|
||||||
|
const ( |
||||||
|
TOKEN_NULL rune = 'N' |
||||||
|
TOKEN_BOOL rune = 'b' |
||||||
|
TOKEN_INT rune = 'i' |
||||||
|
TOKEN_FLOAT rune = 'd' |
||||||
|
TOKEN_STRING rune = 's' |
||||||
|
TOKEN_ARRAY rune = 'a' |
||||||
|
TOKEN_OBJECT rune = 'O' |
||||||
|
TOKEN_OBJECT_SERIALIZED rune = 'C' |
||||||
|
TOKEN_REFERENCE rune = 'R' |
||||||
|
TOKEN_REFERENCE_OBJECT rune = 'r' |
||||||
|
TOKEN_SPL_ARRAY rune = 'x' |
||||||
|
TOKEN_SPL_ARRAY_MEMBERS rune = 'm' |
||||||
|
|
||||||
|
SEPARATOR_VALUE_TYPE rune = ':' |
||||||
|
SEPARATOR_VALUES rune = ';' |
||||||
|
|
||||||
|
DELIMITER_STRING_LEFT rune = '"' |
||||||
|
DELIMITER_STRING_RIGHT rune = '"' |
||||||
|
DELIMITER_OBJECT_LEFT rune = '{' |
||||||
|
DELIMITER_OBJECT_RIGHT rune = '}' |
||||||
|
|
||||||
|
FORMATTER_FLOAT byte = 'g' |
||||||
|
FORMATTER_PRECISION int = 17 |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
debugMode = false |
||||||
|
) |
||||||
|
|
||||||
|
func Debug(value bool) { |
||||||
|
debugMode = value |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhpObject(className string) *PhpObject { |
||||||
|
return &PhpObject{ |
||||||
|
className: className, |
||||||
|
members: PhpArray{}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type SerializedDecodeFunc func(string) (PhpValue, error) |
||||||
|
|
||||||
|
type SerializedEncodeFunc func(PhpValue) (string, error) |
||||||
|
|
||||||
|
type PhpValue interface{} |
||||||
|
|
||||||
|
type PhpArray map[PhpValue]PhpValue |
||||||
|
|
||||||
|
type PhpSlice []PhpValue |
||||||
|
|
||||||
|
type PhpObject struct { |
||||||
|
className string |
||||||
|
members PhpArray |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) GetClassName() string { |
||||||
|
return self.className |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) SetClassName(name string) *PhpObject { |
||||||
|
self.className = name |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) GetMembers() PhpArray { |
||||||
|
return self.members |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) SetMembers(members PhpArray) *PhpObject { |
||||||
|
self.members = members |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) GetPrivate(name string) (v PhpValue, ok bool) { |
||||||
|
v, ok = self.members["\x00"+self.className+"\x00"+name] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) SetPrivate(name string, value PhpValue) *PhpObject { |
||||||
|
self.members["\x00"+self.className+"\x00"+name] = value |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) GetProtected(name string) (v PhpValue, ok bool) { |
||||||
|
v, ok = self.members["\x00*\x00"+name] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) SetProtected(name string, value PhpValue) *PhpObject { |
||||||
|
self.members["\x00*\x00"+name] = value |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) GetPublic(name string) (v PhpValue, ok bool) { |
||||||
|
v, ok = self.members[name] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObject) SetPublic(name string, value PhpValue) *PhpObject { |
||||||
|
self.members[name] = value |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhpObjectSerialized(className string) *PhpObjectSerialized { |
||||||
|
return &PhpObjectSerialized{ |
||||||
|
className: className, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type PhpObjectSerialized struct { |
||||||
|
className string |
||||||
|
data string |
||||||
|
value PhpValue |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) GetClassName() string { |
||||||
|
return self.className |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) SetClassName(name string) *PhpObjectSerialized { |
||||||
|
self.className = name |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) GetData() string { |
||||||
|
return self.data |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) SetData(data string) *PhpObjectSerialized { |
||||||
|
self.data = data |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) GetValue() PhpValue { |
||||||
|
return self.value |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpObjectSerialized) SetValue(value PhpValue) *PhpObjectSerialized { |
||||||
|
self.value = value |
||||||
|
return self |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhpSplArray(array, properties PhpValue) *PhpSplArray { |
||||||
|
if array == nil { |
||||||
|
array = make(PhpArray) |
||||||
|
} |
||||||
|
|
||||||
|
if properties == nil { |
||||||
|
properties = make(PhpArray) |
||||||
|
} |
||||||
|
|
||||||
|
return &PhpSplArray{ |
||||||
|
array: array, |
||||||
|
properties: properties, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type PhpSplArray struct { |
||||||
|
flags int |
||||||
|
array PhpValue |
||||||
|
properties PhpValue |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) GetFlags() int { |
||||||
|
return self.flags |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) SetFlags(value int) { |
||||||
|
self.flags = value |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) GetArray() PhpValue { |
||||||
|
return self.array |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) SetArray(value PhpValue) { |
||||||
|
self.array = value |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) GetProperties() PhpValue { |
||||||
|
return self.properties |
||||||
|
} |
||||||
|
|
||||||
|
func (self *PhpSplArray) SetProperties(value PhpValue) { |
||||||
|
self.properties = value |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package php_serialize |
||||||
|
|
||||||
|
import ( |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
func PhpValueString(p PhpValue) (res string) { |
||||||
|
res, _ = p.(string) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueBool(p PhpValue) (res bool) { |
||||||
|
switch v := p.(type) { |
||||||
|
case bool: |
||||||
|
res = v |
||||||
|
case string: |
||||||
|
res, _ = strconv.ParseBool(v) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueInt(p PhpValue) (res int) { |
||||||
|
switch intVal := p.(type) { |
||||||
|
case int: |
||||||
|
res = intVal |
||||||
|
case int8: |
||||||
|
res = int(intVal) |
||||||
|
case int16: |
||||||
|
res = int(intVal) |
||||||
|
case int32: |
||||||
|
res = int(intVal) |
||||||
|
case int64: |
||||||
|
res = int(intVal) |
||||||
|
case uint: |
||||||
|
res = int(intVal) |
||||||
|
case uint8: |
||||||
|
res = int(intVal) |
||||||
|
case uint16: |
||||||
|
res = int(intVal) |
||||||
|
case uint32: |
||||||
|
res = int(intVal) |
||||||
|
case uint64: |
||||||
|
res = int(intVal) |
||||||
|
case string: |
||||||
|
str, _ := p.(string) |
||||||
|
res, _ = strconv.Atoi(str) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueInt64(p PhpValue) (res int64) { |
||||||
|
switch v := p.(type) { |
||||||
|
case int64: |
||||||
|
res = v |
||||||
|
default: |
||||||
|
res = int64(PhpValueInt(v)) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueUInt(p PhpValue) (res uint) { |
||||||
|
switch v := p.(type) { |
||||||
|
case uint: |
||||||
|
res = v |
||||||
|
default: |
||||||
|
res = uint(PhpValueInt(v)) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueUInt64(p PhpValue) (res uint64) { |
||||||
|
switch v := p.(type) { |
||||||
|
case uint64: |
||||||
|
res = v |
||||||
|
default: |
||||||
|
res = uint64(PhpValueInt(v)) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func PhpValueFloat64(p PhpValue) (res float64) { |
||||||
|
switch v := p.(type) { |
||||||
|
case float64: |
||||||
|
res = v |
||||||
|
case string: |
||||||
|
res, _ = strconv.ParseFloat(v, 64) |
||||||
|
default: |
||||||
|
return float64(PhpValueInt(p)) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
@ -0,0 +1,264 @@ |
|||||||
|
package php_serialize |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"fmt" |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
func Serialize(v PhpValue) (string, error) { |
||||||
|
encoder := NewSerializer() |
||||||
|
encoder.SetSerializedEncodeFunc(SerializedEncodeFunc(Serialize)) |
||||||
|
return encoder.Encode(v) |
||||||
|
} |
||||||
|
|
||||||
|
type Serializer struct { |
||||||
|
lastErr error |
||||||
|
encodeFunc SerializedEncodeFunc |
||||||
|
} |
||||||
|
|
||||||
|
func NewSerializer() *Serializer { |
||||||
|
return &Serializer{} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) SetSerializedEncodeFunc(f SerializedEncodeFunc) { |
||||||
|
self.encodeFunc = f |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) Encode(v PhpValue) (string, error) { |
||||||
|
var value bytes.Buffer |
||||||
|
|
||||||
|
switch t := v.(type) { |
||||||
|
default: |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unknown type %T with value %#v", t, v)) |
||||||
|
case nil: |
||||||
|
value = self.encodeNull() |
||||||
|
case bool: |
||||||
|
value = self.encodeBool(v) |
||||||
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: |
||||||
|
value = self.encodeNumber(v) |
||||||
|
case string: |
||||||
|
value = self.encodeString(v, DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, true) |
||||||
|
case PhpArray, map[PhpValue]PhpValue, PhpSlice: |
||||||
|
value = self.encodeArray(v, true) |
||||||
|
case *PhpObject: |
||||||
|
value = self.encodeObject(v) |
||||||
|
case *PhpObjectSerialized: |
||||||
|
value = self.encodeSerialized(v) |
||||||
|
case *PhpSplArray: |
||||||
|
value = self.encodeSplArray(v) |
||||||
|
} |
||||||
|
|
||||||
|
return value.String(), self.lastErr |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeNull() (buffer bytes.Buffer) { |
||||||
|
buffer.WriteRune(TOKEN_NULL) |
||||||
|
buffer.WriteRune(SEPARATOR_VALUES) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeBool(v PhpValue) (buffer bytes.Buffer) { |
||||||
|
buffer.WriteRune(TOKEN_BOOL) |
||||||
|
buffer.WriteRune(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
if bVal, ok := v.(bool); ok && bVal { |
||||||
|
buffer.WriteString("1") |
||||||
|
} else { |
||||||
|
buffer.WriteString("0") |
||||||
|
} |
||||||
|
|
||||||
|
buffer.WriteRune(SEPARATOR_VALUES) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeNumber(v PhpValue) (buffer bytes.Buffer) { |
||||||
|
var val string |
||||||
|
|
||||||
|
isFloat := false |
||||||
|
|
||||||
|
switch intVal := v.(type) { |
||||||
|
default: |
||||||
|
val = "0" |
||||||
|
case int: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int8: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int16: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int32: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int64: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case uint: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint8: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint16: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint32: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint64: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
// PHP has precision = 17 by default
|
||||||
|
case float32: |
||||||
|
val = strconv.FormatFloat(float64(intVal), FORMATTER_FLOAT, FORMATTER_PRECISION, 32) |
||||||
|
isFloat = true |
||||||
|
case float64: |
||||||
|
val = strconv.FormatFloat(float64(intVal), FORMATTER_FLOAT, FORMATTER_PRECISION, 64) |
||||||
|
isFloat = true |
||||||
|
} |
||||||
|
|
||||||
|
if isFloat { |
||||||
|
buffer.WriteRune(TOKEN_FLOAT) |
||||||
|
} else { |
||||||
|
buffer.WriteRune(TOKEN_INT) |
||||||
|
} |
||||||
|
|
||||||
|
buffer.WriteRune(SEPARATOR_VALUE_TYPE) |
||||||
|
buffer.WriteString(val) |
||||||
|
buffer.WriteRune(SEPARATOR_VALUES) |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeString(v PhpValue, left, right rune, isFinal bool) (buffer bytes.Buffer) { |
||||||
|
val, _ := v.(string) |
||||||
|
|
||||||
|
if isFinal { |
||||||
|
buffer.WriteRune(TOKEN_STRING) |
||||||
|
} |
||||||
|
|
||||||
|
buffer.WriteString(self.prepareLen(len(val))) |
||||||
|
buffer.WriteRune(left) |
||||||
|
buffer.WriteString(val) |
||||||
|
buffer.WriteRune(right) |
||||||
|
|
||||||
|
if isFinal { |
||||||
|
buffer.WriteRune(SEPARATOR_VALUES) |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeArray(v PhpValue, isFinal bool) (buffer bytes.Buffer) { |
||||||
|
var ( |
||||||
|
arrLen int |
||||||
|
s string |
||||||
|
) |
||||||
|
|
||||||
|
if isFinal { |
||||||
|
buffer.WriteRune(TOKEN_ARRAY) |
||||||
|
} |
||||||
|
|
||||||
|
switch arrVal := v.(type) { |
||||||
|
case PhpArray: |
||||||
|
arrLen = len(arrVal) |
||||||
|
buffer.WriteString(self.prepareLen(arrLen)) |
||||||
|
buffer.WriteRune(DELIMITER_OBJECT_LEFT) |
||||||
|
|
||||||
|
for k, v := range arrVal { |
||||||
|
s, _ = self.Encode(k) |
||||||
|
buffer.WriteString(s) |
||||||
|
s, _ = self.Encode(v) |
||||||
|
buffer.WriteString(s) |
||||||
|
} |
||||||
|
|
||||||
|
case map[PhpValue]PhpValue: |
||||||
|
arrLen = len(arrVal) |
||||||
|
|
||||||
|
buffer.WriteString(self.prepareLen(arrLen)) |
||||||
|
buffer.WriteRune(DELIMITER_OBJECT_LEFT) |
||||||
|
|
||||||
|
for k, v := range arrVal { |
||||||
|
s, _ = self.Encode(k) |
||||||
|
buffer.WriteString(s) |
||||||
|
s, _ = self.Encode(v) |
||||||
|
buffer.WriteString(s) |
||||||
|
} |
||||||
|
case PhpSlice: |
||||||
|
arrLen = len(arrVal) |
||||||
|
|
||||||
|
buffer.WriteString(self.prepareLen(arrLen)) |
||||||
|
buffer.WriteRune(DELIMITER_OBJECT_LEFT) |
||||||
|
|
||||||
|
for k, v := range arrVal { |
||||||
|
s, _ = self.Encode(k) |
||||||
|
buffer.WriteString(s) |
||||||
|
s, _ = self.Encode(v) |
||||||
|
buffer.WriteString(s) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
buffer.WriteRune(DELIMITER_OBJECT_RIGHT) |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeObject(v PhpValue) (buffer bytes.Buffer) { |
||||||
|
obj, _ := v.(*PhpObject) |
||||||
|
buffer.WriteRune(TOKEN_OBJECT) |
||||||
|
buffer.WriteString(self.prepareClassName(obj.className)) |
||||||
|
encoded := self.encodeArray(obj.members, false) |
||||||
|
buffer.WriteString(encoded.String()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeSerialized(v PhpValue) (buffer bytes.Buffer) { |
||||||
|
var serialized string |
||||||
|
|
||||||
|
obj, _ := v.(*PhpObjectSerialized) |
||||||
|
buffer.WriteRune(TOKEN_OBJECT_SERIALIZED) |
||||||
|
buffer.WriteString(self.prepareClassName(obj.className)) |
||||||
|
|
||||||
|
if self.encodeFunc == nil { |
||||||
|
serialized = obj.GetData() |
||||||
|
} else { |
||||||
|
var err error |
||||||
|
if serialized, err = self.encodeFunc(obj.GetValue()); err != nil { |
||||||
|
self.saveError(err) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
encoded := self.encodeString(serialized, DELIMITER_OBJECT_LEFT, DELIMITER_OBJECT_RIGHT, false) |
||||||
|
buffer.WriteString(encoded.String()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) encodeSplArray(v PhpValue) bytes.Buffer { |
||||||
|
var buffer bytes.Buffer |
||||||
|
obj, _ := v.(*PhpSplArray) |
||||||
|
|
||||||
|
buffer.WriteRune(TOKEN_SPL_ARRAY) |
||||||
|
buffer.WriteRune(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
encoded := self.encodeNumber(obj.flags) |
||||||
|
buffer.WriteString(encoded.String()) |
||||||
|
|
||||||
|
data, _ := self.Encode(obj.array) |
||||||
|
buffer.WriteString(data) |
||||||
|
|
||||||
|
buffer.WriteRune(SEPARATOR_VALUES) |
||||||
|
buffer.WriteRune(TOKEN_SPL_ARRAY_MEMBERS) |
||||||
|
buffer.WriteRune(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
data, _ = self.Encode(obj.properties) |
||||||
|
buffer.WriteString(data) |
||||||
|
|
||||||
|
return buffer |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) prepareLen(l int) string { |
||||||
|
return string(SEPARATOR_VALUE_TYPE) + strconv.Itoa(l) + string(SEPARATOR_VALUE_TYPE) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) prepareClassName(name string) string { |
||||||
|
encoded := self.encodeString(name, DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, false) |
||||||
|
return encoded.String() |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Serializer) saveError(err error) { |
||||||
|
if self.lastErr == nil { |
||||||
|
self.lastErr = err |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,315 @@ |
|||||||
|
package php_serialize |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"fmt" |
||||||
|
"log" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
const UNSERIALIZABLE_OBJECT_MAX_LEN = 10 * 1024 * 1024 * 1024 |
||||||
|
|
||||||
|
func UnSerialize(s string) (PhpValue, error) { |
||||||
|
decoder := NewUnSerializer(s) |
||||||
|
decoder.SetSerializedDecodeFunc(SerializedDecodeFunc(UnSerialize)) |
||||||
|
return decoder.Decode() |
||||||
|
} |
||||||
|
|
||||||
|
type UnSerializer struct { |
||||||
|
source string |
||||||
|
r *strings.Reader |
||||||
|
lastErr error |
||||||
|
decodeFunc SerializedDecodeFunc |
||||||
|
} |
||||||
|
|
||||||
|
func NewUnSerializer(data string) *UnSerializer { |
||||||
|
return &UnSerializer{ |
||||||
|
source: data, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) SetReader(r *strings.Reader) { |
||||||
|
self.r = r |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) SetSerializedDecodeFunc(f SerializedDecodeFunc) { |
||||||
|
self.decodeFunc = f |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) Decode() (PhpValue, error) { |
||||||
|
if self.r == nil { |
||||||
|
self.r = strings.NewReader(self.source) |
||||||
|
} |
||||||
|
|
||||||
|
var value PhpValue |
||||||
|
|
||||||
|
if token, _, err := self.r.ReadRune(); err == nil { |
||||||
|
switch token { |
||||||
|
default: |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unknown token %#U", token)) |
||||||
|
case TOKEN_NULL: |
||||||
|
value = self.decodeNull() |
||||||
|
case TOKEN_BOOL: |
||||||
|
value = self.decodeBool() |
||||||
|
case TOKEN_INT: |
||||||
|
value = self.decodeNumber(false) |
||||||
|
case TOKEN_FLOAT: |
||||||
|
value = self.decodeNumber(true) |
||||||
|
case TOKEN_STRING: |
||||||
|
value = self.decodeString(DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, true) |
||||||
|
case TOKEN_ARRAY: |
||||||
|
value = self.decodeArray() |
||||||
|
case TOKEN_OBJECT: |
||||||
|
value = self.decodeObject() |
||||||
|
case TOKEN_OBJECT_SERIALIZED: |
||||||
|
value = self.decodeSerialized() |
||||||
|
case TOKEN_REFERENCE, TOKEN_REFERENCE_OBJECT: |
||||||
|
value = self.decodeReference() |
||||||
|
case TOKEN_SPL_ARRAY: |
||||||
|
value = self.decodeSplArray() |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return value, self.lastErr |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeNull() PhpValue { |
||||||
|
self.expect(SEPARATOR_VALUES) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeBool() PhpValue { |
||||||
|
var ( |
||||||
|
raw rune |
||||||
|
err error |
||||||
|
) |
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
if raw, _, err = self.r.ReadRune(); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading bool value: %v", err)) |
||||||
|
} |
||||||
|
|
||||||
|
self.expect(SEPARATOR_VALUES) |
||||||
|
return raw == '1' |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeNumber(isFloat bool) PhpValue { |
||||||
|
var ( |
||||||
|
raw string |
||||||
|
err error |
||||||
|
val PhpValue |
||||||
|
) |
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
if raw, err = self.readUntil(SEPARATOR_VALUES); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading number value: %v", err)) |
||||||
|
} else { |
||||||
|
if isFloat { |
||||||
|
if val, err = strconv.ParseFloat(raw, 64); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to float: %v", raw, err)) |
||||||
|
} |
||||||
|
} else { |
||||||
|
if val, err = strconv.Atoi(raw); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to int: %v", raw, err)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeString(left, right rune, isFinal bool) PhpValue { |
||||||
|
var ( |
||||||
|
err error |
||||||
|
val PhpValue |
||||||
|
strLen int |
||||||
|
readLen int |
||||||
|
) |
||||||
|
|
||||||
|
strLen = self.readLen() |
||||||
|
self.expect(left) |
||||||
|
|
||||||
|
if strLen > 0 { |
||||||
|
buf := make([]byte, strLen) |
||||||
|
if readLen, err = self.r.Read(buf); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading string value: %v", err)) |
||||||
|
} else { |
||||||
|
if readLen != strLen { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unable to read string. Expected %d but have got %d bytes", strLen, readLen)) |
||||||
|
} else { |
||||||
|
val = string(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
self.expect(right) |
||||||
|
if isFinal { |
||||||
|
self.expect(SEPARATOR_VALUES) |
||||||
|
} |
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeArray() PhpValue { |
||||||
|
var arrLen int |
||||||
|
val := make(PhpArray) |
||||||
|
|
||||||
|
arrLen = self.readLen() |
||||||
|
self.expect(DELIMITER_OBJECT_LEFT) |
||||||
|
|
||||||
|
for i := 0; i < arrLen; i++ { |
||||||
|
k, errKey := self.Decode() |
||||||
|
v, errVal := self.Decode() |
||||||
|
|
||||||
|
if errKey == nil && errVal == nil { |
||||||
|
val[k] = v |
||||||
|
/*switch t := k.(type) { |
||||||
|
default: |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unexpected key type %T", t)) |
||||||
|
case string: |
||||||
|
stringKey, _ := k.(string) |
||||||
|
val[stringKey] = v |
||||||
|
case int: |
||||||
|
intKey, _ := k.(int) |
||||||
|
val[strconv.Itoa(intKey)] = v |
||||||
|
}*/ |
||||||
|
} else { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading key or(and) value of array")) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
self.expect(DELIMITER_OBJECT_RIGHT) |
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeObject() PhpValue { |
||||||
|
val := &PhpObject{ |
||||||
|
className: self.readClassName(), |
||||||
|
} |
||||||
|
|
||||||
|
rawMembers := self.decodeArray() |
||||||
|
val.members, _ = rawMembers.(PhpArray) |
||||||
|
|
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeSerialized() PhpValue { |
||||||
|
val := &PhpObjectSerialized{ |
||||||
|
className: self.readClassName(), |
||||||
|
} |
||||||
|
|
||||||
|
rawData := self.decodeString(DELIMITER_OBJECT_LEFT, DELIMITER_OBJECT_RIGHT, false) |
||||||
|
val.data, _ = rawData.(string) |
||||||
|
|
||||||
|
if self.decodeFunc != nil && val.data != "" { |
||||||
|
var err error |
||||||
|
if val.value, err = self.decodeFunc(val.data); err != nil { |
||||||
|
self.saveError(err) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeReference() PhpValue { |
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
if _, err := self.readUntil(SEPARATOR_VALUES); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading reference value: %v", err)) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) expect(expected rune) { |
||||||
|
if token, _, err := self.r.ReadRune(); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading expected rune %#U: %v", expected, err)) |
||||||
|
} else if token != expected { |
||||||
|
if debugMode { |
||||||
|
log.Printf("php_serialize: source\n%s\n", self.source) |
||||||
|
log.Printf("php_serialize: reader info\n%#v\n", self.r) |
||||||
|
} |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Expected %#U but have got %#U", expected, token)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) readUntil(stop rune) (string, error) { |
||||||
|
var ( |
||||||
|
token rune |
||||||
|
err error |
||||||
|
) |
||||||
|
buf := bytes.NewBuffer([]byte{}) |
||||||
|
|
||||||
|
for { |
||||||
|
if token, _, err = self.r.ReadRune(); err != nil || token == stop { |
||||||
|
break |
||||||
|
} else { |
||||||
|
buf.WriteRune(token) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return buf.String(), err |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) readLen() int { |
||||||
|
var ( |
||||||
|
raw string |
||||||
|
err error |
||||||
|
val int |
||||||
|
) |
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
if raw, err = self.readUntil(SEPARATOR_VALUE_TYPE); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading lenght of value: %v", err)) |
||||||
|
} else { |
||||||
|
if val, err = strconv.Atoi(raw); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to int: %v", raw, err)) |
||||||
|
} else if val > UNSERIALIZABLE_OBJECT_MAX_LEN { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val)) |
||||||
|
val = 0 |
||||||
|
} |
||||||
|
} |
||||||
|
return val |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) readClassName() (res string) { |
||||||
|
rawClass := self.decodeString(DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, false) |
||||||
|
res, _ = rawClass.(string) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) saveError(err error) { |
||||||
|
if self.lastErr == nil { |
||||||
|
self.lastErr = err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *UnSerializer) decodeSplArray() PhpValue { |
||||||
|
var err error |
||||||
|
val := &PhpSplArray{} |
||||||
|
|
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
self.expect(TOKEN_INT) |
||||||
|
|
||||||
|
flags := self.decodeNumber(false) |
||||||
|
if flags == nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Unable to read flags of SplArray")) |
||||||
|
return nil |
||||||
|
} |
||||||
|
val.flags = PhpValueInt(flags) |
||||||
|
|
||||||
|
if val.array, err = self.Decode(); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Can't parse SplArray: %v", err)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
self.expect(SEPARATOR_VALUES) |
||||||
|
self.expect(TOKEN_SPL_ARRAY_MEMBERS) |
||||||
|
self.expect(SEPARATOR_VALUE_TYPE) |
||||||
|
|
||||||
|
if val.properties, err = self.Decode(); err != nil { |
||||||
|
self.saveError(fmt.Errorf("php_serialize: Can't parse properties of SplArray: %v", err)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
return val |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package point |
||||||
|
|
||||||
|
func PointLevel(point int64) int32 { |
||||||
|
if point <= 50 { |
||||||
|
return 1 |
||||||
|
} |
||||||
|
if point > 50 && point <= 200 { |
||||||
|
return 2 |
||||||
|
} |
||||||
|
if point > 200 && point <= 500 { |
||||||
|
return 3 |
||||||
|
} |
||||||
|
if point > 500 && point <= 1000 { |
||||||
|
return 4 |
||||||
|
} |
||||||
|
if point > 1000 && point <= 2500 { |
||||||
|
return 5 |
||||||
|
} |
||||||
|
if point > 2500 && point <= 5000 { |
||||||
|
return 6 |
||||||
|
} |
||||||
|
if point > 5000 && point <= 8000 { |
||||||
|
return 7 |
||||||
|
} |
||||||
|
return 8 |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package transurl |
||||||
|
|
||||||
|
var urlMap = map[string]string{ |
||||||
|
"/beijing": "/question-list/alatest/1", |
||||||
|
"/shanghai": "/question-list/alatest/2", |
||||||
|
"/guangzhou": "/question-list/alatest/54", |
||||||
|
"/shenzhen": "/question-list/alatest/55", |
||||||
|
"/chengdu": "/question-list/alatest/63", |
||||||
|
"/xi'an": "/question-list/alatest/64", |
||||||
|
"/hangzhou": "/question-list/alatest/59", |
||||||
|
"/qingdao": "/question-list/alatest/65", |
||||||
|
"/dalian": "/question-list/alatest/69", |
||||||
|
"/suzhou": "/question-list/alatest/67", |
||||||
|
"/nanjing": "/question-list/alatest/68", |
||||||
|
"/arts-entertainment": "/question-list/alatest/34", |
||||||
|
"/business-jobs": "/question-list/alatest/3", |
||||||
|
"/culture": "/question-list/alatest/4", |
||||||
|
"/falimy-kids": "/question-list/alatest/45", |
||||||
|
"/food": "/question-list/alatest/35", |
||||||
|
"/general": "/question-list/alatest/36", |
||||||
|
"/health-safety": "/question-list/alatest/39", |
||||||
|
"/housing": "/question-list/alatest/49", |
||||||
|
"/lifestyle": "/question-list/alatest/1058", |
||||||
|
"/money-banking": "/question-list/alatest/1059", |
||||||
|
"/relationships": "/question-list/alatest/53", |
||||||
|
"/shopping": "/question-list/alatest/41", |
||||||
|
"/sports": "/question-list/alatest/95", |
||||||
|
"/teaching-learning": "/question-list/alatest/43", |
||||||
|
"/transport-travel": "/question-list/alatest/47", |
||||||
|
"/visa-legalities": "/question-list/alatest/48", |
||||||
|
"/web-technology": "/question-list/alatest/44", |
||||||
|
} |
||||||
|
|
||||||
|
func GetLonUrl(src string) string { |
||||||
|
if v, ok := urlMap[src]; ok { |
||||||
|
return v |
||||||
|
} |
||||||
|
return src |
||||||
|
} |
||||||
|
|
||||||
|
func GetShortUrl(dst string) string { |
||||||
|
for src, dt := range urlMap { |
||||||
|
if dt == dst { |
||||||
|
return src |
||||||
|
} |
||||||
|
} |
||||||
|
return dst |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
package xarray |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
func ToSlice(slice interface{}) []interface{} { |
||||||
|
s := reflect.ValueOf(slice) |
||||||
|
if s.Kind() != reflect.Slice { |
||||||
|
panic("InterfaceSlice() given a non-slice type") |
||||||
|
} |
||||||
|
|
||||||
|
ret := make([]interface{}, s.Len()) |
||||||
|
|
||||||
|
for i := 0; i < s.Len(); i++ { |
||||||
|
ret[i] = s.Index(i).Interface() |
||||||
|
} |
||||||
|
|
||||||
|
return ret |
||||||
|
} |
||||||
|
|
||||||
|
func ToCountMap(strArr []string) map[string]int64 { |
||||||
|
mps := make(map[string]int64) |
||||||
|
for _, v := range strArr { |
||||||
|
mps[strings.ToLower(v)]++ |
||||||
|
} |
||||||
|
return mps |
||||||
|
} |
||||||
|
|
||||||
|
func InArray(need interface{}, list []interface{}) bool { |
||||||
|
for _, v := range list { |
||||||
|
if need == v { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
func UniqArray(list []int64) []int64 { |
||||||
|
result := make([]int64, 0) |
||||||
|
if len(list) == 0 { |
||||||
|
return result |
||||||
|
} |
||||||
|
mp := make(map[int64]bool) |
||||||
|
for _, v := range list { |
||||||
|
if mp[v] { |
||||||
|
continue |
||||||
|
} |
||||||
|
result = append(result, v) |
||||||
|
mp[v] = true |
||||||
|
} |
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
package xhttp |
||||||
|
|
||||||
|
import ( |
||||||
|
"crypto/tls" |
||||||
|
"encoding/json" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"io/ioutil" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
const timeout = time.Second * 120 |
||||||
|
|
||||||
|
func Request(method string, reqUrl string, postData string, header http.Header) (string, error) { |
||||||
|
var res string |
||||||
|
transport := &http.Transport{ |
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, |
||||||
|
} |
||||||
|
client := &http.Client{ |
||||||
|
Transport: transport, |
||||||
|
Timeout: timeout, |
||||||
|
} |
||||||
|
var ioreader io.Reader |
||||||
|
if postData != "" { |
||||||
|
ioreader = strings.NewReader(postData) |
||||||
|
} |
||||||
|
req, err := http.NewRequest(method, reqUrl, ioreader) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
if header != nil { |
||||||
|
req.Header = header |
||||||
|
} |
||||||
|
|
||||||
|
resp, err := client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
|
||||||
|
if resp.StatusCode == 200 { |
||||||
|
byt, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
return string(byt), nil |
||||||
|
} else { |
||||||
|
return res, fmt.Errorf("code:%d message:%s", resp.StatusCode, resp.Status) |
||||||
|
} |
||||||
|
} |
||||||
|
func Get(reqUrl string, timeout time.Duration) (string, error) { |
||||||
|
var res string |
||||||
|
transport := &http.Transport{ |
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, |
||||||
|
} |
||||||
|
client := &http.Client{ |
||||||
|
Transport: transport, |
||||||
|
Timeout: timeout, |
||||||
|
} |
||||||
|
req, err := http.NewRequest("GET", reqUrl, nil) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
resp, err := client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
|
||||||
|
if resp.StatusCode == 200 { |
||||||
|
byt, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return res, err |
||||||
|
} |
||||||
|
return string(byt), nil |
||||||
|
} else { |
||||||
|
return res, fmt.Errorf("code:%d message:%s", resp.StatusCode, resp.Status) |
||||||
|
} |
||||||
|
} |
||||||
|
func fetcher(method, u, post string, headers map[string]string, timeout int64) (*[]byte, error) { |
||||||
|
transport := &http.Transport{ |
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, |
||||||
|
} |
||||||
|
client := &http.Client{ |
||||||
|
Transport: transport, |
||||||
|
Timeout: time.Second * time.Duration(timeout), |
||||||
|
} |
||||||
|
req, err := http.NewRequest(method, u, strings.NewReader(post)) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
for k, v := range headers { |
||||||
|
req.Header.Add(k, v) |
||||||
|
} |
||||||
|
resp, err := client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
body, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
if resp.StatusCode != http.StatusOK { |
||||||
|
return nil, fmt.Errorf("FetchUrl status:%s", resp.Status) |
||||||
|
} |
||||||
|
return &body, err |
||||||
|
} |
||||||
|
|
||||||
|
func PostForm(u, post string, headers map[string]string) (*[]byte, error) { |
||||||
|
if headers == nil { |
||||||
|
headers = make(map[string]string) |
||||||
|
} |
||||||
|
headers["Content-Type"] = "application/x-www-form-urlencoded" |
||||||
|
return fetcher("POST", u, post, headers, 60) |
||||||
|
} |
||||||
|
|
||||||
|
func PostJson(u, post string, headers map[string]string) (*[]byte, error) { |
||||||
|
if headers == nil { |
||||||
|
headers = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
headers["Content-Type"] = "application/json;charset=UTF-8" |
||||||
|
fmt.Printf("%+v\n", post) |
||||||
|
fmt.Printf("%+v\n", headers) |
||||||
|
return fetcher("POST", u, post, headers, 60) |
||||||
|
} |
||||||
|
|
||||||
|
func GetWithHeader(u string, headers map[string]string) (*[]byte, error) { |
||||||
|
if headers == nil { |
||||||
|
headers = make(map[string]string) |
||||||
|
} |
||||||
|
return fetcher("GET", u, "", headers, 60) |
||||||
|
} |
||||||
|
|
||||||
|
type apiRes struct { |
||||||
|
Status int64 `json:"status"` |
||||||
|
} |
||||||
|
|
||||||
|
func SenEmail(u string, data map[string]string) error { |
||||||
|
fmt.Println(u) |
||||||
|
postByte, _ := json.Marshal(data) |
||||||
|
fmt.Printf("%s\n", postByte) |
||||||
|
values := url.Values{} |
||||||
|
for k, v := range data { |
||||||
|
values.Add(k, v) |
||||||
|
} |
||||||
|
fmt.Println(data) |
||||||
|
res, err := PostForm(u, values.Encode(), nil) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
fmt.Printf("%s\n", *res) |
||||||
|
result := apiRes{} |
||||||
|
if err := json.Unmarshal(*res, &result); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
if result.Status != 200 { |
||||||
|
return errors.New(string(*res)) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type shotResp struct { |
||||||
|
Code int64 `json:"code"` |
||||||
|
Info string `json:"info"` |
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
func ShotUrl(u string) (string, error) { |
||||||
|
values := url.Values{} |
||||||
|
values.Add("long_url", u) |
||||||
|
res, err := PostForm(`https://echinajobs.cn/add`, values.Encode(), nil) |
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
result := shotResp{} |
||||||
|
if err := json.Unmarshal(*res, &result); err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
if result.Code != 200 { |
||||||
|
return "", errors.New(string(*res)) |
||||||
|
} |
||||||
|
return result.Info, nil |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package xip |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
func GetIpFromContext(ctx context.Context) string { |
||||||
|
if v, ok := ctx.(*gin.Context); ok { |
||||||
|
return v.ClientIP() |
||||||
|
} |
||||||
|
return "" |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
package xjson |
||||||
|
|
||||||
|
import "encoding/json" |
||||||
|
|
||||||
|
func MustMarshal(data any) string { |
||||||
|
b, err := json.Marshal(data) |
||||||
|
if err != nil { |
||||||
|
return "" |
||||||
|
} |
||||||
|
return string(b) |
||||||
|
} |
@ -0,0 +1,77 @@ |
|||||||
|
package xmath |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
//"github.com/shopspring/decimal"
|
||||||
|
"math" |
||||||
|
"math/rand" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
// 小数点后 n 位 - 四舍五入
|
||||||
|
func RoundedFixed(val float64, n int) float64 { |
||||||
|
shift := math.Pow(10, float64(n)) |
||||||
|
fv := 0.0000000001 + val //对浮点数产生.xxx999999999 计算不准进行处理
|
||||||
|
return math.Floor(fv*shift+.5) / shift |
||||||
|
} |
||||||
|
|
||||||
|
// 小数点后 n 位 - 舍去
|
||||||
|
func TruncRound(val float64, n int) float64 { |
||||||
|
floatStr := fmt.Sprintf("%."+strconv.Itoa(n+1)+"f", val) |
||||||
|
temp := strings.Split(floatStr, ".") |
||||||
|
var newFloat string |
||||||
|
if len(temp) < 2 || n >= len(temp[1]) { |
||||||
|
newFloat = floatStr |
||||||
|
} else { |
||||||
|
newFloat = temp[0] + "." + temp[1][:n] |
||||||
|
} |
||||||
|
inst, _ := strconv.ParseFloat(newFloat, 64) |
||||||
|
return inst |
||||||
|
} |
||||||
|
|
||||||
|
// RandInt64 随机范围取值
|
||||||
|
func RandInt64(min, max int64) int64 { |
||||||
|
if min >= max || min == 0 || max == 0 { |
||||||
|
return max |
||||||
|
} |
||||||
|
return rand.Int63n(max-min) + min |
||||||
|
} |
||||||
|
func FloatWithoutRightDot(n float64) string { |
||||||
|
s := fmt.Sprintf("%.2f", n) |
||||||
|
ss := strings.Split(s, ".") |
||||||
|
ss1 := strings.TrimRight(ss[1], "0") |
||||||
|
if ss1 == "" { |
||||||
|
return ss[0] |
||||||
|
} else { |
||||||
|
return fmt.Sprintf("%s.%s", ss[0], ss1) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func NumberFormat(str string) string { |
||||||
|
length := len(str) |
||||||
|
if length < 4 { |
||||||
|
return str |
||||||
|
} |
||||||
|
arr := strings.Split(str, ".") //用小数点符号分割字符串,为数组接收
|
||||||
|
length1 := len(arr[0]) |
||||||
|
if length1 < 4 { |
||||||
|
return str |
||||||
|
} |
||||||
|
count := (length1 - 1) / 3 |
||||||
|
for i := 0; i < count; i++ { |
||||||
|
arr[0] = arr[0][:length1-(i+1)*3] + "," + arr[0][length1-(i+1)*3:] |
||||||
|
} |
||||||
|
return strings.Join(arr, ".") //将一系列字符串连接为一个字符串,之间用sep来分隔。
|
||||||
|
} |
||||||
|
|
||||||
|
func ConvertInt64(s string) int64 { |
||||||
|
v, _ := strconv.ParseInt(s, 10, 64) |
||||||
|
return v |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
//func Round(f float64, n int32) float64 {
|
||||||
|
// v, _ := decimal.NewFromFloat(f).Round(n).Float64()
|
||||||
|
// return v
|
||||||
|
//}
|
@ -0,0 +1,12 @@ |
|||||||
|
package xmd5 |
||||||
|
|
||||||
|
import ( |
||||||
|
"crypto/md5" |
||||||
|
"encoding/hex" |
||||||
|
) |
||||||
|
|
||||||
|
func MD5(str string) string { |
||||||
|
s := md5.New() |
||||||
|
s.Write([]byte(str)) |
||||||
|
return hex.EncodeToString(s.Sum(nil)) |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package xpage |
||||||
|
|
||||||
|
func GetPageOffset(page int32, size int32) int { |
||||||
|
if page < 1 { |
||||||
|
page = 1 |
||||||
|
} |
||||||
|
return int((page - 1) * size) |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package xredis |
||||||
|
|
||||||
|
//
|
||||||
|
//import (
|
||||||
|
// "context"
|
||||||
|
// "encoding/json"
|
||||||
|
// "fmt"
|
||||||
|
// "github.com/go-redis/redis/v8"
|
||||||
|
// "github.com/pkg/errors"
|
||||||
|
// "time"
|
||||||
|
//)
|
||||||
|
//
|
||||||
|
//var redisClient *redis.Client
|
||||||
|
//
|
||||||
|
//func Init(host, password string, db int) error {
|
||||||
|
// redisClient = redis.NewClient(&redis.Options{
|
||||||
|
// Network: "tcp",
|
||||||
|
// Addr: host,
|
||||||
|
// Password: password,
|
||||||
|
// DB: db,
|
||||||
|
// })
|
||||||
|
// return redisClient.Ping(context.Background()).Err()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func Client() *redis.Client {
|
||||||
|
// return redisClient
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func GetData[T any](ctx context.Context, key string, fn func() (T, error), dur time.Duration) (T, error) {
|
||||||
|
// var result T
|
||||||
|
// res := redisClient.Get(ctx, key).Val()
|
||||||
|
// if res != "" {
|
||||||
|
// err := json.Unmarshal([]byte(res), &result)
|
||||||
|
// if err == nil {
|
||||||
|
// return result, nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// r, err := fn()
|
||||||
|
// if err != nil {
|
||||||
|
// return result, err
|
||||||
|
// }
|
||||||
|
// if b, err := json.Marshal(r); err == nil {
|
||||||
|
// redisClient.Set(ctx, key, string(b), dur)
|
||||||
|
// }
|
||||||
|
// return r, nil
|
||||||
|
//}
|
||||||
|
//func Lock[T any](ctx context.Context, key string, fn func() (T, error)) (T, error) {
|
||||||
|
// var res T
|
||||||
|
// lockKey := fmt.Sprintf("lock:%s", key)
|
||||||
|
// ok, err := redisClient.SetNX(ctx, lockKey, 1, time.Second*20).Result()
|
||||||
|
// if err != nil {
|
||||||
|
// return res, errors.Wrap(err, "")
|
||||||
|
// }
|
||||||
|
// if !ok {
|
||||||
|
// return res, errors.Wrap(errors.New(fmt.Sprintf("lock %s exists", lockKey)), "")
|
||||||
|
// }
|
||||||
|
// defer redisClient.Del(ctx, lockKey)
|
||||||
|
// return fn()
|
||||||
|
//}
|
@ -0,0 +1,28 @@ |
|||||||
|
package xredis |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
type Res struct { |
||||||
|
Name string |
||||||
|
} |
||||||
|
|
||||||
|
func TestGetData(t *testing.T) { |
||||||
|
_ = Init("localhost:6379", "", 1) |
||||||
|
res, err := GetData(context.Background(), "userId1212", func() (*Res, error) { |
||||||
|
fmt.Println("from db") |
||||||
|
in := &Res{ |
||||||
|
Name: "ttt", |
||||||
|
} |
||||||
|
return in, nil |
||||||
|
}, time.Second*50) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
t.Error(err) |
||||||
|
} |
||||||
|
fmt.Printf("%+v\n", res) |
||||||
|
} |
@ -0,0 +1,641 @@ |
|||||||
|
package xstring |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/base64" |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"github.com/PuerkitoBio/goquery" |
||||||
|
"github.com/pkg/errors" |
||||||
|
"reflect" |
||||||
|
"regexp" |
||||||
|
"sort" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
func TableFieldNames(obj any) ([]string, string) { |
||||||
|
v := reflect.TypeOf(obj) |
||||||
|
cols := []string{} |
||||||
|
primary := "" |
||||||
|
for i := 0; i < v.NumField(); i++ { |
||||||
|
cols = append(cols, v.Field(i).Tag.Get("db")) |
||||||
|
if primary == "" { |
||||||
|
primary = v.Field(i).Tag.Get("primaryKey") |
||||||
|
} |
||||||
|
} |
||||||
|
return cols, primary |
||||||
|
} |
||||||
|
|
||||||
|
func Remove[T string](cols []T, key T) []T { |
||||||
|
arr := make([]T, 0) |
||||||
|
for _, v := range cols { |
||||||
|
if key != v { |
||||||
|
arr = append(arr, v) |
||||||
|
} |
||||||
|
} |
||||||
|
return arr |
||||||
|
} |
||||||
|
|
||||||
|
func NamedSql(cls []string) string { |
||||||
|
str := []string{} |
||||||
|
for _, v := range cls { |
||||||
|
str = append(str, fmt.Sprintf("%s=:%s", v, v)) |
||||||
|
} |
||||||
|
return strings.Join(str, ",") |
||||||
|
} |
||||||
|
|
||||||
|
func StripTags(content string) string { |
||||||
|
re := regexp.MustCompile(`<(.|\n)*?>`) |
||||||
|
return re.ReplaceAllString(content, "") |
||||||
|
} |
||||||
|
func SubString(str string, begin, length int) string { |
||||||
|
rs := []rune(str) |
||||||
|
lth := len(rs) |
||||||
|
if begin < 0 { |
||||||
|
begin = 0 |
||||||
|
} |
||||||
|
if begin >= lth { |
||||||
|
begin = lth |
||||||
|
} |
||||||
|
end := begin + length |
||||||
|
|
||||||
|
if end > lth { |
||||||
|
end = lth |
||||||
|
} |
||||||
|
return string(rs[begin:end]) |
||||||
|
} |
||||||
|
func Nl2br(str string) string { |
||||||
|
return strings.Join(strings.Split(strings.Join(strings.Split(str, "\r"), "<br/>"), "\n"), "<br/>") |
||||||
|
} |
||||||
|
|
||||||
|
func Serialize(value interface{}) ([]byte, error) { |
||||||
|
|
||||||
|
if value == nil { |
||||||
|
return MarshalNil(), nil |
||||||
|
} |
||||||
|
|
||||||
|
t := reflect.TypeOf(value) |
||||||
|
switch t.Kind() { |
||||||
|
case reflect.Bool: |
||||||
|
return MarshalBool(value.(bool)), nil |
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, |
||||||
|
reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, |
||||||
|
reflect.Float32, reflect.Float64: |
||||||
|
return MarshalNumber(value), nil |
||||||
|
case reflect.String: |
||||||
|
return MarshalString(value.(string)), nil |
||||||
|
case reflect.Map: |
||||||
|
return MarshalMap(value) |
||||||
|
case reflect.Slice: |
||||||
|
return MarshalSlice(value) |
||||||
|
default: |
||||||
|
return nil, fmt.Errorf("Marshal: Unknown type %T with value %#v", t, value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func MarshalNil() []byte { |
||||||
|
return []byte("N;") |
||||||
|
} |
||||||
|
|
||||||
|
func MarshalBool(value bool) []byte { |
||||||
|
if value { |
||||||
|
return []byte("b:1;") |
||||||
|
} |
||||||
|
|
||||||
|
return []byte("b:0;") |
||||||
|
} |
||||||
|
|
||||||
|
func MarshalNumber(value interface{}) []byte { |
||||||
|
var val string |
||||||
|
|
||||||
|
isFloat := false |
||||||
|
|
||||||
|
switch value.(type) { |
||||||
|
default: |
||||||
|
val = "0" |
||||||
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: |
||||||
|
val, _ = NumericalToString(value) |
||||||
|
case float32, float64: |
||||||
|
val, _ = NumericalToString(value) |
||||||
|
isFloat = true |
||||||
|
} |
||||||
|
|
||||||
|
if isFloat { |
||||||
|
return []byte("d:" + val + ";") |
||||||
|
|
||||||
|
} else { |
||||||
|
return []byte("i:" + val + ";") |
||||||
|
} |
||||||
|
} |
||||||
|
func NumericalValue(value reflect.Value) (float64, bool) { |
||||||
|
switch value.Type().Kind() { |
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
||||||
|
return float64(value.Int()), true |
||||||
|
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
||||||
|
return float64(value.Uint()), true |
||||||
|
|
||||||
|
case reflect.Float32, reflect.Float64: |
||||||
|
return value.Float(), true |
||||||
|
|
||||||
|
default: |
||||||
|
return 0, false |
||||||
|
} |
||||||
|
} |
||||||
|
func MarshalString(value string) []byte { |
||||||
|
return []byte(fmt.Sprintf("s:%d:\"%s\";", len(value), value)) |
||||||
|
} |
||||||
|
func LessValue(a, b reflect.Value) bool { |
||||||
|
aValue, aNumerical := NumericalValue(a) |
||||||
|
bValue, bNumerical := NumericalValue(b) |
||||||
|
|
||||||
|
if aNumerical && bNumerical { |
||||||
|
return aValue < bValue |
||||||
|
} |
||||||
|
|
||||||
|
if !aNumerical && !bNumerical { |
||||||
|
// In theory this should mean they are both strings. In reality
|
||||||
|
// they could be any other type and the String() representation
|
||||||
|
// will be something like "<bool>" if it is not a string. Since
|
||||||
|
// distinct values of non-strings still return the same value
|
||||||
|
// here that's what makes the ordering undefined.
|
||||||
|
return strings.Compare(a.String(), b.String()) < 0 |
||||||
|
} |
||||||
|
|
||||||
|
// Numerical values are always treated as less than other types
|
||||||
|
// (including strings that might represent numbers themselves). The
|
||||||
|
// inverse is also true.
|
||||||
|
return aNumerical && !bNumerical |
||||||
|
} |
||||||
|
|
||||||
|
func MarshalMap(value interface{}) ([]byte, error) { |
||||||
|
|
||||||
|
s := reflect.ValueOf(value) |
||||||
|
|
||||||
|
mapKeys := s.MapKeys() |
||||||
|
sort.Slice(mapKeys, func(i, j int) bool { |
||||||
|
return LessValue(mapKeys[i], mapKeys[j]) |
||||||
|
}) |
||||||
|
|
||||||
|
var buffer bytes.Buffer |
||||||
|
for _, mapKey := range mapKeys { |
||||||
|
m, err := Serialize(mapKey.Interface()) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
buffer.Write(m) |
||||||
|
|
||||||
|
m, err = Serialize(s.MapIndex(mapKey).Interface()) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
buffer.Write(m) |
||||||
|
} |
||||||
|
|
||||||
|
return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil |
||||||
|
} |
||||||
|
|
||||||
|
func MarshalSlice(value interface{}) ([]byte, error) { |
||||||
|
s := reflect.ValueOf(value) |
||||||
|
|
||||||
|
var buffer bytes.Buffer |
||||||
|
for i := 0; i < s.Len(); i++ { |
||||||
|
m, err := Serialize(i) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
buffer.Write(m) |
||||||
|
|
||||||
|
m, err = Serialize(s.Index(i).Interface()) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
buffer.Write(m) |
||||||
|
} |
||||||
|
|
||||||
|
return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil |
||||||
|
} |
||||||
|
|
||||||
|
const UNSERIALIZABLE_OBJECT_MAX_LEN = int64(10 * 1024 * 1024 * 1024) |
||||||
|
|
||||||
|
func UnSerialize(data []byte) (interface{}, error) { |
||||||
|
reader := bytes.NewReader(data) |
||||||
|
return unMarshalByReader(reader) |
||||||
|
} |
||||||
|
|
||||||
|
func UnSerializeBind(data []byte, post any) error { |
||||||
|
reader := bytes.NewReader(data) |
||||||
|
b, err := unMarshalByReader(reader) |
||||||
|
if err != nil { |
||||||
|
return errors.Wrap(err, "") |
||||||
|
} |
||||||
|
bb, err := json.Marshal(b) |
||||||
|
if err != nil { |
||||||
|
return errors.Wrap(err, "") |
||||||
|
} |
||||||
|
err = json.Unmarshal(bb, post) |
||||||
|
return errors.Wrap(err, "") |
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalByReader(reader *bytes.Reader) (interface{}, error) { |
||||||
|
|
||||||
|
for { |
||||||
|
|
||||||
|
if token, _, err := reader.ReadRune(); err == nil { |
||||||
|
switch token { |
||||||
|
default: |
||||||
|
return nil, fmt.Errorf("UnMarshal: Unknown token %#U", token) |
||||||
|
case 'N': |
||||||
|
return unMarshalNil(reader) |
||||||
|
case 'b': |
||||||
|
return unMarshalBool(reader) |
||||||
|
case 'i': |
||||||
|
return unMarshalNumber(reader, false) |
||||||
|
case 'd': |
||||||
|
return unMarshalNumber(reader, true) |
||||||
|
case 's': |
||||||
|
return unMarshalString(reader, true) |
||||||
|
case 'a': |
||||||
|
return unMarshalArray(reader) |
||||||
|
// case 'O':
|
||||||
|
|
||||||
|
// case 'C':
|
||||||
|
|
||||||
|
// case 'R', 'r':
|
||||||
|
|
||||||
|
// case 'x':
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalNil(reader *bytes.Reader) (interface{}, error) { |
||||||
|
_ = expect(reader, ';') |
||||||
|
|
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalBool(reader *bytes.Reader) (interface{}, error) { |
||||||
|
var ( |
||||||
|
raw rune |
||||||
|
err error |
||||||
|
) |
||||||
|
err = expect(reader, ':') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if raw, _, err = reader.ReadRune(); err != nil { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Error while reading bool value: %v", err) |
||||||
|
} |
||||||
|
|
||||||
|
err = expect(reader, ';') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return raw == '1', nil |
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalNumber(reader *bytes.Reader, isFloat bool) (interface{}, error) { |
||||||
|
var ( |
||||||
|
raw string |
||||||
|
err error |
||||||
|
val interface{} |
||||||
|
) |
||||||
|
err = expect(reader, ':') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if raw, err = readUntil(reader, ';'); err != nil { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Error while reading number value: %v", err) |
||||||
|
} else { |
||||||
|
if isFloat { |
||||||
|
if val, err = strconv.ParseFloat(raw, 64); err != nil { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Unable to convert %s to float: %v", raw, err) |
||||||
|
} |
||||||
|
} else { |
||||||
|
if val, err = strconv.Atoi(raw); err != nil { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return val, nil |
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalString(reader *bytes.Reader, isFinal bool) (interface{}, error) { |
||||||
|
var ( |
||||||
|
err error |
||||||
|
val interface{} |
||||||
|
strLen int |
||||||
|
readLen int |
||||||
|
) |
||||||
|
|
||||||
|
strLen, err = readLength(reader) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
err = expect(reader, '"') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if strLen > 0 { |
||||||
|
buf := make([]byte, strLen) |
||||||
|
if readLen, err = reader.Read(buf); err != nil { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Error while reading string value: %v", err) |
||||||
|
} else { |
||||||
|
if readLen != strLen { |
||||||
|
return nil, fmt.Errorf("UnMarshal: Unable to read string. Expected %d but have got %d bytes", strLen, readLen) |
||||||
|
} else { |
||||||
|
val = string(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err = expect(reader, '"') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
if isFinal { |
||||||
|
err = expect(reader, ';') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
} |
||||||
|
return val, nil |
||||||
|
} |
||||||
|
|
||||||
|
func unMarshalArray(reader *bytes.Reader) (interface{}, error) { |
||||||
|
var arrLen int |
||||||
|
var err error |
||||||
|
val := make(map[string]interface{}) |
||||||
|
|
||||||
|
arrLen, err = readLength(reader) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
err = expect(reader, '{') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
indexLen := 0 |
||||||
|
for i := 0; i < arrLen; i++ { |
||||||
|
k, err := unMarshalByReader(reader) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
v, err := unMarshalByReader(reader) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// if errKey == nil && errVal == nil {
|
||||||
|
// val[k] = v
|
||||||
|
switch t := k.(type) { |
||||||
|
default: |
||||||
|
return nil, fmt.Errorf("UnMarshal: Unexpected key type %T", t) |
||||||
|
case string: |
||||||
|
stringKey, _ := k.(string) |
||||||
|
val[stringKey] = v |
||||||
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: |
||||||
|
// intKey, _ := k.(int)
|
||||||
|
// val[strconv.Itoa(intKey)] = v
|
||||||
|
stringKey, _ := NumericalToString(k) |
||||||
|
val[stringKey] = v |
||||||
|
|
||||||
|
// stringI, _ := utils.NumericalToString(i)
|
||||||
|
if i == k { |
||||||
|
indexLen++ |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
// } else {
|
||||||
|
// return nil, fmt.Errorf("UnMarshal: Error while reading key or(and) value of array")
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
err = expect(reader, '}') |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if indexLen == arrLen { |
||||||
|
var slice []interface{} |
||||||
|
for _, row := range val { |
||||||
|
slice = append(slice, row) |
||||||
|
} |
||||||
|
return slice, nil |
||||||
|
} |
||||||
|
|
||||||
|
return val, nil |
||||||
|
} |
||||||
|
|
||||||
|
func expect(reader *bytes.Reader, expected rune) error { |
||||||
|
if token, _, err := reader.ReadRune(); err != nil { |
||||||
|
return fmt.Errorf("UnMarshal: Error while reading expected rune %#U: %v", expected, err) |
||||||
|
} else if token != expected { |
||||||
|
return fmt.Errorf("UnMarshal: Expected %#U but have got %#U", expected, token) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func readUntil(reader *bytes.Reader, stop rune) (string, error) { |
||||||
|
var ( |
||||||
|
token rune |
||||||
|
err error |
||||||
|
) |
||||||
|
buf := bytes.NewBuffer([]byte{}) |
||||||
|
|
||||||
|
for { |
||||||
|
if token, _, err = reader.ReadRune(); err != nil || token == stop { |
||||||
|
break |
||||||
|
} else { |
||||||
|
buf.WriteRune(token) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return buf.String(), err |
||||||
|
} |
||||||
|
|
||||||
|
func readLength(reader *bytes.Reader) (int, error) { |
||||||
|
var ( |
||||||
|
raw string |
||||||
|
err error |
||||||
|
val int |
||||||
|
) |
||||||
|
err = expect(reader, ':') |
||||||
|
if err != nil { |
||||||
|
return 0, err |
||||||
|
} |
||||||
|
|
||||||
|
if raw, err = readUntil(reader, ':'); err != nil { |
||||||
|
return 0, fmt.Errorf("UnMarshal: Error while reading lenght of value: %v", err) |
||||||
|
} else { |
||||||
|
if val, err = strconv.Atoi(raw); err != nil { |
||||||
|
return 0, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) |
||||||
|
} else if int64(val) > UNSERIALIZABLE_OBJECT_MAX_LEN { |
||||||
|
return 0, fmt.Errorf("UnMarshal: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val) |
||||||
|
} |
||||||
|
} |
||||||
|
return val, nil |
||||||
|
} |
||||||
|
|
||||||
|
func NumericalToString(value interface{}) (string, bool) { |
||||||
|
var val string |
||||||
|
|
||||||
|
switch intVal := value.(type) { |
||||||
|
default: |
||||||
|
return "0", false |
||||||
|
case int: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int8: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int16: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int32: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case int64: |
||||||
|
val = strconv.FormatInt(int64(intVal), 10) |
||||||
|
case uint: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint8: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint16: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint32: |
||||||
|
val = strconv.FormatUint(uint64(intVal), 10) |
||||||
|
case uint64: |
||||||
|
val = strconv.FormatUint(intVal, 10) |
||||||
|
case float32: |
||||||
|
val = strconv.FormatFloat(float64(intVal), 'f', -1, 32) |
||||||
|
case float64: |
||||||
|
val = strconv.FormatFloat(intVal, 'f', -1, 64) |
||||||
|
} |
||||||
|
return val, true |
||||||
|
} |
||||||
|
|
||||||
|
//func StrToArr(str string) []string {
|
||||||
|
// re := regexp.MustCompile(`<(.|\n)*?>`)
|
||||||
|
// str = re.ReplaceAllString(str, " ")
|
||||||
|
// str = strings.ReplaceAll(str, `"`, "")
|
||||||
|
// str = strings.ReplaceAll(str, `'`, "")
|
||||||
|
// str = strings.ReplaceAll(str, "`", "")
|
||||||
|
// str = strings.ReplaceAll(str, ",", "")
|
||||||
|
// str = strings.ReplaceAll(str, " ", "")
|
||||||
|
// newStr := []string{}
|
||||||
|
// tmp := ""
|
||||||
|
// for i := 0; i < len(str); {
|
||||||
|
// r, n := utf8.DecodeRuneInString(str[i:])
|
||||||
|
// if n == 3 {
|
||||||
|
// tmp = ""
|
||||||
|
// newStr = append(newStr, string(r))
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// if string(r) == " " {
|
||||||
|
// newStr = append(newStr, tmp)
|
||||||
|
// tmp = ""
|
||||||
|
// } else if string(r) != "\n" {
|
||||||
|
// tmp = fmt.Sprintf("%s%c", tmp, r)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// i += n
|
||||||
|
// }
|
||||||
|
// if tmp != "" {
|
||||||
|
// newStr = append(newStr, tmp)
|
||||||
|
// tmp = ""
|
||||||
|
// }
|
||||||
|
// newStr1 := make([]string, 0)
|
||||||
|
// for _, v := range newStr {
|
||||||
|
// if strings.TrimSpace(v) == "" {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// newStr1 = append(newStr1, strings.TrimSpace(v))
|
||||||
|
// }
|
||||||
|
// return newStr1
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func StrToUrl(str string) string {
|
||||||
|
// strs := []string{}
|
||||||
|
// for _, v := range StrToArr(str) {
|
||||||
|
// fmt.Println(v)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return strings.Join(strs, "-")
|
||||||
|
//}
|
||||||
|
|
||||||
|
func Base64Encode(s string) string { |
||||||
|
return base64.StdEncoding.EncodeToString([]byte(s)) |
||||||
|
} |
||||||
|
|
||||||
|
func Base64Decode(s string) (string, error) { |
||||||
|
b, err := base64.StdEncoding.DecodeString(s) |
||||||
|
if err != nil { |
||||||
|
return "", errors.Wrap(err, "") |
||||||
|
} |
||||||
|
return string(b), nil |
||||||
|
} |
||||||
|
|
||||||
|
func HtmlToText(body string) ([]string, error) { |
||||||
|
body = strings.ReplaceAll(body, " ", " ") |
||||||
|
ss := "<(.|\\n)*?>" |
||||||
|
body = regexp.MustCompile(ss).ReplaceAllString(body, " ") |
||||||
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) |
||||||
|
if err != nil { |
||||||
|
return nil, errors.Wrap(err, "") |
||||||
|
} |
||||||
|
defer doc.Clone() |
||||||
|
v := doc.Text() |
||||||
|
var hzRegexp = regexp.MustCompile("^[a-zA-Z0-9\u4e00-\u9fa5]$") |
||||||
|
var zwReg = regexp.MustCompile("^[\u4e00-\u9fa5]$") |
||||||
|
strn := "" |
||||||
|
ars := []string{} |
||||||
|
for _, c := range v { |
||||||
|
filter := false |
||||||
|
if hzRegexp.MatchString(string(c)) { |
||||||
|
if zwReg.MatchString(string(c)) { |
||||||
|
strn += string(c) |
||||||
|
filter = true |
||||||
|
} else { |
||||||
|
strn += string(c) |
||||||
|
} |
||||||
|
} else { |
||||||
|
filter = true |
||||||
|
} |
||||||
|
fmt.Println(strn) |
||||||
|
if filter && strn != "" { |
||||||
|
ars = append(ars, strn) |
||||||
|
strn = "" |
||||||
|
} |
||||||
|
} |
||||||
|
if strn != "" { |
||||||
|
ars = append(ars, strn) |
||||||
|
} |
||||||
|
return ars, nil |
||||||
|
} |
||||||
|
func ContentText(body string) string { |
||||||
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) |
||||||
|
if err != nil { |
||||||
|
return err.Error() |
||||||
|
} |
||||||
|
defer doc.Clone() |
||||||
|
return doc.Text() |
||||||
|
} |
||||||
|
func GetPicture(pic string) string { |
||||||
|
if pic == "" { |
||||||
|
return "/sites/default/files/imagecache/ic50x50/avatar_selection/o2QQW.jpg.png" |
||||||
|
} |
||||||
|
if !strings.HasPrefix(pic, "/") { |
||||||
|
return "/" + pic |
||||||
|
} |
||||||
|
return pic |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package xtime |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
const DefaultTimeLayout = "2006-01-02 15:04:05" |
||||||
|
|
||||||
|
func LeaTime(t int64) string { |
||||||
|
leaSeconds := time.Now().Unix() - t |
||||||
|
mps := []struct { |
||||||
|
Seconds int64 |
||||||
|
Title string |
||||||
|
}{ |
||||||
|
{31536000, "years"}, |
||||||
|
{604800, "weeks"}, |
||||||
|
{86400, "days"}, |
||||||
|
{3600, "hours"}, |
||||||
|
{60, "min"}, |
||||||
|
{1, "sec"}, |
||||||
|
} |
||||||
|
res := []string{} |
||||||
|
for _, v := range mps { |
||||||
|
if leaSeconds > v.Seconds { |
||||||
|
if len(res) == 2 { |
||||||
|
break |
||||||
|
} |
||||||
|
n := leaSeconds / v.Seconds |
||||||
|
tt := v.Title |
||||||
|
if n == 1 { |
||||||
|
tt = strings.TrimRight(v.Title, "s") |
||||||
|
} |
||||||
|
res = append(res, fmt.Sprintf("%d %s", n, tt)) |
||||||
|
leaSeconds -= v.Seconds * n |
||||||
|
} |
||||||
|
} |
||||||
|
return strings.Join(res, " ") |
||||||
|
} |
||||||
|
|
||||||
|
func UnixToTime(unix int64) time.Time { |
||||||
|
return time.Unix(unix, 0) |
||||||
|
} |
||||||
|
func ParseTime(day string, layout string) int64 { |
||||||
|
if day == "" { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
t, err := time.ParseInLocation(layout, day, time.Local) |
||||||
|
if err != nil { |
||||||
|
fmt.Println(err) |
||||||
|
return 0 |
||||||
|
} |
||||||
|
return t.Unix() |
||||||
|
} |
||||||
|
|
||||||
|
const DefaultLayout = "2006-01-02 15:04:05" |
||||||
|
|
||||||
|
func TimeTodayMinAndMax(ctime time.Time) (min, max time.Time) { |
||||||
|
start, _ := time.ParseInLocation(DefaultLayout, ctime.Format("2006-01-02")+" 00:00:00", time.Local) |
||||||
|
end, _ := time.ParseInLocation(DefaultLayout, ctime.Format("2006-01-02")+" 23:59:59", time.Local) |
||||||
|
return start, end |
||||||
|
} |
||||||
|
func UnixToStr(t int64) string { |
||||||
|
if t == 0 { |
||||||
|
return "" |
||||||
|
} |
||||||
|
return UnixToTime(t).Format(DefaultTimeLayout) |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package xtime |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestLeaTime(t *testing.T) { |
||||||
|
fmt.Println(LeaTime(1651812894)) |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package xuser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
type requestUserIdKey struct { |
||||||
|
} |
||||||
|
|
||||||
|
func GetUserNameFromContext(ctx *gin.Context) string { |
||||||
|
v, ok := ctx.Get("userId") |
||||||
|
if !ok { |
||||||
|
return "" |
||||||
|
} |
||||||
|
//if value, ok := ctx.Value(requestUserIdKey{}).(string); ok {
|
||||||
|
// return value
|
||||||
|
//}
|
||||||
|
return v.(string) |
||||||
|
} |
||||||
|
func SetContextUserId(ctx *gin.Context, username string) { |
||||||
|
ctx.Set("userId", username) |
||||||
|
//return context.WithValue(ctx, requestUserIdKey{}, username)
|
||||||
|
} |
Loading…
Reference in new issue