快手开放平台对接内容管理demo

其中包括用户授权,获取accessToken,获取用户信息,自动上传视频,发布视频,视频列表,删除视频等

<?php
namespace app\controller;

use app\BaseController;
use Psr\SimpleCache\InvalidArgumentException;
use think\facade\App;
use think\facade\Cache;

class KuaiShou extends BaseController
{
    public $appId = "";
    public $appSecret = "";

    public $uploadToken; // 上传令牌
    public $endpoint;//上传网关的域名

    public $redirectUri = "";

    public $accessToken;
    public $accessTokenTTl = 3600 * 12 * 2; // 2天
    /**
     * @var mixed
     */
    private $refreshToken;

    public $refreshTokenTTl = 3600 * 24 * 180;//180天

    private $limitShardSize = 1024 * 1024 * 10;//大于10m分片上传
    public $userId = 1;

    public $successResult = [
        'code' => 200,
        'msg' => 'success',
        'data' => []
    ];
    public $errorResult = [
        'code' => 400,
        'msg' => 'error',
        'data' => []
    ];

    /**
     * 用户授权
     * */
    public function authorize($return = 0)
    {
        // 要请求的 URL
        $url = 'https://open.kuaishou.com/oauth2/authorize?';
        $params = [
            'app_id'                    => $this->appId,  // 应用唯一标识
            'scope'                     => 'user_info,user_base,user_video_publish,user_video_delete,user_video_info', // code
            'response_type'             => 'code',
            'redirect_uri'              => $this->redirectUri,// 应用授权作用域,多个授权作用域以英文逗号(,)分隔
            'state'                     => '123456789', //安全参数,标识和用户或者设备相关的授权请求。建议开发者实现。回调的时候会带回。
            'ua'                        => 'pc', // 运行环境,普通网页传pc, H5网页不传此参数即可
        ];


        // 调用 CURL GET 请求方法
        $result = $this->montageUrl($url,$params);

        if ($return) {
            return $result;
        }
        header('Location: '.$result);
        exit;
    }


    /**
     * 获取access_token
     *
     * @throws InvalidArgumentException
     */
    public function getAccessToken()
    {
       $res = $this->getAccessTokenServices();

       $data = [
           'access_token' => $res
       ];
       return json($data);
    }

    /**
     * 获取access_token服务
     * */
    public function getAccessTokenServices()
    {
        $redis = Cache::store('redis');
        $accessTokenKey = "{$this->userId}:access_token";
        $refreshTokenKey = "{$this->userId}:refresh_token";
        // 检查用户access_token是否存在
        if ($redis->has($accessTokenKey)) {
            // 获取key的剩余过期时间
            $ttl = $redis->ttl($accessTokenKey);
            if ($ttl < 1800) {
                //半小时内过期重新获取一个token
                $this->refreshToken();
            }
            return $redis->get($accessTokenKey, '');
        } else {
            // key不存在或已过期
            $url = "https://open.kuaishou.com/oauth2/access_token?";
            $data = [
                'app_id' => $this->appId,
                'app_secret' => $this->appSecret,
                'code' => $this->getCode(),
                'grant_type' => 'authorization_code',
            ];

            $result = $this->performCurlGetRequestWithParameters($url,$data);
            if ($result) {
                $result = json_decode($result,true);
                if ($result['result'] != 1 ) {
                    return '';
                }
                if ($result['access_token']) {
                    $this->accessToken = $result['access_token'];
                    $this->refreshToken = $result['refresh_token'];
                    $this->accessTokenTTl = $result['expires_in'];
                    $this->refreshTokenTTl = $result['refresh_token_expires_in'];
                    Cache::set($accessTokenKey,$this->accessToken,$this->accessTokenTTl);
                    Cache::set($refreshTokenKey,$this->refreshToken,$this->refreshTokenTTl);
                    return $result['access_token'];
                }

                return '';
            } else{
                //返回错误信息
                return $result;
            }
        }
    }

    private function getCode()
    {
        return "ad3dac16a93aa4434335c4d3e9a1773dcc8cd759c65b965a727a6ec18b8569981ec3e415";
    }

