mirror of
				https://github.com/v2board/v2board.git
				synced 2025-10-31 09:21:46 +08:00 
			
		
		
		
	update: rewrite alipay f2f sdk
This commit is contained in:
		| @@ -5,8 +5,6 @@ | ||||
|  */ | ||||
| namespace App\Payments; | ||||
|  | ||||
| use Omnipay\Omnipay; | ||||
|  | ||||
| class AlipayF2F { | ||||
|     public function __construct($config) | ||||
|     { | ||||
| @@ -36,28 +34,25 @@ class AlipayF2F { | ||||
|  | ||||
|     public function pay($order) | ||||
|     { | ||||
|         $gateway = Omnipay::create('Alipay_AopF2F'); | ||||
|         $gateway->setSignType('RSA2'); //RSA/RSA2 | ||||
|         $gateway->setAppId($this->config['app_id']); | ||||
|         $gateway->setPrivateKey($this->config['private_key']); // 可以是路径,也可以是密钥内容 | ||||
|         $gateway->setAlipayPublicKey($this->config['public_key']); // 可以是路径,也可以是密钥内容 | ||||
|         $gateway->setNotifyUrl($order['notify_url']); | ||||
|         $request = $gateway->purchase(); | ||||
|         $request->setBizContent([ | ||||
|             'subject' => config('v2board.app_name', 'V2Board') . ' - 订阅', | ||||
|             'out_trade_no' => $order['trade_no'], | ||||
|             'total_amount' => $order['total_amount'] / 100 | ||||
|         ]); | ||||
|         /** @var \Omnipay\Alipay\Responses\AopTradePreCreateResponse $response */ | ||||
|         $response = $request->send(); | ||||
|         $result = $response->getAlipayResponse(); | ||||
|         if ($result['code'] !== '10000') { | ||||
|             abort(500, $result['sub_msg']); | ||||
|         try { | ||||
|             $gateway = new \Library\AlipayF2F(); | ||||
|             $gateway->setAppId($this->config['app_id']); | ||||
|             $gateway->setPrivateKey($this->config['private_key']); // 可以是路径,也可以是密钥内容 | ||||
|             $gateway->setAlipayPublicKey($this->config['public_key']); // 可以是路径,也可以是密钥内容 | ||||
|             $gateway->setNotifyUrl($order['notify_url']); | ||||
|             $gateway->setBizContent([ | ||||
|                 'subject' => config('v2board.app_name', 'V2Board') . ' - 订阅', | ||||
|                 'out_trade_no' => $order['trade_no'], | ||||
|                 'total_amount' => $order['total_amount'] / 100 | ||||
|             ]); | ||||
|             $gateway->send(); | ||||
|             return [ | ||||
|                 'type' => 0, // 0:qrcode 1:url | ||||
|                 'data' => $gateway->getQrCodeUrl() | ||||
|             ]; | ||||
|         } catch (\Exception $e) { | ||||
|             abort(500, $e->getMessage()); | ||||
|         } | ||||
|         return [ | ||||
|             'type' => 0, // 0:qrcode 1:url | ||||
|             'data' => $response->getQrCode() | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function notify($params) | ||||
|   | ||||
| @@ -20,7 +20,6 @@ | ||||
|         "laravel/horizon": "^4.3.5", | ||||
|         "laravel/tinker": "^2.5", | ||||
|         "linfo/linfo": "^4.0", | ||||
|         "lokielse/omnipay-alipay": "3.1.2", | ||||
|         "lokielse/omnipay-wechatpay": "^3.0", | ||||
|         "php-curl-class/php-curl-class": "^8.6", | ||||
|         "stripe/stripe-php": "^7.36.1", | ||||
|   | ||||
							
								
								
									
										164
									
								
								library/AlipayF2F.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								library/AlipayF2F.php
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user