Files
bl/common/contrib/files/pngcm/local.go

171 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pngcm
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"time"
"blazing/cool"
"blazing/cool/coolfile"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
// Pngcm 实现coolfile.Driver接口用于远程图片上传
type Pngcm struct{}
// 远程上传接口响应结构
type uploadResponse struct {
Code int `json:"code"`
Url string `json:"url"`
Message string `json:"message"`
}
// Upload 上传文件到远程服务
func (p *Pngcm) Upload(ctx g.Ctx, filepath, filename string) (string, error) {
// 检查本地文件是否存在
if _, err := os.Stat(filepath); err != nil {
return "", gerror.Newf("上传文件不存在: %s, 错误: %v", filepath, err)
}
// 生成27位随机字符串类似PHP的Str::random(27)
randomStr, err := randString(27)
if err != nil {
return "", gerror.Newf("生成随机字符串失败: %v", err)
}
uuid := "o_" + randomStr
// 构建表单数据
var requestBody bytes.Buffer
writer := multipart.NewWriter(&requestBody)
// 添加普通表单字段
if err := writer.WriteField("name", filename); err != nil {
return "", gerror.Newf("写入name字段失败: %v", err)
}
if err := writer.WriteField("uuid", uuid); err != nil {
return "", gerror.Newf("写入uuid字段失败: %v", err)
}
if err := writer.WriteField("sign", fmt.Sprintf("%d", time.Now().Unix())); err != nil {
return "", gerror.Newf("写入sign字段失败: %v", err)
}
// 添加文件字段
file, err := os.Open(filepath)
if err != nil {
return "", gerror.Newf("打开文件失败: %v", err)
}
defer file.Close()
fileField, err := writer.CreateFormFile("file", filename)
if err != nil {
return "", gerror.Newf("创建文件表单字段失败: %v", err)
}
if _, err := io.Copy(fileField, file); err != nil {
return "", gerror.Newf("复制文件内容失败: %v", err)
}
// 完成表单构建
if err := writer.Close(); err != nil {
return "", gerror.Newf("关闭表单写入器失败: %v", err)
}
// 创建HTTP请求
req, err := http.NewRequestWithContext(ctx, "POST", "https://img.wnflb2023.com/application/upload.php", &requestBody)
if err != nil {
return "", gerror.Newf("创建请求失败: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Referer", "https://img.wnflb2023.com/")
// 发送请求
client := &http.Client{
Timeout: 30 * time.Second, // 设置超时时间
}
resp, err := client.Do(req)
if err != nil {
return "", gerror.Newf("发送请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应内容
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", gerror.Newf("读取响应内容失败: %v", err)
}
// 检查HTTP状态码
if resp.StatusCode != http.StatusOK {
return "", gerror.Newf("接口返回非200状态码: %d, 响应内容: %s", resp.StatusCode, string(respBody))
}
// 解析JSON响应
var uploadResp uploadResponse
if err := json.Unmarshal(respBody, &uploadResp); err != nil {
return "", gerror.Newf("解析响应JSON失败: %v, 响应内容: %s", err, string(respBody))
}
// 处理业务响应
if uploadResp.Code == 200 {
return uploadResp.Url, nil
} else if uploadResp.Message != "" {
return "", gerror.Newf("上传失败请重试: %s", uploadResp.Message)
} else {
return "", gerror.Newf("上传失败!接口错误,响应内容: %s", string(respBody))
}
}
// GetMode 获取驱动模式信息
func (p *Pngcm) GetMode() (data interface{}, err error) {
data = g.MapStrStr{
"mode": cool.Config.File.Mode,
"type": "pngcm",
}
return
}
// New 创建驱动实例
func (p *Pngcm) New() coolfile.Driver {
return &Pngcm{}
}
// New 实例化驱动
func New() coolfile.Driver {
return &Pngcm{}
}
// 生成指定长度的随机字符串(字母数字混合)
func randString(length int) (string, error) {
b := make([]byte, length)
_, err := rand.Read(b)
if err != nil {
return "", err
}
// 使用base64编码确保字符安全然后截取指定长度
return base64.URLEncoding.EncodeToString(b)[:length], nil
}
func init() {
var (
err error
driverObj = New()
driverNames = g.SliceStr{"pngcm"}
)
// 注册驱动
for _, driverName := range driverNames {
if err = coolfile.Register(driverName, driverObj); err != nil {
panic(err)
}
}
}