    /**
     * 刷新token
     * */
    public function refreshToken()
    {
        $accessTokenKey = "{$this->userId}:access_token";
        $refreshTokenKey = "{$this->userId}:refresh_token";

        $url = "https://open.kuaishou.com/oauth2/refresh_token?";
        $data = [
            'app_id' => $this->appId,
            'app_secret' => $this->appSecret,
            "refresh_token" => $this->getRefreshTokenServices(),
            'grant_type' => 'refresh_token',
        ];

        $result = $this->performCurlGetRequestWithParameters($url,$data);
        if ($result) {
            $result = json_decode($result,true);
            if ($result['access_token']) {
                $this->accessToken = $result['access_token'];
                $this->refreshToken = $result['refresh_token'];
                $this->accessTokenTTl = $result['expires_in'];
                $this->refreshTokenTTl = $result['refresh_token_expires_in'];
                Cache::set($accessTokenKey,$this->accessToken,$this->accessTokenTTl);
                Cache::set($refreshTokenKey,$this->refreshToken,$this->refreshTokenTTl);
                return $result['access_token'];
            }

            return '';
        }else{
            //返回错误信息
            return $result;
        }
    }

    /**
     * 刷新token服务
     * */
    public function getRefreshTokenServices()
    {
        $refreshTokenKey = "{$this->userId}:refresh_token";

        $this->refreshToken = Cache::get($refreshTokenKey, '');
        if ($this->refreshToken) {
            return $this->refreshToken;
        } else {
            $this->getAccessTokenServices();
            $this->refreshToken = Cache::get($refreshTokenKey, '');
        }

        return $this->refreshToken;
    }

    /**
     * 获取用户信息
     * */
    public function getUserInfo()
    {
        $accessToken = $this->getAccessTokenServices();

        if (!$accessToken) {
            return json(['code' => 10001,'msg' => '请先授权', 'data' => $this->authorize(1)], 200);
        }
        $url = "https://open.kuaishou.com/openapi/user_info?";
        $data = [
            'app_id' => $this->appId,
            'access_token' => $accessToken
        ];

        $result = $this->performCurlGetRequestWithParameters($url,$data);
        if ($result) {
            $result = json_decode($result,true);
            if ($result['result'] == 1) {
                $this->successResult['data'] = $result['user_info'];
                return json($this->successResult, 200);
            }else{
                $this->errorResult['msg'] = $result['error_msg'];
                return json($this->errorResult, 200);
            }
        }
        return $result;
    }

    /**
     * 获取用户手机号码
     * */
    public function getUserPhone()
    {
        $accessToken = $this->getAccessTokenServices();

        if (!$accessToken) {
            return json(['code' => 10001,'msg' => '请先授权', 'data' => $this->authorize(1)], 200);
        }

        $url = "https://open.kuaishou.com/openapi/user_phone?";
        $data = [
            'app_id' => $this->appId,
            'access_token' => $accessToken
        ];

        $result = $this->performCurlGetRequestWithParameters($url,$data);
        if ($result) {
            $result = json_decode($result,true);
            if ($result['result'] == 1) {
                $this->successResult['data'] = $result['encrypted_phone'];
                return json($this->successResult, 200);
            }else{
                $this->errorResult['msg'] = $result['error_msg'];
                return json($this->errorResult, 200);
            }
        }
        return $result;
    }

    /**
     * 上传视频,用户调用
     * */
    public function uploadVideo()
    {
        $this->accessToken = $this->getAccessTokenServices();

        if (!$this->accessToken) {
            return json(['code' => 10001,'msg' => '请先授权', 'data' => $this->authorize(1)], 200);
        }

        $basePath = App::getBasePath();
        // 构造runtime文件夹的完整路径
        $runtimePath = $basePath . '../runtime/storage/';;
        // 获取表单上传文件 例如上传了001.jpg
        $videoFile = request()->file('videoFile');//视频文件
        $picFile = request()->file('picFile');//封面文件
        $uploadType = $this->request->post('uploadType', 'formData');

        $title = $this->request->post('title', date('Y-m-d H i:s'));
        $videoFileSize = $videoFile->getSize();

        // 上传到本地服务器
        $videoFilePath = \think\facade\Filesystem::putFile( 'topic', $videoFile);
        $picFilePath = \think\facade\Filesystem::putFile( 'topic', $picFile);
        $videoFilePath = $runtimePath.$videoFilePath;
        $picFilePath = $runtimePath.$picFilePath;

        $preData = $this->startUpload();
        if ($preData['result'] != 1) {
            return json($this->errorResult, 200);
        }

        $this->uploadToken = $preData['upload_token'] ?? '';
        $this->endpoint = $preData['endpoint'] ?? '';

        if ($this->uploadToken && $this->endpoint) {
            //视频大于5M分片上传
            if ($videoFileSize > $this->limitShardSize) {
                $fragmentTotal = $this->uploadFragment($videoFilePath);
                $comData = $this->uploadComplete($fragmentTotal);
                if ($comData['result'] != 1) {
                    return json($this->errorResult, 200);
                }
            } else {
                if ($uploadType == 'formData') {
                    $doingData = $this->uploadForFormData($videoFilePath);
                    if ($doingData['result'] != 1) {
                        return json($this->errorResult, 200);
                    }
                } else {
                    $doingData = $this->uploadForBinaryData($videoFilePath);
                    if ($doingData['result'] != 1) {
                        return json($this->errorResult, 200);
                    }
                }
            }
        }

        $res = $this->publish($picFilePath, $title);
        if ($res['result'] == 1) {
            $this->successResult['data'] = $res['video_info'];
            return json($this->successResult, 200);
        }else{
            $this->errorResult['msg'] = $res['error_msg'];
            return json($this->errorResult, 200);
        }
    }

