API = $api; } /** * @param string $code * * @return array|mixed * * @throws \Exception */ public function login($code = ''): array { return $this->post($this->API::LOGIN, [ 'app_id' => $this->appId, 'app_secret' => $this->secret, 'js_code' => $code, ]); } public function createOrder($outOrderNo, $totalAmount, $openId): array { $data = [ 'app_id' => $this->appId, 'out_order_no' => $outOrderNo, 'open_id' => $openId, 'total_amount' => intval($totalAmount * 100), 'subject' => '订单号:' . $outOrderNo, 'detail' => '快手担保支付', 'type' => 1233, // @url https://mp.kuaishou.com/docs/operate/platformAgreement/epayServiceCharge.html 'expire_time' => $this->validTimestamp, 'notify_url' => $this->noticeUrl, ]; $data['sign'] = $this->getSign($data); $url = $this->API::CREATE_ORDER . '?' . http_build_query([ 'app_id' => $this->appId, 'access_token' => $this->accessToken, ]); $res = $this->post( $url, $data, 'json' ); return [ 'order_id' => $res['order_info']['order_no'], 'order_token' => $res['order_info']['order_info_token'], ]; } public function settle($orderNo, $amount) { $url = $this->API::SETTLE . '?' . http_build_query([ 'app_id' => $this->appId, 'access_token' => $this->accessToken, ]); $data = [ 'app_id' => $this->appId, 'out_order_no' => $orderNo, 'out_settle_no' => $orderNo, 'reason' => '主动结算', 'notify_url' => env('APP_URL') . '/api/pay/kuaishou/settle', 'settle_amount' => $amount, ]; $data['sign'] = $this->getSign($data); return $this->post( $url, $data, 'json' ); } public function pushOrder($openid, $orderId, $createAt): array { $data = [ 'app_id' => $this->appId, 'out_order_no' => $orderId, 'out_biz_order_no' => $orderId, 'open_id' => $openid, 'order_create_time' => (int) Carbon::parse($createAt)->getPreciseTimestamp(3), 'order_status' => 11, // 支付成功 虚拟 'order_path' => 'pages/my/consume', 'product_cover_img_id' => '5acfa29b90c8234ff41ede600cad6a9b715f38871eaf5973', ]; $url = $this->API::ORDER_PUSH . '?' . http_build_query([ 'app_id' => $this->appId, 'access_token' => $this->accessToken, ]); return $this->post($url, $data, 'json'); } public function upload() { $url = 'https://open.kuaishou.com/openapi/mp/developer/file/img/uploadWithUrl?' . http_build_query([ 'app_id' => $this->appId, 'access_token' => $this->accessToken, 'url' => 'http://fourtiao.oss-cn-beijing.aliyuncs.com/zhangsiye/images/664b34c5afb8cb56d4a3cec398e64948.png', ]); return $this->post( $url, ); } /** * @return string */ public function getSign(array $data) { $filterArray = ['sign', 'access_token']; $rList = []; foreach ($data as $k => $v) { if (in_array($k, $filterArray)) { continue; } $value = trim(strval($v)); $len = strlen($value); if ($len > 1 && '"' == substr($value, 0, 1) && '"' == substr($value, $len, $len - 1)) { $value = substr($value, 1, $len - 1); } $value = trim($value); if ('' == $value || 'null' == $value) { continue; } array_push($rList, "$k=$value"); } sort($rList, SORT_STRING); $str = implode('&', $rList); $str .= $this->secret; return md5($str); } protected function getAccessToken(): string { $res = $this->post($this->API::ACCESS_TOKEN, [ 'app_id' => $this->appId, 'app_secret' => $this->secret, 'grant_type' => 'client_credentials', ]); if (!isset($res['result']) || 1 != $res['result']) { throw new \Exception('获取access token 错误'); } file_put_contents($this->accessTokenFile, json_encode([ 'access_token' => $res['access_token'], 'expires_at' => Carbon::now()->timestamp + $res['expires_in'], ])); return $res['access_token']; } protected function setAccessFileDir(): void { $this->accessTokenDir = storage_path('app/kuaishou'); } protected function setAccessFilePath(): void { $this->accessTokenFile = storage_path('app/kuaishou/kuaishou_access_token.json'); } public function getNotifySign(array $data) { $req = file_get_contents('php://input'); $str = $req . $this->secret; return md5($str); } /** * @param string $uri * @param array $data * @param string $type * * @throws \Exception */ protected function post($uri = '', $data = [], $type = 'urlencoded'): array { try { $client = new Client(); if ('urlencoded' == $type) { $url = $uri . '?' . http_build_query($data); $options = [ 'verify' => false, 'headers' => ['Content-Type' => 'x-www-form-urlencoded'], ]; } else { $url = $uri; $options = [ 'verify' => false, 'headers' => ['Content-Type' => 'application/json'], 'body' => json_encode($data), ]; } $res = $client->post($url, $options); $stringBody = (string) $res->getBody(); $res = json_decode($stringBody, true); if (!isset($res['result']) || 1 != $res['result']) { throw new \Exception("请求快手API接口错误,错误码:{$res['result']},错误信息:{$res['error_msg']}"); } return $res; } catch (GuzzleException $e) { \Log::error($e->getMessage()); throw new \Exception($e->getMessage()); } } protected function setNoticeUrl(): void { $this->noticeUrl = env('APP_URL') . '/api/pay/kuaishou/notify'; } }