├── README.md ├── golang ├── auth.go ├── main.go ├── submit.go ├── typelist.go ├── upcover.go └── upvideo.go ├── java ├── Demo.java ├── entity │ ├── ArcAddParam.java │ ├── ArcBizException.java │ └── CommonReply.java └── util │ ├── ArchiveUtil.java │ └── HttpUtil.java └── php └── VideoUpUtoken.php /README.md: -------------------------------------------------------------------------------- 1 | # 此仓库由于历史迭代的兼容原因,已归档,不推荐使用 2 | 3 | # [bilibili 开放平台](https://openhome.bilibili.com/) 4 | 哔哩哔哩开放平台示例代码库,目前主要包含视频稿件投稿流程的各语言版本示例代码。 5 | 6 | 如果您有任何问题或需求,可以通过如下途径查询或反馈: 7 | - 开放平台技术文档:https://openhome.bilibili.com/doc/4/aa909d41-01da-e47e-e64c-f32bc76b8a42 8 | - 开放平台主页右下角-帮助中心-发起工单:https://openhome.bilibili.com/ticket 9 | - 开放平台官方邮箱:openplatform-feedback@bilibili.com 10 | - 新建Issuse:https://github.com/bilibili-openplatform/demo/issues 11 | 12 | 13 | ### Java 14 | [Java示例代码](java/Demo.java) 15 | 16 | 本示例引用了 HttpClient、jackson 等依赖,使用者可自行替换: 17 | ```xml 18 | 19 | org.apache.httpcomponents 20 | httpclient 21 | 4.5.13 22 | 23 | 24 | org.apache.httpcomponents 25 | httpmime 26 | 4.5.3 27 | 28 | 29 | com.fasterxml.jackson.core 30 | jackson-databind 31 | 2.12.5 32 | 33 | ``` 34 | 35 | ### Golang 36 | [Golang示例代码](golang/main.go) 37 | 38 | ### PHP 39 | [PHP示例代码](php/VideoUpUtoken.php) 40 | 41 | -------------------------------------------------------------------------------- /golang/auth.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/url" 9 | ) 10 | 11 | type AuthLoginResp struct { 12 | Code int `json:"code"` 13 | Message string `json:"message"` 14 | Data struct { 15 | AccessToken string `json:"access_token"` 16 | RefreshToken string `json:"refresh_token"` 17 | ExpiresIn int64 `json:"expires_in"` 18 | } 19 | } 20 | 21 | func authLogin(code string) (res *AuthLoginResp, err error) { 22 | params := url.Values{} 23 | params.Set("client_id", _client_id) 24 | params.Set("client_secret", _client_secret) 25 | params.Set("code", code) 26 | params.Set("grant_type", "authorization_code") 27 | uri := _openapi_auth + "?" + params.Encode() 28 | fmt.Printf("authLogin uri(%v)\n", uri) 29 | req, err := http.NewRequest(http.MethodPost, uri, nil) 30 | if err != nil { 31 | fmt.Printf("authLogin http.NewRequest error(%v)\n", err) 32 | return 33 | } 34 | c := http.DefaultClient 35 | resp, err := c.Do(req) 36 | if err != nil { 37 | fmt.Printf("authLogin c.Do error(%v), uri(%s)\n", err, uri) 38 | return 39 | } 40 | defer resp.Body.Close() 41 | bs, err := ioutil.ReadAll(resp.Body) 42 | if err != nil { 43 | fmt.Printf("authLogin read resp err(%v)\n", err) 44 | return 45 | } 46 | if resp.StatusCode != 200 { 47 | fmt.Printf("authLogin uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 48 | return 49 | } 50 | fmt.Printf("authLogin uri(%v) respbody(%v) success\n", uri, string(bs)) 51 | json.Unmarshal(bs, &res) 52 | return 53 | } 54 | -------------------------------------------------------------------------------- /golang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | const ( 10 | _client_id = "xxx" // 应用client_id,请设置成真实信息 11 | _client_secret = "xxx" // 应用secret,请设置成真实信息 12 | _openapi_auth = "https://api.bilibili.com/x/account-oauth2/v1/token" 13 | _openapi_videoup_init = "http://member.bilibili.com/arcopen/fn/archive/video/init" 14 | _openapi_videoup_upload = "http://openupos.bilivideo.com/video/v2/part/upload" 15 | _openapi_videoup_merge = "http://member.bilibili.com/arcopen/fn/archive/video/complete" 16 | _openapi_archive_upcover = "http://member.bilibili.com/arcopen/fn/archive/cover/upload" 17 | _openapi_archive_add = "http://member.bilibili.com/arcopen/fn/archive/add-by-utoken" 18 | _openapi_type_list = "http://member.bilibili.com/arcopen/fn/archive/type/list" 19 | ) 20 | 21 | func main() { 22 | /* step 0: 授权登录,入参code通过授权SDK获取 23 | * 获取到的access_token等结果建议保存起来,以免每次交互都重新请求 24 | * 根据expires_in识别access_token的过期时间 25 | * 可通过refresh_token来续期access_token 26 | */ 27 | code := "xxx" // 授权code,请通过授权SDK获取 28 | authLoginResp, err := authLogin(code) 29 | if err != nil || authLoginResp.Code != 0 { 30 | fmt.Printf("登录失败, code=%s\n", code) 31 | return 32 | } 33 | fmt.Printf("登录成功, resp=(%+v)\n", authLoginResp.Data) 34 | aToken := authLoginResp.Data.AccessToken 35 | 36 | // 文件信息获取 37 | filePath := "xxx" // 文件路径,请设置成真实信息 38 | fs, err := os.Stat(filePath) 39 | if err != nil { 40 | fmt.Printf("读取文件信息失败, path=%s\n", filePath) 41 | return 42 | } 43 | 44 | //step 1.1: 文件上传初始化 45 | initReq := &VideoupInitReq{ 46 | Name: fs.Name(), 47 | } 48 | videoupInitResp := videoupInit(aToken, initReq) 49 | uToken := videoupInitResp.Data.UploadToken 50 | if videoupInitResp.Code != 0 { 51 | fmt.Printf("文件预处理失败, resp=%+v\n", videoupInitResp) 52 | return 53 | } 54 | 55 | //step 1.2: 文件分片信息计算,8M一个分片 56 | chunkInfos := preChunk(fs, 8*1024*1024) 57 | fmt.Printf("分片信息 %+v\n", chunkInfos) 58 | 59 | //step 1.3: 读取本地文件并分片上传 60 | f, _ := os.Open(filePath) 61 | defer f.Close() 62 | for _, v := range chunkInfos { 63 | bs := make([]byte, v.Size) 64 | f.ReadAt(bs, v.Start) 65 | videoUploadResp, err := videoUpload(uToken, v.PartNum, v, bytes.NewReader(bs)) 66 | if err != nil || videoUploadResp.Code != 0 { 67 | fmt.Printf("文件分片上传失败, part_num=%d, resp=%+v, err=%+v\n", v.PartNum, videoupInitResp, err) 68 | return 69 | } 70 | } 71 | 72 | //step 1.4 分片合并 73 | videoupMerge(uToken) 74 | 75 | //step 2.1 稿件封面上传 76 | coverPath := "xxx" // 封面路径,请设置成真实信息 77 | coverUploadResp, err := uploadCover(aToken, coverPath) 78 | if err != nil || coverUploadResp.Code != 0 { 79 | fmt.Printf("封面上传失败, resp=%+v, err=%+v\n", coverUploadResp, err) 80 | return 81 | } 82 | coverUrl := coverUploadResp.Data.Url 83 | 84 | //// 稿件分区列表 85 | //typeListResp, err := typeList(aToken) 86 | //if err != nil || typeListResp.Code != 0 { 87 | // fmt.Printf("获取分区列表失败, resp=%+v, err=%+v\n", typeListResp, err) 88 | // return 89 | //} 90 | //fmt.Printf("获取分区列表成功, resp=(%+v)\n", authLoginResp.Data) 91 | 92 | //step 3.1 稿件提交 93 | arcAddReq := &ArcAddReq{ 94 | Title: "xxx", // 稿件标题,请设置成真实信息 95 | Cover: coverUrl, 96 | TypeID: 21, // 稿件分区,请使用分区查询接口找到真实的分区信息,可参考typeList()方法 97 | Tag: "xxx", // 稿件标签,请设置成真实信息 98 | Desc: "xxx", // 稿件描述,请设置成真实信息 99 | Copyright: 1, 100 | } 101 | arcAddResp, err := arcAdd(aToken, uToken, arcAddReq) 102 | if err != nil || arcAddResp.Code != 0 { 103 | fmt.Printf("稿件提交失败, resp=%+v, err=%+v\n", arcAddResp, err) 104 | return 105 | } 106 | resourceId := arcAddResp.Data.ResourceId 107 | fmt.Printf("稿件提交成功 resource_id %s\n", resourceId) 108 | } 109 | -------------------------------------------------------------------------------- /golang/submit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "net/url" 10 | ) 11 | 12 | type ArcAddReq struct { 13 | Mid int64 `json:"mid" validate:"required"` 14 | Title string `json:"title" validate:"required"` 15 | Cover string `json:"cover" validate:"required"` 16 | TypeID int16 `json:"tid" validate:"required"` 17 | Tag string `json:"tag" validate:"required"` 18 | Desc string `json:"desc"` 19 | Copyright int8 `json:"copyright" validate:"required"` 20 | } 21 | 22 | type ArcAddResp struct { 23 | Code int `json:"code"` 24 | Message string `json:"message"` 25 | Data struct { 26 | ResourceId string `json:"resource_id"` 27 | } `json:"data"` 28 | } 29 | 30 | func arcAdd(accessToken string, uploadToken string, p *ArcAddReq) (res *ArcAddResp, err error) { 31 | params := url.Values{} 32 | params.Set("client_id", _client_id) 33 | params.Set("access_token", accessToken) 34 | params.Set("upload_token", uploadToken) 35 | uri := _openapi_archive_add + "?" + params.Encode() 36 | arcAddReqStr, _ := json.Marshal(p) 37 | fmt.Printf("arcAdd uri(%v) reqbody(%v) ready\n", uri, string(arcAddReqStr)) 38 | req, err := http.NewRequest(http.MethodPost, uri, bytes.NewReader(arcAddReqStr)) 39 | if err != nil { 40 | fmt.Printf("arcAdd http.NewRequest error(%v)\n", err) 41 | return 42 | } 43 | req.Header.Set("Content-Type", "application/json; charset=UTF-8") 44 | c := http.DefaultClient 45 | resp, err := c.Do(req) 46 | if err != nil { 47 | fmt.Printf("arcAdd c.Do error(%v), uri(%s)\n", err, uri) 48 | return 49 | } 50 | defer resp.Body.Close() 51 | bs, err := ioutil.ReadAll(resp.Body) 52 | if err != nil { 53 | fmt.Printf("arcAdd read resp err(%v)\n", err) 54 | return 55 | } 56 | if resp.StatusCode != 200 { 57 | fmt.Printf("arcAdd uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 58 | return 59 | } 60 | fmt.Printf("arcAdd uri(%v) respbody(%v) success\n", uri, string(bs)) 61 | res = &ArcAddResp{} 62 | if err = json.Unmarshal(bs, res); err != nil { 63 | fmt.Printf("arcAdd json.Unmarshal error(%v)", err) 64 | return 65 | } 66 | return 67 | } 68 | -------------------------------------------------------------------------------- /golang/typelist.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/url" 9 | ) 10 | 11 | type TypeListResp struct { 12 | Code int `json:"code"` 13 | Message string `json:"message"` 14 | Data struct { 15 | AccessToken string `json:"access_token"` 16 | RefreshToken string `json:"refresh_token"` 17 | ExpiresIn int64 `json:"expires_in"` 18 | } 19 | } 20 | 21 | func typeList(aToken string) (res *AuthLoginResp, err error) { 22 | params := url.Values{} 23 | params.Set("client_id", _client_id) 24 | params.Set("access_token", aToken) 25 | uri := _openapi_type_list + "?" + params.Encode() 26 | fmt.Printf("typeList uri(%v)\n", uri) 27 | req, err := http.NewRequest(http.MethodGet, uri, nil) 28 | if err != nil { 29 | fmt.Printf("typeList http.NewRequest error(%v)\n", err) 30 | return 31 | } 32 | c := http.DefaultClient 33 | resp, err := c.Do(req) 34 | if err != nil { 35 | fmt.Printf("typeList c.Do error(%v), uri(%s)\n", err, uri) 36 | return 37 | } 38 | defer resp.Body.Close() 39 | bs, err := ioutil.ReadAll(resp.Body) 40 | if err != nil { 41 | fmt.Printf("typeList read resp err(%v)\n", err) 42 | return 43 | } 44 | if resp.StatusCode != 200 { 45 | fmt.Printf("typeList uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 46 | return 47 | } 48 | fmt.Printf("typeList uri(%v) respbody(%v) success\n", uri, string(bs)) 49 | json.Unmarshal(bs, &res) 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /golang/upcover.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "mime/multipart" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | ) 14 | 15 | type UPloadCoverResp struct { 16 | Code int `json:"code"` 17 | Message string `json:"message"` 18 | Data struct { 19 | Url string `json:"url"` 20 | } `json:"data"` 21 | } 22 | 23 | func uploadCover(accessToken string, cover string) (res *UPloadCoverResp, err error) { 24 | params := url.Values{} 25 | params.Set("client_id", _client_id) 26 | params.Set("access_token", accessToken) 27 | uri := _openapi_archive_upcover + "?" + params.Encode() 28 | fmt.Printf("uploadCover uri(%v) ready\n", uri) 29 | return generateFileAndUpload(cover, uri) 30 | } 31 | 32 | func generateFileAndUpload(filePath string, uri string) (res *UPloadCoverResp, err error) { 33 | res = &UPloadCoverResp{} 34 | fs, err := os.Stat(filePath) 35 | if err != nil { 36 | fmt.Printf("uploadCover stat file(%v) error(%v)\n", filePath, err) 37 | return 38 | } 39 | file1, err := os.Open(filePath) 40 | if err != nil { 41 | fmt.Printf("uploadCover open file(%v) error(%v)\n", filePath, err) 42 | return 43 | } 44 | defer file1.Close() 45 | bodyBuffer := &bytes.Buffer{} 46 | bodyWriter := multipart.NewWriter(bodyBuffer) 47 | fileWriter1, err := bodyWriter.CreateFormFile("file", fs.Name()) 48 | if err != nil { 49 | fmt.Printf("uploadCover bodyWriter.CreateFormFile error(%v)\n", err) 50 | return 51 | } 52 | _, err = io.Copy(fileWriter1, file1) 53 | if err != nil { 54 | fmt.Printf("uploadCover io.Copy error(%v)\n", err) 55 | return 56 | } 57 | contentType := bodyWriter.FormDataContentType() 58 | bodyWriter.Close() 59 | req, err := http.NewRequest(http.MethodPost, uri, bodyBuffer) 60 | if err != nil { 61 | fmt.Printf("uploadCover http.NewRequest error(%v)\n", err) 62 | return 63 | } 64 | req.Header.Set("Content-Type", contentType) 65 | c := http.DefaultClient 66 | resp, err := c.Do(req) 67 | if err != nil { 68 | fmt.Printf("uploadCover c.Do error(%v)\n", err) 69 | return 70 | } 71 | defer resp.Body.Close() 72 | bs, err := ioutil.ReadAll(resp.Body) 73 | if err != nil { 74 | fmt.Printf("uploadCover ioutil.ReadAll(resp.Body) error(%v)\n", err) 75 | return 76 | } 77 | if resp.StatusCode != 200 { 78 | fmt.Printf("uploadCover uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 79 | return 80 | } 81 | fmt.Printf("uploadCover uri(%v) respbody(%v) success\n", uri, string(bs)) 82 | if err = json.Unmarshal(bs, res); err != nil { 83 | fmt.Printf("uploadCover json.Unmarshal error(%v)", err) 84 | return 85 | } 86 | return 87 | } 88 | -------------------------------------------------------------------------------- /golang/upvideo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | "os" 12 | "strconv" 13 | ) 14 | 15 | type VideoupInitReq struct { 16 | Name string `json:"name"` 17 | } 18 | 19 | type VideoInitResp struct { 20 | Code int `json:"code"` 21 | Message string `json:"message"` 22 | Data struct { 23 | UploadToken string `json:"upload_token"` 24 | } 25 | } 26 | 27 | type VideoUploadResp struct { 28 | Code int `json:"code"` 29 | Message string `json:"message"` 30 | } 31 | 32 | type VideoMergeResp struct { 33 | Code int `json:"code"` 34 | Message string `json:"message"` 35 | Data struct { 36 | UploadToken string `json:"upload_token"` 37 | } 38 | } 39 | 40 | func videoupInit(accessToken string, p *VideoupInitReq) (res *VideoInitResp) { 41 | params := url.Values{} 42 | params.Set("client_id", _client_id) 43 | params.Set("access_token", accessToken) 44 | uri := _openapi_videoup_init + "?" + params.Encode() 45 | initReqStr, _ := json.Marshal(p) 46 | fmt.Printf("videoupInit uri(%v) reqbody(%v) ready\n", uri, string(initReqStr)) 47 | req, err := http.NewRequest(http.MethodPost, uri, bytes.NewReader(initReqStr)) 48 | if err != nil { 49 | fmt.Printf("videoupInit http.NewRequest error(%v)\n", err) 50 | return 51 | } 52 | req.Header.Set("Content-Type", "application/json; charset=UTF-8") 53 | c := http.DefaultClient 54 | resp, err := c.Do(req) 55 | if err != nil { 56 | fmt.Printf("videoupInit c.Do error(%v), uri(%s)\n", err, uri) 57 | return 58 | } 59 | defer resp.Body.Close() 60 | bs, err := ioutil.ReadAll(resp.Body) 61 | if err != nil { 62 | fmt.Printf("videoupInit read resp err(%v)\n", err) 63 | return 64 | } 65 | if resp.StatusCode != 200 { 66 | fmt.Printf("videoupInit uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 67 | return 68 | } 69 | fmt.Printf("videoupInit uri(%v) respbody(%v) success\n", uri, string(bs)) 70 | _ = json.Unmarshal(bs, &res) 71 | return 72 | } 73 | 74 | func videoUpload(uploadToken string, partNum int64, chunkInfo ChunkInfo, body io.Reader) (res *VideoUploadResp, err error) { 75 | params := url.Values{} 76 | params.Set("upload_token", uploadToken) 77 | params.Set("part_number", strconv.FormatInt(partNum, 10)) 78 | uri := _openapi_videoup_upload + "?" + params.Encode() 79 | fmt.Printf("videoupLoad(%v) put uri(%v) ready\n", chunkInfo, uri) 80 | req, err := http.NewRequest(http.MethodPost, uri, body) 81 | if err != nil { 82 | fmt.Printf("videoupLoad http.NewRequest error(%v)\n", err) 83 | return 84 | } 85 | req.Header.Set("Content-Type", "application/octet-stream") 86 | c := http.DefaultClient 87 | resp, err := c.Do(req) 88 | if err != nil { 89 | fmt.Printf("videoUpload c.Do error(%v), uri(%s)\n", err, uri) 90 | return 91 | } 92 | defer resp.Body.Close() 93 | bs, err := ioutil.ReadAll(resp.Body) 94 | if err != nil { 95 | fmt.Printf("videoUpload read resp err(%v)\n", err) 96 | return 97 | } 98 | if resp.StatusCode != 200 { 99 | fmt.Printf("videoupLoad(%v) put uri(%v) statecode(%v), failed\n", chunkInfo, uri, resp.StatusCode) 100 | return 101 | } 102 | fmt.Printf("videoupLoad(%v) put uri(%v) respbody(%v) success\n", chunkInfo, uri, string(bs)) 103 | _ = json.Unmarshal(bs, &res) 104 | return 105 | } 106 | 107 | func videoupMerge(uploadToken string) (res *VideoMergeResp) { 108 | params := url.Values{} 109 | params.Set("upload_token", uploadToken) 110 | uri := _openapi_videoup_merge + "?" + params.Encode() 111 | req, err := http.NewRequest(http.MethodPost, uri, nil) 112 | if err != nil { 113 | fmt.Printf("videoupMerge http.NewRequest error(%v)\n", err) 114 | return 115 | } 116 | req.Header.Set("Content-Type", "application/json; charset=UTF-8") 117 | c := http.DefaultClient 118 | resp, err := c.Do(req) 119 | if err != nil { 120 | fmt.Printf("videoupMerge c.Do error(%v), uri(%s)\n", err, uri) 121 | return 122 | } 123 | defer resp.Body.Close() 124 | bs, err := ioutil.ReadAll(resp.Body) 125 | if err != nil { 126 | fmt.Printf("videoupMerge read resp err(%v)", err) 127 | return 128 | } 129 | if resp.StatusCode != 200 { 130 | fmt.Printf("videoupMerge uri(%v) statecode(%v), failed\n", uri, resp.StatusCode) 131 | return 132 | } 133 | fmt.Printf("videoupMerge uri(%v) respbody(%v) success\n", uri, string(bs)) 134 | _ = json.Unmarshal(bs, &res) 135 | return 136 | } 137 | 138 | func preChunk(fs os.FileInfo, chunksize int64) (res []ChunkInfo) { 139 | n := fs.Size() / chunksize 140 | var i int64 141 | for i = 0; i < n; i++ { 142 | v := ChunkInfo{ 143 | PartNum: i + 1, 144 | Chunk: i, 145 | Chunks: n + 1, 146 | Size: chunksize, 147 | Start: i * chunksize, 148 | End: (i + 1) * chunksize, 149 | Total: fs.Size(), 150 | } 151 | res = append(res, v) 152 | } 153 | lastsize := fs.Size() - n*chunksize 154 | if lastsize == 0 { 155 | return 156 | } 157 | v := ChunkInfo{ 158 | PartNum: i + 1, 159 | Chunk: i, 160 | Chunks: n + 1, 161 | Size: lastsize, 162 | Start: i * chunksize, 163 | End: i*chunksize + lastsize, 164 | Total: fs.Size(), 165 | } 166 | res = append(res, v) 167 | return 168 | } 169 | 170 | type ChunkInfo struct { 171 | PartNum int64 172 | Chunk int64 173 | Chunks int64 174 | Size int64 175 | Start int64 176 | End int64 177 | Total int64 178 | } 179 | -------------------------------------------------------------------------------- /java/Demo.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import com.example.demo.entity.ArcAddParam; 4 | import com.example.demo.util.ArchiveUtil; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.InputStream; 9 | import java.util.Arrays; 10 | 11 | public class Demo { 12 | 13 | private final static String clientId = "这里填入您的 client_id"; 14 | private final static String secret = "这里填入对应的 client_secret"; 15 | 16 | // 视频文件名 17 | private final static String fileName = "video_test.MP4"; 18 | // 视频文件路径 19 | private final static String filePath = "/Users/bilibili/files/video_test.MP4"; 20 | // 稿件封面图片路径 21 | private final static String coverPath = "/Users/bilibili/files/cover_test.png"; 22 | 23 | public static void main(String[] args) throws Exception { 24 | ArchiveUtil arcUtil = new ArchiveUtil(clientId, secret); 25 | 26 | // 通过临时 code 获取 access_token,详见账号授权文档: 27 | // https://openhome.bilibili.com/doc/4/eaf0e2b5-bde9-b9a0-9be1-019bb455701c 28 | String accessToken = arcUtil.getAccessToken("这里填入您获取的code"); 29 | System.out.println("access_token: " + accessToken); 30 | 31 | // 文件上传预处理 32 | // https://openhome.bilibili.com/doc/4/0c532c6a-e6fb-0aff-8021-905ae2409095 33 | String uploadToken = arcUtil.arcInit(accessToken, fileName); 34 | System.out.println("arcInit success: " + uploadToken); 35 | 36 | // 文件分片上传 37 | // https://openhome.bilibili.com/doc/4/733a520a-c50f-7bb4-17cb-35338ba20500 38 | File file = new File(filePath); 39 | InputStream is = new FileInputStream(file); 40 | int partSize = 8 * 1024 * 1024; 41 | byte[] part = new byte[partSize]; 42 | int len; 43 | int partNum = 1; 44 | // 可适当使用并发上传,线程数不宜过大 45 | while ((len = is.read(part)) != -1) { 46 | if (len < partSize) { 47 | part = Arrays.copyOf(part, len); 48 | } 49 | arcUtil.arcUp(uploadToken, partNum, part); 50 | System.out.println("arcUpload success: " + partNum); 51 | partNum++; 52 | } 53 | 54 | // 文件分片合片 55 | // https://openhome.bilibili.com/doc/4/0828e499-38d8-9e58-2a70-a7eaebf9dd64 56 | arcUtil.arcComplete(uploadToken); 57 | System.out.println("arcComplete success"); 58 | 59 | // 上传封面 60 | // https://openhome.bilibili.com/doc/4/8243399e-50e3-4058-7f01-1ebe4c632cf8 61 | String coverUrl = arcUtil.uploadCover(accessToken, new File(coverPath)); 62 | System.out.println("uploadCover success: " + coverUrl); 63 | 64 | // 构造稿件提交参数,提交稿件 65 | // https://openhome.bilibili.com/doc/4/f7fc57dd-55a1-5cb1-cba4-61fb2994bf0f 66 | ArcAddParam arcAddParam = new ArcAddParam(); 67 | arcAddParam.setTitle("测试投稿-" + System.currentTimeMillis()); 68 | arcAddParam.setCover(coverUrl); 69 | // 调用分区查询接口获取,选择合适的分区 70 | // https://openhome.bilibili.com/doc/4/4f13299b-5316-142f-df6a-87313eaf85a9 71 | arcAddParam.setTid(75); 72 | arcAddParam.setNoReprint(1); 73 | arcAddParam.setDesc("测试投稿-描述"); 74 | arcAddParam.setTag("生活,搞笑,游戏"); 75 | arcAddParam.setCopyright(1); 76 | arcAddParam.setSource(""); 77 | 78 | String resourceId = arcUtil.arcSubmit(accessToken, uploadToken, arcAddParam); 79 | System.out.println("arcSubmit success: " + resourceId); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /java/entity/ArcAddParam.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ArcAddParam { 6 | private String title; 7 | private String cover; 8 | private int tid; 9 | @JsonProperty("no_reprint") 10 | private int noReprint; 11 | private String desc; 12 | private String tag; 13 | private int copyright; 14 | private String source; 15 | 16 | public String getTitle() { 17 | return title; 18 | } 19 | 20 | public void setTitle(String title) { 21 | this.title = title; 22 | } 23 | 24 | public String getCover() { 25 | return cover; 26 | } 27 | 28 | public void setCover(String cover) { 29 | this.cover = cover; 30 | } 31 | 32 | public int getTid() { 33 | return tid; 34 | } 35 | 36 | public void setTid(int tid) { 37 | this.tid = tid; 38 | } 39 | 40 | public int getNoReprint() { 41 | return noReprint; 42 | } 43 | 44 | public void setNoReprint(int noReprint) { 45 | this.noReprint = noReprint; 46 | } 47 | 48 | public String getDesc() { 49 | return desc; 50 | } 51 | 52 | public void setDesc(String desc) { 53 | this.desc = desc; 54 | } 55 | 56 | public String getTag() { 57 | return tag; 58 | } 59 | 60 | public void setTag(String tag) { 61 | this.tag = tag; 62 | } 63 | 64 | public int getCopyright() { 65 | return copyright; 66 | } 67 | 68 | public void setCopyright(int copyright) { 69 | this.copyright = copyright; 70 | } 71 | 72 | public String getSource() { 73 | return source; 74 | } 75 | 76 | public void setSource(String source) { 77 | this.source = source; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /java/entity/ArcBizException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | public class ArcBizException extends Exception { 4 | public ArcBizException(CommonReply cr) { 5 | super(String.format("business error: code(%s), message(%s)", cr.getCode(), cr.getMessage())); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java/entity/CommonReply.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import java.util.Map; 4 | 5 | public class CommonReply { 6 | 7 | private Integer code; 8 | private String message; 9 | private Integer ttl; 10 | private Map data; 11 | 12 | public Integer getCode() { 13 | return code; 14 | } 15 | 16 | public void setCode(Integer code) { 17 | this.code = code; 18 | } 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | public void setMessage(String message) { 25 | this.message = message; 26 | } 27 | 28 | public Map getData() { 29 | return data; 30 | } 31 | 32 | public void setData(Map data) { 33 | this.data = data; 34 | } 35 | 36 | public Integer getTtl() { 37 | return ttl; 38 | } 39 | 40 | public void setTtl(Integer ttl) { 41 | this.ttl = ttl; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java/util/ArchiveUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.util; 2 | 3 | import com.example.demo.entity.ArcAddParam; 4 | import com.example.demo.entity.ArcBizException; 5 | import com.example.demo.entity.CommonReply; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.apache.http.client.utils.URIBuilder; 8 | 9 | import java.io.File; 10 | import java.net.URI; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class ArchiveUtil { 15 | 16 | private String clientId; 17 | private String secret; 18 | 19 | public ArchiveUtil(String clientId, String secret) { 20 | this.clientId = clientId; 21 | this.secret = secret; 22 | } 23 | 24 | // apis 25 | private final static String url_token = "https://api.bilibili.com/x/account-oauth2/v1/token"; 26 | private final static String url_arc_init = "https://member.bilibili.com/arcopen/fn/archive/video/init"; 27 | private final static String url_arc_up = "https://openupos.bilivideo.com/video/v2/part/upload"; 28 | private final static String url_arc_complete = "https://member.bilibili.com/arcopen/fn/archive/video/complete"; 29 | private final static String url_arc_cover_up = "https://member.bilibili.com/arcopen/fn/archive/cover/upload"; 30 | private final static String url_arc_submit = "https://member.bilibili.com/arcopen/fn/archive/add-by-utoken"; 31 | 32 | /** 33 | * 获取 accessToken 34 | * 35 | * @param code 授权拿到的临时票据 code 36 | * @return upload_token 37 | */ 38 | public String getAccessToken(String code) throws Exception { 39 | URI uri = new URIBuilder(url_token) 40 | .setParameter("client_id", clientId) 41 | .setParameter("client_secret", secret) 42 | .setParameter("grant_type", "authorization_code") 43 | .setParameter("code", code) 44 | .build(); 45 | ObjectMapper mapper = new ObjectMapper(); 46 | String res = HttpUtil.doPost(uri); 47 | CommonReply reply = mapper.readValue(res, CommonReply.class); 48 | if (reply.getCode() != 0) { 49 | throw new ArcBizException(reply); 50 | } 51 | return (String) reply.getData().get("access_token"); 52 | } 53 | 54 | /** 55 | * 文件上传预处理 56 | * 57 | * @param accessToken access_token 58 | * @param name 文件名字,需携带正确的扩展名,例如test.mp4 59 | * @return upload_token 60 | */ 61 | public String arcInit(String accessToken, String name) throws Exception { 62 | URI uri = new URIBuilder(url_arc_init) 63 | .setParameter("client_id", clientId) 64 | .setParameter("access_token", accessToken) 65 | .build(); 66 | ObjectMapper mapper = new ObjectMapper(); 67 | Map param = new HashMap<>(); 68 | param.put("name", name); 69 | String res = HttpUtil.doPostJson(uri, mapper.writeValueAsString(param)); 70 | CommonReply reply = mapper.readValue(res, CommonReply.class); 71 | if (reply.getCode() != 0) { 72 | throw new ArcBizException(reply); 73 | } 74 | return (String) reply.getData().get("upload_token"); 75 | } 76 | 77 | /** 78 | * 文件分片上传 79 | * 80 | * @param uploadToken upload_token 81 | * @param partNum 分片编号 82 | * @param bytes 字节数组 83 | */ 84 | public void arcUp(String uploadToken, int partNum, byte[] bytes) throws Exception { 85 | URI uri = new URIBuilder(url_arc_up) 86 | .setParameter("upload_token", uploadToken) 87 | .setParameter("part_number", partNum + "") 88 | .build(); 89 | ObjectMapper mapper = new ObjectMapper(); 90 | String res = HttpUtil.doPostStream(uri, bytes); 91 | CommonReply reply = mapper.readValue(res, CommonReply.class); 92 | if (reply.getCode() != 0) { 93 | throw new ArcBizException(reply); 94 | } 95 | } 96 | 97 | /** 98 | * 文件分片合片 99 | * 100 | * @param uploadToken upload_token 101 | */ 102 | public void arcComplete(String uploadToken) throws Exception { 103 | URI uri = new URIBuilder(url_arc_complete) 104 | .setParameter("upload_token", uploadToken) 105 | .build(); 106 | ObjectMapper mapper = new ObjectMapper(); 107 | String res = HttpUtil.doPostJson(uri, ""); 108 | CommonReply reply = mapper.readValue(res, CommonReply.class); 109 | if (reply.getCode() != 0) { 110 | throw new ArcBizException(reply); 111 | } 112 | } 113 | 114 | 115 | /** 116 | * 稿件封面上传 117 | * 118 | * @param accessToken access_token 119 | * @param file 封面图片文件 120 | * @return 封面图片地址 121 | */ 122 | public String uploadCover(String accessToken, File file) throws Exception { 123 | URI uri = new URIBuilder(url_arc_cover_up) 124 | .setParameter("client_id", clientId) 125 | .setParameter("access_token", accessToken) 126 | .build(); 127 | String res = HttpUtil.doPostFile(uri, file); 128 | ObjectMapper mapper = new ObjectMapper(); 129 | CommonReply reply = mapper.readValue(res, CommonReply.class); 130 | if (reply.getCode() != 0) { 131 | throw new ArcBizException(reply); 132 | } 133 | return (String) reply.getData().get("url"); 134 | } 135 | 136 | /** 137 | * 视频稿件提交 138 | * 139 | * @param accessToken access_token 140 | * @param arcAdd 稿件提交参数 141 | * @return 稿件ID 142 | */ 143 | public String arcSubmit(String accessToken, String uploadToken, ArcAddParam arcAdd) throws Exception { 144 | URI uri = new URIBuilder(url_arc_submit) 145 | .setParameter("client_id", clientId) 146 | .setParameter("access_token", accessToken) 147 | .setParameter("upload_token", uploadToken) 148 | .build(); 149 | ObjectMapper mapper = new ObjectMapper(); 150 | String res = HttpUtil.doPostJson(uri, mapper.writeValueAsString(arcAdd)); 151 | CommonReply reply = mapper.readValue(res, CommonReply.class); 152 | if (reply.getCode() != 0) { 153 | throw new ArcBizException(reply); 154 | } 155 | return (String) reply.getData().get("resource_id"); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /java/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.util; 2 | 3 | import org.apache.http.HttpEntity; 4 | import org.apache.http.HttpStatus; 5 | import org.apache.http.client.methods.CloseableHttpResponse; 6 | import org.apache.http.client.methods.HttpPost; 7 | import org.apache.http.entity.ByteArrayEntity; 8 | import org.apache.http.entity.ContentType; 9 | import org.apache.http.entity.StringEntity; 10 | import org.apache.http.entity.mime.MultipartEntityBuilder; 11 | import org.apache.http.entity.mime.content.FileBody; 12 | import org.apache.http.impl.client.CloseableHttpClient; 13 | import org.apache.http.impl.client.HttpClients; 14 | import org.apache.http.util.EntityUtils; 15 | 16 | import java.io.File; 17 | import java.net.URI; 18 | import java.nio.charset.StandardCharsets; 19 | 20 | public class HttpUtil { 21 | 22 | public static String doPost(URI uri) throws Exception { 23 | CloseableHttpClient httpClient = HttpClients.createDefault(); 24 | CloseableHttpResponse response = null; 25 | try { 26 | HttpPost httpPost = new HttpPost(uri); 27 | response = httpClient.execute(httpPost); 28 | if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 29 | throw new Exception("请求失败..."); 30 | } 31 | return EntityUtils.toString(response.getEntity(), "UTF-8"); 32 | } finally { 33 | if (response != null) { 34 | response.close(); 35 | } 36 | httpClient.close(); 37 | } 38 | } 39 | 40 | public static String doPostJson(URI uri, String json) throws Exception { 41 | CloseableHttpClient httpClient = HttpClients.createDefault(); 42 | CloseableHttpResponse response = null; 43 | try { 44 | HttpPost httpPost = new HttpPost(uri); 45 | httpPost.setHeader("Content-Type", "application/json;charset=utf-8"); 46 | StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8); 47 | entity.setContentType("application/json;charset=utf-8"); 48 | httpPost.setEntity(entity); 49 | 50 | response = httpClient.execute(httpPost); 51 | if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 52 | throw new Exception("请求失败..."); 53 | } 54 | return EntityUtils.toString(response.getEntity(), "UTF-8"); 55 | } finally { 56 | if (response != null) { 57 | response.close(); 58 | } 59 | httpClient.close(); 60 | } 61 | } 62 | 63 | public static String doPostFile(URI uri, File file) throws Exception { 64 | CloseableHttpClient httpClient = HttpClients.createDefault(); 65 | CloseableHttpResponse response = null; 66 | try { 67 | HttpPost httpPost = new HttpPost(uri); 68 | FileBody bin = new FileBody(file); 69 | HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("file", bin).build(); 70 | httpPost.setEntity(reqEntity); 71 | 72 | response = httpClient.execute(httpPost); 73 | if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 74 | throw new Exception("请求失败..."); 75 | } 76 | return EntityUtils.toString(response.getEntity(), "UTF-8"); 77 | } finally { 78 | if (response != null) { 79 | response.close(); 80 | } 81 | httpClient.close(); 82 | } 83 | } 84 | 85 | public static String doPostStream(URI uri, byte[] bytes) throws Exception { 86 | CloseableHttpClient httpClient = HttpClients.createDefault(); 87 | CloseableHttpResponse response = null; 88 | try { 89 | HttpPost httpPost = new HttpPost(uri); 90 | httpPost.setHeader("Content-Type", ContentType.APPLICATION_OCTET_STREAM.getMimeType()); 91 | httpPost.setEntity(new ByteArrayEntity(bytes)); 92 | response = httpClient.execute(httpPost); 93 | if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 94 | throw new Exception("请求失败..."); 95 | } 96 | return EntityUtils.toString(response.getEntity(), "UTF-8"); 97 | } finally { 98 | if (response != null) { 99 | response.close(); 100 | } 101 | httpClient.close(); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /php/VideoUpUtoken.php: -------------------------------------------------------------------------------- 1 | getCode().", message=".$e->getMessage()."\n"; 58 | } 59 | 60 | // 合片 61 | $completeResp = videoUpComplete($uToken); 62 | if (!$completeResp) { 63 | return; 64 | } 65 | 66 | // 图片上传 67 | $coverPath = "xxx"; // 封面图路径,请设置成真实信息 68 | $coverResp = coverUp($aToken, $coverPath); 69 | if (!$coverResp) { 70 | return; 71 | } 72 | $coverUrl = $coverResp["url"]; 73 | 74 | // 稿件提交 75 | $title = "xxx"; // 稿件标题,请设置成真实信息 76 | $tid = 21; // 稿件分区,请使用分区查询接口找到真实的分区信息,可参考typeList()方法 77 | $tag = "xxx"; // 稿件标签,请设置成真实信息 78 | $addResp = archiveAdd($aToken, $title, $coverUrl, $tid, $tag, $uToken); 79 | if (!$addResp) { 80 | return; 81 | } 82 | echo "稿件提交成功: resource_id=".$addResp["resource_id"]; 83 | } 84 | 85 | 86 | /** 87 | * 授权登录,获取access_token等信息 88 | * @param $code 89 | * @return array|bool 90 | */ 91 | function authLogin($code) 92 | { 93 | // 获取access_token 94 | $url = URL_AUTH."?client_id=".CLIENT_ID."&client_secret=".CLIENT_SECRET. "&grant_type=authorization_code&code=".$code; 95 | 96 | $resp = curl_post($url); 97 | if(!isset($resp['code']) || $resp['code'] != 0) { 98 | echo "授权登陆失败:".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 99 | return false; 100 | } 101 | echo "authLogin: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 102 | return $resp['data']; 103 | } 104 | 105 | 106 | /** 107 | * 视频上传预处理 108 | * @param $aToken 109 | * @param $name 110 | * @return array|bool 111 | */ 112 | function videoUpInit($aToken, $name) 113 | { 114 | $url = URL_VIDEO_INIT."?client_id=".CLIENT_ID."&access_token=".$aToken; 115 | $body = [ 116 | 'name'=>$name 117 | ]; 118 | $req_headers = array(); 119 | $req_headers[] = 'Content-Type: application/json;'; 120 | $resp = curl_post($url, json_encode($body,JSON_UNESCAPED_UNICODE), $req_headers); 121 | if(!isset($resp['code']) || $resp['code'] != 0) { 122 | echo "文件预处理失败:".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 123 | return false; 124 | } 125 | echo "videoUpInit: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 126 | return $resp['data']; 127 | } 128 | 129 | 130 | /** 131 | * 视频文件分片 132 | * @param $uToken 133 | * @param $partNum 134 | * @param $partData 135 | * @return bool 136 | */ 137 | function videoUpPart($uToken, $partNum, $partData): bool 138 | { 139 | $url = URL_VIDEO_UP."?upload_token=".$uToken."&part_number=".$partNum; 140 | $resp = curl_post($url, $partData); 141 | if(!isset($resp['code']) || $resp['code'] != 0) { 142 | echo "上传分片失败".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 143 | return false; 144 | } 145 | echo "videoUpPart: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 146 | return true; 147 | } 148 | 149 | 150 | /** 151 | * 视频分片合片 152 | * @param $uToken 153 | * @return bool 154 | */ 155 | function videoUpComplete($uToken): bool 156 | { 157 | $url = URL_VIDEO_COMPLETE."?upload_token=".$uToken; 158 | $resp = curl_post($url); 159 | if(!isset($resp['code']) || $resp['code'] != 0) { 160 | echo "合并分片失败".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 161 | return false; 162 | } 163 | echo "videoUpComplete: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 164 | return true; 165 | } 166 | 167 | 168 | /** 169 | * 封面上传 170 | * @param $aToken 171 | * @param $coverFile 172 | * @return array|bool 173 | */ 174 | function coverUp($aToken, $coverFile) 175 | { 176 | $url = URL_COVER_UP."?client_id=".CLIENT_ID."&access_token=".$aToken; 177 | $data = [ 178 | 'file'=>new \CURLFile($coverFile) 179 | ]; 180 | $req_headers = array(); 181 | $req_headers[] = 'Content-Type:multipart/form-data'; 182 | $resp = curl_post($url, $data, $req_headers); 183 | if(!isset($resp['code']) || $resp['code'] != 0) { 184 | echo "上传封面失败".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 185 | return false; 186 | } 187 | echo "coverUp: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 188 | return $resp['data']; 189 | } 190 | 191 | 192 | /** 193 | * 稿件提交 194 | * @param $aToken 195 | * @param $title 196 | * @param $coverUrl 197 | * @param $tid 198 | * @param $tag 199 | * @param $uToken 200 | * @return array|bool 201 | */ 202 | function archiveAdd($aToken, $title, $coverUrl, $tid, $tag, $uToken) 203 | { 204 | $url = URL_ARCHIVE_ADD."?client_id=".CLIENT_ID."&access_token=".$aToken."&upload_token=".$uToken; 205 | $body = [ 206 | 'title'=>$title, 207 | 'cover'=>$coverUrl, 208 | 'tid'=>$tid, 209 | 'tag'=>$tag, 210 | 'copyright'=>1 211 | ]; 212 | $req_headers = array(); 213 | $req_headers[] = 'Content-Type: application/json;'; 214 | $resp = curl_post($url, json_encode($body,JSON_UNESCAPED_UNICODE), $req_headers); 215 | if(!isset($resp['code']) || $resp['code'] != 0) { 216 | echo "稿件提交失败".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 217 | return false; 218 | } 219 | echo "archiveAdd: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 220 | return $resp['data']; 221 | } 222 | 223 | 224 | /** 225 | * 分区查询 226 | * @param $aToken 227 | * @return array|bool 228 | */ 229 | function typeList($aToken) 230 | { 231 | $url = URL_TYPE_LIST."?client_id=".CLIENT_ID."&access_token=".$aToken; 232 | $resp = curl_get($url); 233 | if(!isset($resp['code']) || $resp['code'] != 0) { 234 | echo "分区查询失败".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 235 | return false; 236 | } 237 | echo "typeList: ".json_encode($resp,JSON_UNESCAPED_UNICODE)."\n"; 238 | return $resp['data']; 239 | } 240 | 241 | 242 | // POST请求 243 | function curl_post($url, $data = array(), $header = array()) 244 | { 245 | // 初始化 246 | $curl = curl_init(); 247 | if (!empty($header)) { 248 | curl_setopt($curl, CURLOPT_HTTPHEADER, $header); 249 | } 250 | // 设置抓取的url 251 | curl_setopt($curl, CURLOPT_URL, $url); 252 | // 设置头文件的信息作为数据流输出 253 | curl_setopt($curl, CURLOPT_HEADER, 0); 254 | // 设置获取的信息以文件流的形式返回,而不是直接输出。 255 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 256 | // 设置post方式提交 257 | curl_setopt($curl, CURLOPT_POST, 1); 258 | // 设置post数据 259 | curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 260 | 261 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 不验证证书下同 262 | curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); 263 | // 执行命令 264 | $json = curl_exec($curl); 265 | 266 | // 关闭URL请求 267 | curl_close($curl); 268 | 269 | $result = json_decode($json, true); 270 | 271 | return $result; 272 | } 273 | 274 | 275 | // GET请求 276 | function curl_get($url, $data = array()) 277 | { 278 | // 初始化 279 | $ch = curl_init(); 280 | // 设置选项,包括URL 281 | if(!empty($data)){ 282 | $query = http_build_query($data); 283 | $url = $url . '?' . $query; 284 | } 285 | curl_setopt($ch, CURLOPT_URL, $url); 286 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 287 | curl_setopt($ch, CURLOPT_HEADER, 0); 288 | // 执行并获取HTML文档内容 289 | $output = curl_exec($ch); 290 | // 释放curl句柄 291 | curl_close($ch); 292 | 293 | $result = json_decode($output, true); 294 | 295 | return $result; 296 | } 297 | --------------------------------------------------------------------------------