    /**
     * 发起上传
     * */
    public function startUpload()
    {
        $url = "https://open.kuaishou.com/openapi/photo/start_upload?";
        $data = [
            'app_id' => $this->appId,
            'access_token' => $this->accessToken
        ];
        $params = '';
        foreach ($data as $key => $val) {
            $params .= "$key=$val&";
        }
        $url .= rtrim($params, '&');

        $res = $this->sendPostRequest($url);
        return json_decode($res, true);
    }

    /**
     * 视频上传 FormData
     * */
    public function uploadForFormData($file_path)
    {
        $url = "http://{$this->endpoint}/api/upload/multipart?upload_token={$this->uploadToken}";

        $data = [
            'file' => new \CURLFile($file_path),
        ];
        $headers = ['Content-Type: multipart/form-data'];
        $result = $this->sendPostRequest($url, $headers, $data);
        return json_decode($result, true);
    }

    /**
     * body二进制 视频上传
     * */
    public function uploadForBinaryData($file_path)
    {
        $url = "http://{$this->endpoint}/api/upload?upload_token={$this->uploadToken}";

        $headers = array('Content-Type: video/mp4');
        // 准备二进制数据
        $binaryData = file_get_contents($file_path);

        $result = $this->sendPostRequest($url,$headers, $binaryData);

        return json_decode($result, true);
    }

    /**
     * 分片上传
     * */
    public function uploadFragment($file_path)
    {
        $chunks = $this->splitFileIntoChunks($file_path, $this->limitShardSize);

        $headers = array('Content-Type: video/mp4');
        foreach ($chunks as $k => $chunk) {
            // 对每个分片进行处理,例如上传到服务器或写入到另一个文件
            $url = "http://{$this->endpoint}/api/upload/fragment?fragment_id={$k}&upload_token={$this->uploadToken}";
            $this->sendPostRequest($url,$headers, $chunk);
        }

        return count($chunks);
    }

   /**
    * 断点续传
    * */
    public function uploadResume()
    {
        $endpoint = "upload.kuaishouzt.com";
        $url = "http://{$endpoint}/api/upload/resume?upload_token={$this->uploadToken}";

        $this->performCurlGetRequestWithParameters($url);
    }

    /**
     * 完成分片上传
     * */
    public function uploadComplete($fragment_count)
    {
        $url = "http://{$this->endpoint}/api/upload/complete?upload_token={$this->uploadToken}&fragment_count={$fragment_count}";

        $res = $this->sendPostRequest($url);

        return json_decode($res, true);
    }

    /**
     * 发布视频
     * */
    public function publish($picFilePath, $title)
    {
        $url = "https://open.kuaishou.com/openapi/photo/publish?";
        $data = [
            'app_id' => $this->appId,
            'access_token' => $this->accessToken,
            'upload_token' => $this->uploadToken,
        ];

        $url = $this->montageUrl($url, $data);

        $header = [
            'Content-Type: multipart/form-data'
        ];
        $params = [
            'cover' => new \CURLFile($picFilePath),
            'caption' => $title
        ];
        $res = $this->sendPostRequest($url,$header, $params);
        return json_decode($res, true);
    }

    /**
     * 查询用户视频列表
     * */
    public function userVideoList()
    {
        $accessToken = $this->getAccessTokenServices();

        if (!$accessToken) {
            return json(['code' => 10001,'msg' => '请先授权', 'data' => $this->authorize(1)], 200);
        }

        $url = "https://open.kuaishou.com/openapi/photo/list?";
        $data = [
            'access_token'	=> $accessToken,
            'app_id'	=> $this->appId
        ];

        $result = $this->performCurlGetRequestWithParameters($url, $data);

        if ($result) {
            $result = json_decode($result,true);
            if ($result['result'] == 1) {
                $this->successResult['data'] = $result['video_list'];
                return json($this->successResult, 200);
            }else{
                $this->errorResult['msg'] = $result['error_msg'];
                return json($this->errorResult, 200);
            }
        }

        return $result;
    }


