├── 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 |
--------------------------------------------------------------------------------