Kuaishou.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. namespace Ycpay;
  3. class Kuaishou implements PayInterface
  4. {
  5. private $orderParam;
  6. private $app_id;
  7. private $app_secret;
  8. private $notify_url;
  9. private $type;
  10. private $token;
  11. private $settle_url;
  12. private $codedUrl = 'https://open.kuaishou.com/oauth2/mp/code2session';
  13. private $tokenUrl = 'https://open.kuaishou.com/oauth2/access_token';
  14. protected $payUrl = 'https://open.kuaishou.com/openapi/mp/developer/epay/create_order';
  15. protected $query = 'https://open.kuaishou.com/openapi/mp/developer/epay/query_order';
  16. protected $refundUrl = 'https://open.kuaishou.com/openapi/mp/developer/epay/apply_refund';
  17. protected $settle = 'https://open.kuaishou.com/openapi/mp/developer/epay/settle';
  18. protected $sendMsgUrl = 'https://open.kuaishou.com/openapi/mp/developer/message/template/send';
  19. protected $notifyOrder;
  20. public static function init($config)
  21. {
  22. if (empty($config['app_id'])) {
  23. throw new \Exception('not empty app_id');
  24. }
  25. if (empty($config['app_secret'])) {
  26. throw new \Exception('not empty secret');
  27. }
  28. if (empty($config['notify_url'])) {
  29. throw new \Exception('not empty notify_url');
  30. }
  31. $class = new self();
  32. $class->app_id = $config['app_id'];
  33. $class->app_secret = $config['app_secret'];
  34. $class->notify_url = $config['notify_url'];
  35. $class->settle_url = isset($config['settle_url']) ? $config['settle_url'] : $config['notify_url'];
  36. $class->type = isset($config['type']) ? $config['type'] : "";
  37. return $class;
  38. }
  39. /**
  40. * 获取下单信息
  41. */
  42. public function getParam()
  43. {
  44. return $this->orderParam;
  45. }
  46. /**
  47. * 获取异步订单信息
  48. */
  49. public function getNotifyOrder()
  50. {
  51. $bodyData = file_get_contents("php://input");
  52. $this->notifyOrder = json_decode($bodyData, true);
  53. return $this->notifyOrder;
  54. }
  55. /**
  56. * 设置订单号 金额 描述
  57. * @param string $order_no 平台订单号
  58. * @param int $money 订单金额
  59. * @param string $title 描述
  60. * @param string $desc 详细
  61. * @param string $openid 用户openid
  62. * @param string @access_token 获取access_token
  63. */
  64. public function set($order_no, $money, $title, $desc, $openid, $access_token)
  65. {
  66. $order = [
  67. 'app_id' => $this->app_id,
  68. 'out_order_no' => $order_no,
  69. 'open_id' => $openid,
  70. 'total_amount' => $money,
  71. 'subject' => $title,
  72. 'detail' => $desc,
  73. 'type' => $this->type,
  74. 'expire_time' => 3000,
  75. 'attach' => '11',
  76. 'notify_url' => $this->notify_url,
  77. ];
  78. $order['sign'] = $this->sign($order);
  79. $url = $this->payUrl . "?app_id=" . $this->app_id . "&access_token=" . $access_token;
  80. $this->orderParam = json_decode($this->curl_post_json($url, json_encode($order)), true);
  81. return $this;
  82. }
  83. /**
  84. * @param array $map
  85. * @return string
  86. */
  87. public function sign(array $map)
  88. {
  89. foreach ($map as $k => $v) {
  90. $Parameters[$k] = $v;
  91. }
  92. //签名步骤一:按字典序排序参数
  93. ksort($Parameters);
  94. $String = $this->formatBizQueryParaMap($Parameters, false);
  95. //签名步骤二:在string后加入KEY
  96. $String = $String . $this->app_secret;
  97. //签名步骤三:MD5加密
  98. $String = md5($String);
  99. // //签名步骤四:所有字符转为大写
  100. return $String;
  101. }
  102. /**
  103. * 作用:格式化参数,签名过程需要使用
  104. */
  105. public function formatBizQueryParaMap($paraMap, $urlencode)
  106. {
  107. $buff = "";
  108. ksort($paraMap);
  109. foreach ($paraMap as $k => $v) {
  110. if ($urlencode) {
  111. $v = urlencode($v);
  112. }
  113. $buff .= $k . "=" . $v . "&";
  114. }
  115. $reqPar = '';
  116. if (strlen($buff) > 0) {
  117. $reqPar = substr($buff, 0, strlen($buff) - 1);
  118. }
  119. return $reqPar;
  120. }
  121. /**
  122. * 获取token
  123. * @return array
  124. */
  125. public function getToken()
  126. {
  127. $arr = [
  128. 'grant_type' => 'client_credentials',
  129. 'app_id' => $this->app_id,
  130. 'app_secret' => $this->app_secret,
  131. ];
  132. return json_decode($this->curl_post($this->tokenUrl, $arr), true);
  133. }
  134. /**
  135. * 获取openid
  136. * @param string $code
  137. * @return array 成功返回数组 失败为空
  138. */
  139. public function getOpenid($code)
  140. {
  141. $data = [
  142. 'js_code' => $code,
  143. 'app_id' => $this->app_id,
  144. 'app_secret' => $this->app_secret,
  145. ];
  146. $result = json_decode($this->curl_post($this->codedUrl, $data), true);
  147. if ($result['result'] == 1) {
  148. return $result['openid'] = $result['open_id'];
  149. }
  150. return $result;
  151. }
  152. /**
  153. * 异步回调
  154. * @param string $order 回调数据
  155. * @param string $kwaisign sign
  156. * @return bool true 验签通过|false 验签不通过
  157. */
  158. public function notifyCheck()
  159. {
  160. if (md5(json_encode($this->getNotifyOrder()) . $this->app_secret) != $_SERVER['HTTP_KWAISIGN']) {
  161. return false;
  162. }
  163. return true;
  164. }
  165. /**
  166. * 申请退款
  167. * @param string $order['out_order_no'] 订单号
  168. * @param string $order['out_refund_no'] 自定义退款单号
  169. * @param string $order['reason'] 推荐原因
  170. * @param string $order['attach'] 自定义字段
  171. * @param string $order['refund_amount'] 金额
  172. * @param string $order['access_token'] access_token
  173. */
  174. public function applyOrderRefund($order)
  175. {
  176. $orders = [
  177. 'app_id' => $this->app_id,
  178. 'out_order_no' => $order['out_order_no'],
  179. 'out_refund_no' => $order['out_refund_no'],
  180. 'reason' => $order['reason'],
  181. 'notify_url' => $this->notify_url,
  182. 'attach' => $order['attach'],
  183. 'refund_amount' => $order['refund_amount'],
  184. ];
  185. $orders['sign'] = $this->sign($orders);
  186. $url = $this->refundUrl . "?app_id=" . $this->app_id . "&access_token=" . $order['access_token'];
  187. return json_decode($this->curl_post_json($url, json_encode($orders)), true);
  188. }
  189. /**
  190. * 查询订单
  191. * @param string $out_order_no
  192. * @param string $access_token
  193. * @param string $bodyParam
  194. * @param string $url
  195. * @param void
  196. */
  197. public function findOrder($out_order_no, $access_token)
  198. {
  199. $order = [
  200. 'app_id' => $this->app_id,
  201. 'out_order_no' => $out_order_no,
  202. ];
  203. $bodyParam['sign'] = $this->sign($order);
  204. $bodyParam['out_order_no'] = $out_order_no;
  205. $url = $this->query . "?app_id=" . $this->app_id . "&access_token=" . $access_token;
  206. return json_decode($this->curl_post_json($url, json_encode($bodyParam)), true);
  207. }
  208. /**
  209. * 分账
  210. *
  211. * @param [type] $order
  212. * @return void
  213. * @author LiJie
  214. */
  215. public function settle($settle_order, $access_token)
  216. {
  217. $settle_order['app_id'] = $this->app_id;
  218. $settle_order['notify_url'] = $this->settle_url;
  219. $settle_order = $settle_order;
  220. $settle_order['sign'] = $this->sign($settle_order);
  221. $url = $this->settle . "?app_id=" . $this->app_id . "&access_token=" . $access_token;
  222. return json_decode($this->curl_post_json($url, json_encode($settle_order)), true);
  223. }
  224. /**
  225. * 发送模版消息
  226. *
  227. * @param [type] $data
  228. * @param [type] $token
  229. * @return void
  230. */
  231. public function sendMsg($data, $token)
  232. {
  233. return json_decode($this->curl_post($this->sendMsgUrl . $token, http_build_query($data)), true);
  234. }
  235. /**
  236. * curl post json传递
  237. *
  238. * @param string $url
  239. * @param string $data json数据
  240. * @return string $response
  241. */
  242. protected static function curl_post_json($url, $data)
  243. {
  244. $ch = curl_init();
  245. curl_setopt($ch, CURLOPT_POST, 1);
  246. curl_setopt($ch, CURLOPT_URL, $url);
  247. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  248. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  249. curl_setopt(
  250. $ch,
  251. CURLOPT_HTTPHEADER,
  252. array(
  253. 'Content-Type: application/json; charset=utf-8',
  254. 'Content-Length: ' . strlen($data),
  255. )
  256. );
  257. $response = curl_exec($ch);
  258. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  259. curl_close($ch);
  260. return $response;
  261. }
  262. /**
  263. * curl get function
  264. * @param string $url
  265. * @return void
  266. */
  267. protected static function curl_get($url)
  268. {
  269. $headerArr = array("Content-type:application/x-www-form-urlencoded");
  270. $curl = curl_init();
  271. curl_setopt($curl, CURLOPT_URL, $url);
  272. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  273. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  274. curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArr);
  275. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  276. $output = curl_exec($curl);
  277. curl_close($curl);
  278. return $output;
  279. }
  280. /**
  281. * 获取token 和 openid
  282. *
  283. * @param string $url
  284. * @param array $data
  285. * @return string $output
  286. */
  287. protected static function curl_post($url, $data)
  288. {
  289. $ch = curl_init();
  290. curl_setopt($ch, CURLOPT_URL, $url);
  291. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  292. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  293. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  294. curl_setopt($ch, CURLOPT_POST, 1);
  295. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  296. $output = curl_exec($ch);
  297. curl_close($ch);
  298. return $output;
  299. }
  300. /**
  301. * 解密手机号
  302. *
  303. * @param string $session_key 前端传递的session_key
  304. * @param string $iv 前端传递的iv
  305. * @param string $encryptedData 前端传递的encryptedData
  306. */
  307. public function decryptPhone($session_key, $iv, $encryptedData)
  308. {
  309. if (strlen($session_key) != 24) {
  310. return false;
  311. }
  312. $aesKey = base64_decode($session_key);
  313. if (strlen($iv) != 24) {
  314. return false;
  315. }
  316. $aesIV = base64_decode($iv);
  317. $aesCipher = base64_decode($encryptedData);
  318. $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
  319. $dataObj = json_decode($result);
  320. if ($dataObj == null) {
  321. return false;
  322. }
  323. return json_decode($result, true);
  324. }
  325. }