    /**
     * 删除视频
     * */
    public function deleteVideo()
    {
        $accessToken = $this->getAccessTokenServices();

        if (!$accessToken) {
            return json(['code' => 10001,'msg' => '请先授权', 'data' => $this->authorize(1)], 200);
        }

        $url = "https://open.kuaishou.com/openapi/photo/delete?";

        $data = [
            'access_token'	=> $accessToken,
            'app_id'	=> $this->appId,
            'photo_id' => '3xdr3fw9f5i9ajw'
        ];

        $url = $this->montageUrl($url, $data);
        $res = $this->sendPostRequest($url);

        if ($res) {
            $res = json_decode($res,true);
            $errorMap = [
                1      => '成功',
                120001 => '视频不存在', // 用户请求的视频不存在
                120002 => '视频未上传', // 视频尚未完成上传
                120003 => '视频发布失败', // 发布视频过程中遇到错误
                100400 => '异常参数', // 请求中包含异常或缺失的参数
                100200500 => '服务器内部错误', // 请求中包含异常或缺失的参数
            ];
            if ($res['result'] == 1) {
                return json($this->successResult, 200);
            }else{
                $this->errorResult['msg'] = $errorMap[$res['result']] ?? '';
                return json($this->errorResult, 200);
            }
        }

        return $res;
    }

    /**
     * 获取二进制内容,并按指定大小分割
     * */
    function splitFileIntoChunks($filePath, $chunkSize) {
        $fileHandle = fopen($filePath, 'rb'); // 以二进制读取模式打开文件
        if ($fileHandle === false) {
            return false;// 如果文件打开失败,返回false
        }
        $chunks = [];
        while (!feof($fileHandle)) {
            $buffer = fread($fileHandle, $chunkSize);
            // 读取文件的一个片段
            if ($buffer === false) {
                break;// 如果读取失败,跳出循环
            }
            $chunks[] = $buffer; // 将片段添加到数组中
        }
        fclose($fileHandle); // 关闭文件句柄

        return $chunks;// 返回包含所有片段的数组
    }

    function performCurlGetRequestWithParameters($url, $parameters = []) {
        // 构建带有参数的 URL
        $url = $this->montageUrl($url, $parameters);

        // 执行 CURL GET 请求
        $headers = [
            'Content-Type: application/json'
        ];
        return $this->sendGetRequest($url, $headers);

    }

    /**
     * url拼接
     * */
    public function montageUrl($url, $data)
    {
        $params = http_build_query($data);
        $url .= rtrim($params, '&');
        return $url;
    }

    /**
     * 执行 CURL GET 请求的方法
     *
     * @param string $url 要请求的 URL
     * @return string 请求的结果
     */
    function sendGetRequest(string $url, $headers = [], $data = []) {
        // 初始化 CURL
        $ch = curl_init();

        // 设置请求方式为 GET
        curl_setopt($ch, CURLOPT_HTTPGET, true);

        // 设置要请求的 URL
        curl_setopt($ch, CURLOPT_URL, $url);

        // 禁用 SSL 证书验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        // 设置默认的头部信息
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        // 将数据以 JSON 格式发送
        if ($data) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
        // 使cURL将响应结果作为字符串返回而不是输出
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        // 执行请求
        $result = curl_exec($ch);

        // 检查请求是否成功
        if (curl_errno($ch)) {
            // 处理请求失败的情况
            echo "CURL 请求失败: ". curl_error($ch);
            return false;
        }

        // 关闭 CURL 连接
        curl_close($ch);
        // 返回请求结果

        return $result;
    }

    /**
     * curl post请求
     * params string $url 请求的url
     * */
    public function sendPostRequest($url, $header = [], $data = [])
    {
        // 初始化cURL会话
        $ch = curl_init();
        // 设置目标URL
        curl_setopt($ch, CURLOPT_URL, $url);

        // 为cURL会话设置适当的请求头
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        // 启用POST方法
        curl_setopt($ch, CURLOPT_POST, 1);

        if ($data) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        // 设置cURL选项,以便将响应结果直接作为字符串返回,而不是输出到浏览器
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        // 执行cURL请求并获取结果
        $response = curl_exec($ch);

        // 检查是否有错误发生
        if (curl_errno($ch)) {
            echo 'cURL error: ' . curl_error($ch);
            return false;
        }

        // 关闭cURL会话
        curl_close($ch);// 输出响应结果echo $response;

        return $response;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值