|
@@ -0,0 +1,164 @@
|
|
|
+<?php
|
|
|
+namespace Library;
|
|
|
+
|
|
|
+use Illuminate\Support\Facades\Http;
|
|
|
+
|
|
|
+class AlipayF2F {
|
|
|
+ private $appId;
|
|
|
+ private $privateKey;
|
|
|
+ private $alipayPublicKey;
|
|
|
+ private $signType = 'RSA2';
|
|
|
+ public $bizContent;
|
|
|
+ public $method;
|
|
|
+ public $notifyUrl;
|
|
|
+ public $response;
|
|
|
+
|
|
|
+ public function __construct()
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ public function verify($data): bool
|
|
|
+ {
|
|
|
+ if (is_string($data)) {
|
|
|
+ parse_str($data, $data);
|
|
|
+ }
|
|
|
+ $sign = $data['sign'];
|
|
|
+ unset($data['sign']);
|
|
|
+ unset($data['sign_type']);
|
|
|
+ ksort($data);
|
|
|
+ $data = $this->buildQuery($data);
|
|
|
+ $res = "-----BEGIN PUBLIC KEY-----\n" .
|
|
|
+ wordwrap($this->alipayPublicKey, 64, "\n", true) .
|
|
|
+ "\n-----END PUBLIC KEY-----";
|
|
|
+ if ("RSA2" == $this->signType) {
|
|
|
+ $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
|
|
|
+ } else {
|
|
|
+ $result = (openssl_verify($data, base64_decode($sign), $res) === 1);
|
|
|
+ }
|
|
|
+ openssl_free_key(openssl_get_publickey($res));
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setBizContent($bizContent = [])
|
|
|
+ {
|
|
|
+ $this->bizContent = json_encode($bizContent);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setMethod($method)
|
|
|
+ {
|
|
|
+ $this->method = $method;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setAppId($appId)
|
|
|
+ {
|
|
|
+ $this->appId = $appId;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setPrivateKey($privateKey)
|
|
|
+ {
|
|
|
+ $this->privateKey = $privateKey;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setAlipayPublicKey($alipayPublicKey)
|
|
|
+ {
|
|
|
+ $this->alipayPublicKey = $alipayPublicKey;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function setNotifyUrl($url)
|
|
|
+ {
|
|
|
+ $this->notifyUrl = $url;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function send()
|
|
|
+ {
|
|
|
+ $response = Http::get('https://openapi.alipay.com', $this->buildParam())->json();
|
|
|
+ $resKey = str_replace('.', '_', $this->method) . '_response';
|
|
|
+ if (!isset($response[$resKey])) throw new \Exception('从支付宝请求失败');
|
|
|
+ $response = $response[$resKey];
|
|
|
+ if ($response['msg'] !== 'Success') throw new \Exception($response['sub_msg']);
|
|
|
+ $this->response = $response;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getQrCodeUrl()
|
|
|
+ {
|
|
|
+ $response = $this->response;
|
|
|
+ if (!isset($response['qr_code'])) throw new \Exception('获取付款二维码失败');
|
|
|
+ return $response['qr_code'];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getResponse()
|
|
|
+ {
|
|
|
+ return $this->response;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function buildParam(): array
|
|
|
+ {
|
|
|
+ $params = [
|
|
|
+ 'app_id' => $this->appId,
|
|
|
+ 'method' => $this->method,
|
|
|
+ 'charset' => 'UTF-8',
|
|
|
+ 'sign_type' => $this->signType,
|
|
|
+ 'timestamp' => date('Y-m-d H:m:s'),
|
|
|
+ 'biz_content' => $this->bizContent,
|
|
|
+ 'version' => '1.0',
|
|
|
+ '_input_charset' => 'UTF-8'
|
|
|
+ ];
|
|
|
+ if ($this->notifyUrl) $params['notify_url'] = $this->notifyUrl;
|
|
|
+ ksort($params);
|
|
|
+ $params['sign'] = $this->buildSign($this->buildQuery($params));
|
|
|
+ return $params;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function buildQuery($query)
|
|
|
+ {
|
|
|
+ if (!$query) {
|
|
|
+ throw new \Exception('参数构造错误');
|
|
|
+ }
|
|
|
+ //将要 参数 排序
|
|
|
+ ksort($query);
|
|
|
+
|
|
|
+ //重新组装参数
|
|
|
+ $params = array();
|
|
|
+ foreach ($query as $key => $value) {
|
|
|
+ $params[] = $key . '=' . $value;
|
|
|
+ }
|
|
|
+ $data = implode('&', $params);
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function buildSign(string $signData): string
|
|
|
+ {
|
|
|
+ $privateKey = $this->privateKey;
|
|
|
+ $p_key = array();
|
|
|
+ //如果私钥是 1行
|
|
|
+ if (!stripos($privateKey, "\n")) {
|
|
|
+ $i = 0;
|
|
|
+ while ($key_str = substr($privateKey, $i * 64, 64)) {
|
|
|
+ $p_key[] = $key_str;
|
|
|
+ $i++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
|
|
|
+ $privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";
|
|
|
+
|
|
|
+ //私钥
|
|
|
+ $privateId = openssl_pkey_get_private($privateKey, '');
|
|
|
+
|
|
|
+ // 签名
|
|
|
+ $signature = '';
|
|
|
+
|
|
|
+ if ("RSA2" == $this->signType) {
|
|
|
+
|
|
|
+ openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA256);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA1);
|
|
|
+ }
|
|
|
+
|
|
|
+ openssl_free_key($privateId);
|
|
|
+
|
|
|
+ //加密后的内容通常含有特殊字符,需要编码转换下
|
|
|
+ $signature = base64_encode($signature);
|
|
|
+ return $signature;
|
|
|
+ }
|
|
|
+}
|