appid = isset($kuaishou['kuai_mini_appid']) ? trim($kuaishou['kuai_mini_appid']) : ''; $this->appSecret = isset($kuaishou['kuai_mini_secret']) ? trim($kuaishou['kuai_mini_secret']) : ''; } /** * 获得用户信息 根据code 获取session_key * @param array|string $openid * @return $userInfo */ public function getUserInfo($code) { try { $dat = array( 'app_id' => $this->appid, 'app_secret' => $this->appSecret, 'js_code' => $code ); if (isset($code)) { $res = self::curlPost(self::CODE2_SESSION_URL, $dat); $data = json_decode($res, true); if ($data['result'] == 1) { return $data; } else { throw new ValidateException("获取失败"); } } else { throw new ValidateException("获取失败"); } } catch (\Throwable $e) { throw new ValidateException($e->getMessage()); } } /** * 加密数据解密 * @param $sessionKey * @param $iv * @param $encryptData * @return $userInfo */ public static function encryptor($sessionKey, $iv, $encrypted) { try { $decrypted = openssl_decrypt( base64_decode($encrypted, true), 'aes-128-cbc', base64_decode($sessionKey, true), OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, base64_decode($iv, true) ); } catch (Exception $e) { throw new EncryptionException($e->getMessage(), EncryptionException::ERROR_DECRYPT_AES); } if (is_null($result = json_decode(self::decode($decrypted), true))) { throw new EncryptionException('ILLEGAL_BUFFER', EncryptionException::ILLEGAL_BUFFER); } return $result; } public static function decode($decrypted) { $pad = ord(substr($decrypted, -1)); if ($pad < 1 || $pad > 32) { $pad = 0; } return substr($decrypted, 0, (strlen($decrypted) - $pad)); } /** * 生成支付订单对象 * @param $openid * @param $out_trade_no * @param $total_fee * @param $attach * @param $body * @param string $detail * @param string $trade_type * @param array $options * @return Order */ protected static function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) { $total_fee = bcmul($total_fee, 100, 0); $order = array_merge(compact('openid', 'out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options); if ($order['detail'] == '') unset($order['detail']); return new Order($order); } /** * 获得jsSdk支付参数 * @param $openid * @param $out_trade_no * @param $total_fee * @param $attach * @param $body * @param string $detail * @param string $trade_type * @param array $options * @return array|string */ public function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) { $time = time(); $price = $total_fee*100; $config = [ 'access_token' =>self::get_token(), 'app_id' => $this->appid, ]; $data = [ 'open_id' => $openid, 'out_order_no' => $out_trade_no, //订单号 'total_amount' => $price, //金额 单位:分 'detail' => $body, //支付的内容 'subject' =>$body, //支付的标题 'type' => 1953, 'attach'=> $attach, 'expire_time' => 3600, 'notify_url'=>SystemConfigService::get('site_url') . Url::build('wap/Kuaishou/notify'), ]; $data['sign'] = self::generate_sign($config,$data); $url = self::CREATE_ORDER.'?' . http_build_query($config); $json = json_encode($data, 320); $res = self::jsonPost($url, $json); $res=json_decode($res,true); if($res['result']==1) return $res['order_info']; else throw new ValidateException($res['error_msg']); } public function generate_sign($query, $postData) { unset($query['access_token']); $arr = array_merge($query, $postData); foreach ($arr as $k => $item) { if (empty($item)) { unset($arr[$k]); } } ksort($arr, 2); $str = ''; foreach ($arr as $k => $v) { $str .= $k . '=' . $v . '&'; } $str = substr($str, 0, strlen($str) - 1); $md5 = $str . $this->appSecret; return md5($md5); } public function get_token() { try { $postData['app_id'] = $this->appid; $postData['app_secret'] = $this->appSecret; $postData['grant_type'] = 'client_credentials'; $res = self::curlPost(self::ACCESS_TOKEN_URL, $postData); $res = json_decode($res, 1); return $res['access_token']; } catch (\Throwable $e) { throw new ValidateException($e->getMessage()); } } /** 根据订单号退款 * @param $orderNo * @param array $opt * @return bool */ public function createRefund($order){ $config = [ 'access_token' => $this->get_token(), 'app_id' => $this->appid, ]; $params = [ 'out_order_no' => (string)$order['order_id'], 'out_refund_no' => 'ks_refund_'. (string)$order['order_id'], 'reason' =>$order['refund_reason_wap_explain'] ?? '用户申请退款', 'notify_url' => SystemConfigService::get('site_url') . Url::build('wap/kuaishou/refundNotify'), 'refund_amount' =>(int)($order['refund_price']*100), ]; $params['sign'] = $this->generate_sign($config,$params); $url = self::REFUND_ORDER_URL.'?'. http_build_query($config); $json = json_encode($params, 320); $res = $this->jsonPost($url, $json); return json_decode($res, true); } public function jsonPost($url, $data = NULL, $times = 0) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_TIMEOUT, 2); //超时时间2秒 curl_setopt($curl, CURLOPT_POSTFIELDS, $data); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json; charset=utf-8', 'Content-Length:' . strlen($data), 'Cache-Control: no-cache', 'Pragma: no-cache' )); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $res = curl_exec($curl); curl_close($curl); return $res; } public static function curlGet($url = '', $options = array()) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); if (!empty($options)) { curl_setopt_array($ch, $options); } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($ch); curl_close($ch); return $data; } public function curlPost($url = '', $postData = '', $options = array()) { if (is_array($postData)) { $postData = http_build_query($postData); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 if (!empty($options)) { curl_setopt_array($ch, $options); } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($ch); curl_close($ch); return $data; } }